FULL PRODUCT VERSION :
java version "1.6.0_19"
Java(TM) SE Runtime Environment (build 1.6.0_19-b04)
Java HotSpot(TM) 64-Bit Server VM (build 16.2-b04, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux lx00078.starbucks.net 2.6.18-164.6.1.el5 #1 SMP Tue Oct 27 11:28:30 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
Clients that simply "open" and then immediately "close" the socket cause the HttpsServer to leak open files. In any kind of monitored load balancer environment this quickly leads to an O/S layer "too many open files" runtime error.
In reviewing the dispatch code there is no attempt made to catch a runtime error nor is there a finally clause to ensure that all open files get closed.
In this use case the completely empty request is never dispatched so the custom request HttpHandler is never called. The files are left open for the duration of the VM.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a new HttpsServer instance and then layer in the SSLContext, HttpsConfigurator and HttpRequestHandler with a HttpContext.
Next simply use telnet to open the HTTP/s listener port and then terminate the telnet session.
On Linus using the "lsof" (list open files) along with grep and "wc" on the running user will reveal that the open file count increases with each "open & close" operation.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The proper result would be for the open files to go up and then shrink. Some will be left in a FIN_WAIT, but will be cleaned up over time based on the O/S settings.
This is not the case here because the files are never closed.
ACTUAL -
Regularly inspecting the open file count while running a script to open and close the HTTP/s listener socket 1 time every second will show a leak of about 8-10 open files every 10 seconds.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
The JVM will begin throwing IOException's with a cause of "too many open files".
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
HttpsServer httpsServer = HttpsServer.create();
final SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
kmf.init(getKeyStore(), getKSPasswd());
tmf.init(getKeyStore());
sslContext.init(
kmf.getKeyManagers()
, tmf.getTrustManagers()
, getSecureRandom()
);
sslContext.getClientSessionContext().setSessionTimeout(1000);
sslContext.getServerSessionContext().setSessionTimeout(1000);
// initialize http/s server
dsServerParams.httpsServer.setHttpsConfigurator(
new HttpsConfigurator(sslContext) {
@Override
public void configure(HttpsParameters params) {
final SSLEngine sslEngine = getSSLContext().createSSLEngine();
String ciphers[] = sslEngine.getEnabledCipherSuites();
String protocols[] = sslEngine.getEnabledProtocols();
params.setCipherSuites(ciphers);
params.setProtocols(protocols);
params.setNeedClientAuth(false);
params.setWantClientAuth(false);
}
}
);
InetSocketAddress isa = new InetSocketAddress(dsServerParams.portNo);
httpsServer.bind(isa, dsServerParams.backlog);
HttpHandler handler = new HttpHandler() {
public void handle(HttpExchange exchange) {
try {
System.out.println(exchange.getHttpContext().getPath(););
}
finally {
try { exchange.close(); } catch(Throwable t) {}
}
}
};
httpsServer.createContext("/", handler);
httpsServer.setExecutor( Executors.newCachedThreadPool() );
httpsServer.start();
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There is no way to work around this bug.