HttpsUrlConnection and keep-alive

Biggie picture Biggie · Mar 30, 2012 · Viewed 54.4k times · Source

I am using com.sun.net.httpserver.HttpsServer in my current project which deals with client-authentification etc.. Currently it only prints out the clients address/port, so that I can check if one TCP-connection is used for multiple requests (keep-alive) or if a new connection is established for every request (and thus a new SSL-handshake is made every time). When I use FireFox to make multiple request against the server I can see that keep-alive is working. So the server part works fine with GET and POST-requests.

If I use HttpURLConnection to make a request against the Server (in this case using no SSL) keep-alive works, too: Only one connection is established for multiple sequentially started requests.

But if I use HttpsURLConnection (using exactly the same code, but using SSL) then keep-alive is not working anymore. So for each request a new connection is established, although I am using the same SSLContext (and SSLSocketFactory):

// URL myUrl = ...
// SSLContext mySsl = ...
HttpsURLConnection conn = (HttpsURLConnection) myUrl.openConnection();
conn.setUseCaches(false);
conn.setSSLSocketFactory(mySsl.getSocketFactory());

conn.setRequestMethod("POST");
// send Data
// receive Data

How do I force HttpsURLConnection to use keep-alive because many requests will lead to many SSL-handshakes which is a real performance issue?

Update (2012-04-02): Instead of calling mySsl.getSocketFactory() each time, I tried to cache the SSLSocketFactory. But nothing changed. The problem still exists.

Answer

Bill Healey picture Bill Healey · Apr 9, 2015

I ran into this exact same problem and finally have a solution after some in-depth debugging.

Http(s)UrlConnection does handle Keep-Alive by default but sockets must be in a very specific condition in order to be reused.

These are:

  • Input streams must be fully consumed. You must call read on the input stream until it returns -1 and also close it.
  • Settings on the underlying socket must use the exact same objects.
  • You should call disconnect (yes this is counter-intuitive) on the Http(s)URLConnection when done with it.

In the above code, the problem is:

conn.setSSLSocketFactory(mySsl.getSocketFactory());

Saving the result of getSocketFactory() to a static variable during initialization and then passing that in to conn.setSSLSocketFactory should allow the socket to be reused.