views:

114

answers:

3

I'm using com.sun.net.httpserver.HttpServer in my project. However, it seems that the server leaks connections when it gets invalid data from the HTTP connection. The bug is this one:

http://bugs.sun.com/view_bug.do;jsessionid=dfe841c3152d878571573bafceb8?bug_id=6946825

Now, this is reported to be fixed in version "7(b94)" - however, we are still using Java 1.6 and it is unlikely that we would want switch Java versions at this point.

So, I am looking for ways to fix this situation. I don't have a lot of time, so I'd prefer quick solutions that work for now, over reimplementing a lot of things for later.

I have a few ideas on how to go about this:

  • Update to a more recent Java - this is something I don't want to do.
  • Find a jar which only contains a more recent version of com.sun.net.httpserver and make sure that jar loads before the system jars.
  • Find a drop-in replacement for com.sun.net.httpserver - I'm open to pointers here.
  • Modify code to work with another embedded HTTP server, hopefully one that isn't too different from the current one. I can rewrite the server setup code, somewhat, but most of the interfaces should stay the same.
  • Decompile the com.sun.net.httpserver.ServerImpl class, fix the offending places, and recompile that single class to a jar of it's own

But, I'm open to good suggestions!

Thank you in advance.


Fix is now implemented and works. I will paste here the relevant bits if anyone else needs these:

final Field httpserverimpl_server = Class.forName("sun.net.httpserver.HttpServerImpl").getDeclaredField("server");
final Field httpsserverimpl_server = Class.forName("sun.net.httpserver.HttpsServerImpl").getDeclaredField("server");
final Field serverimpl_allconnections = Class.forName("sun.net.httpserver.ServerImpl").getDeclaredField("allConnections");
final Field httpconnection_closed = Class.forName("sun.net.httpserver.HttpConnection").getDeclaredField("closed");

httpserverimpl_server.setAccessible(true);
httpsserverimpl_server.setAccessible(true);
serverimpl_allconnections.setAccessible(true);
httpconnection_closed.setAccessible(true);

Object serverimpl = httpserverimpl_server.get(server);
Set allconnections = (Set)serverimpl_allconnections.get(serverimpl);
LinkedList<Object> toRemove = new LinkedList<Object>();
for (Object conn : allconnections) {
    if (httpconnection_closed.getBoolean(conn)) {
        toRemove.add(conn);
    }
}
for (Object conn : toRemove) {
    allconnections.remove(conn);
}
A: 

Do you have access to 7(b94)? Then you can compare the sources and see whether you can fix it by overriding or providing different accessors.

mklhmnn
I have access to the version - it seems that I can register another HttpServerProvider, for example, so this is replacable, but I'm still not sure what's the easiest solution.
Nakedible
+1  A: 

Could you put a reverse proxy infront of the HTTP server, to make sure you only allow known good requests to come through? Varnish or Squid or Apache?

Or knock something up in Jetty so that it acts as a reverse proxy?

Another approach would be to grab the source code of the fixed version, rename the class and package so that it fits into your project, make the class public, and then use that implementation instead.

Jonathan Hedley
Complicating the setup is even worse at this point - this is a very strict environment. Good idea, though!
Nakedible
+1  A: 

I can understand your reluctance to upgrade to a pre-release build of Java 7.

Here are my suggestions:

  • Get a Java support contract from Oracle and get them to provide you with a patch for Java 6 that fixes the bug.

  • Download the Java 6 sources for the release you are currently using, backport the bug fix from the Java 7 sources and build. Maybe you only need to do a build of certain JAR files.

  • Look at the code and see if you could develop a workaround. For example, you might be able to use reflection to dig out the "list of HttpConnection instances" that the bug report talks about, and periodically remove entries that look like they are dead. (I'd treat this as a last resort.)

Stephen C
I managed to cook up a class that uses reflection to dig up the ServerImpl instance, goes through it's allConnections set and again uses reflection to check if the HttpConnection is closed - if so, it is removed from the setHaven't been able to try this in actual code to see if it fixes the problem, but this seems possible atleast in theory.
Nakedible
Cool. If I were you, I'd read the source code carefully and try to convince yourself that your approach should. Also, leave yourself and future maintainers a BIG REMINDER to get rid of the workaround when you upgrade to Java 7.
Stephen C
Reflection it is – and BIG REMINDERs are in place. Also code is protected in try blocks so that if it doesn't work, it just warns and won't try to clean the connections so the code will automatically work on platforms where the httpserver is perhaps different and will not share the same bugs.
Nakedible