Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does com.sun.net.httpserver.HttpServer hang? [closed]

Tags:

java

https

freeze

When my simple HTTPS server implemented using com.sun.net.httpserver.HttpServer is called via this PHP proxy (which uses curl), it works fine. But as soon as I don't use the proxy but change my web form so that browsers directly send their requests to the server, the server becomes unstable and sometimes stops responding. The client will then wait for a response until it times out. The problem is difficult to reproduce and sometimes happens after hours in the live system. All of this is via HTTPS, on a non-standard port (currently 8081). My server returns XML.

The stacktrace I see when the server doesn't respond anymore (via "kill -QUIT [pid]"):

"Thread-2" prio=10 tid=0x0000000017fc4800 nid=0x1c2b runnable
    [0x00002ba5ec97c000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:218)
at sun.nio.ch.IOUtil.read(IOUtil.java:191)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:359)
    - locked <0x00000000fd1e4b98> (a java.lang.Object)
at sun.net.httpserver.SSLStreams$EngineWrapper.recvAndUnwrap(SSLStreams.java:334)
    - locked <0x00000000fd1e4c58> (a java.lang.Object)
at sun.net.httpserver.SSLStreams.recvData(SSLStreams.java:409)
at sun.net.httpserver.SSLStreams$InputStream.read(SSLStreams.java:524)
at sun.net.httpserver.SSLStreams$InputStream.read(SSLStreams.java:593)
at sun.net.httpserver.Request.readLine(Request.java:84)
at sun.net.httpserver.Request.<init>(Request.java:54)
at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:529)
at sun.net.httpserver.ServerImpl$DefaultExecutor.execute(ServerImpl.java:156)
at sun.net.httpserver.ServerImpl$Dispatcher.handle(ServerImpl.java:424)
at sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:389)
at java.lang.Thread.run(Thread.java:722)

What I already tried: Sending a Connection: close http header - didn't help. Writing a Java test case that uses multiple threads to query the server in parallel - works fine.

So the questions is: what do browsers do different than my proxy, and why does that make my server process hang?

Source: here's the source of the HttpHandler and here's the source of the Server that uses that handler

Background: I want anybody to be able to use my REST service from their web page, without installing a proxy (needed to circumvent the Javascript cross-origin policy). For that, the server sends an Access-Control-Allow-Origin: * header. I'm using the classes provided by Java to have minimal overhead compared to Jetty or Tomcat Embedded.

like image 627
Daniel Naber Avatar asked Sep 05 '25 17:09

Daniel Naber


1 Answers

Why different behaviour for proxy & no proxy?

  • more connections with no proxy
  • real-world browser users can do funny things, like start a request and then cancel/back button/new request.

You need to set a socket timeout. Unfortunately, the API documentation suggests no way to do so programmatically.

But you can set resquest & response timeouts via JVM system properties:

http://www.javaworld.com/community/node/8424
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/sun/net/httpserver/ServerConfig.java
https://bugs.java.com/bugdatabase/view_bug?bug_id=6563368

Set these system properties:

sun.net.httpserver.clockTick Default value = 10000 i.e. 10 sec

sun.net.httpserver.timerMillis Default value = 1000 i.e. 1 sec

sun.net.httpserver.maxReqTime Default value = -1 i.e. forever.

A default > 0 gives timeout = default * (either clockTick ot timerMillis) sec

sun.net.httpserver.maxRspTime Default value = -1 i.e. forever.

A default > 0 gives timeout = default * (either clockTick ot timerMillis) sec


Obviously, in your HttpHandler.handle() method, make sure you set the response code in the response headers:

  httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.length());  
  final OutputStream os = httpExchange.getResponseBody();  
  os.write( response.getBytes() );  
  os.close(); 
like image 139
Glen Best Avatar answered Sep 07 '25 14:09

Glen Best