JDK-6238070 : Unable to control keepalive time out in HttpUrlConnection
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2005-03-09
  • Updated: 2011-02-16
  • Resolved: 2005-07-26
Description
FULL PRODUCT VERSION :
java version "1.5.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_01-b08
Java HotSpot(TM) Client VM (build 1.5.0_01-b08, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Windows 2000 service pack 4

A DESCRIPTION OF THE PROBLEM :
I need to use Http 1.1 persistent connection capabilities of the class java.net.HttpUrlConnection to run my http client.
My http client sends multiple requests to a servlet running in Tomcat 5.0.19 web server and after 5 sec it doesn't send a message the underlying socket is replaced with another socket  (I'm using TCPView to view the state of the tcp sockets).
In particular I need to estabilish 'long-lived' tcp connection but in this way it's not possible because I can't handle the keepAliveTimeOut.
By analyzing the source code of HttpUrlConnection and related classes, and Tomcat connector, I've discovered that:
-in the sun client classes, in the cases of 'noProxy', the keepAliveTimeOut is hardcoded and is 5 sec: but if it receives something like:
"timeout=40, max=5" in the "Keep-Alive" header property it should take it  into account; besides, it seems to be no limit about the number of requests I can do on the underlying socket
-in Tomcat, setting the property maxKeepAliveRequests="-1", the socket is never closed by the web server, and the connectionTimeout="20000" doesn't create problems; besides it seems to be hardcoded a keepAliveTimeOut of 60 sec.





STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Simply execute the test methods with and without the codeblock surrounded by th line comments:
//--------------
....
//--------------

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Among client side and server side, the stronger keepAliveTimeOut constraint is the Tomcat constraint: connectionTimeout="20000";
after this there is the "timeout=40... of the client, and so the 60 sec hardcoded in Tomcat.
So, running the method 'request(false)' including the codeblock surrounded by th line comments:
//--------------
....
//--------------
the socket should remain the same if i don't send a message in 20 sec (connectionTimeout="20000" )
ACTUAL -
the socket is replaced randomly; it is replaced much frequently if the frequency of the requests is higher;
if I exclude the code inside the
//--------------
....
//--------------
it is replaced after 5 sec if I send norequest

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
==============CLIENT SIDE==============
  private synchronized void request(boolean close){
    try{
      con=(HttpURLConnection) url.openConnection();
      con.setDoInput(true);
      con.setDoOutput(true);
      con.setUseCaches(false);
      con.setRequestProperty("Content-Type", "application/octet-stream");

//------------
      if(close)
        con.setRequestProperty("connection","close");
       else{
        con.setRequestProperty("connection","keep-alive");
        con.setRequestProperty("Keep-Alive", "timeout=40, max=5");
      }
//---------

      ObjectOutputStream os=new ObjectOutputStream(con.getOutputStream());
      os.writeObject("xx");
      os.close();

      ObjectInputStream is = new ObjectInputStream(con.getInputStream());
      Object o = is.readObject();
      is.close();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
===================================

==============SERVER SIDE==========
servlet with:

  protected void service(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {

    String connHeader=httpServletRequest.getHeader("connection");
    if(connHeader!=null && connHeader.toLowerCase().equals("keep-alive")){
      String kaHeader=httpServletRequest.getHeader("Keep-Alive");
      if(kaHeader!=null){
        httpServletResponse.setHeader("Connection",connHeader);
        httpServletResponse.setHeader("Keep-Alive",kaHeader);
      }
    }

    ObjectInputStream is = new ObjectInputStream(httpServletRequest.getInputStream());
    Object o=null;
    try {o=is.readObject();}catch (Exception e) {e.printStackTrace();}
    is.close();

    ObjectOutputStream os = new ObjectOutputStream(httpServletResponse.getOutputStream());
    os.writeObject("tnx");
    os.close();
  }
===================================
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I tried this workaround:
-set the response header property ("Keep-Alive","timeout=40, max=5") in my server-side code, so to let the client side (class sun.net.www.http.HttpClient) read it;
-set maxKeepAliveRequests="-1" in Tomcat;
the things seem to work much better, but sometimes, unexpectedly, the tcp socket is replaced, also after 1-2 sec from the last mesage. Besides, after some minutes the client cpu raise to 90%
###@###.### 2005-03-09 09:36:42 GMT

Comments
EVALUATION For the intention of this bug's submitter, a standard HTTP client implementation isn't suitable. Most likely he/she should use socket directly. And it's also not good to rely on the implementation detail of JDK network feature, i.e. internal package. Close it for now.
26-07-2005

EVALUATION It looks like the original submitter wants to sustain some kind of state information in HTTP session by using HTTP/1.1 persistent connection. It is not the intention of HTTP/1.1 persistent connection. And, HTTP/1.1 does not define any parameters for Keep-Alive header. So I would like to say most likely we will not support such enhancements. ###@###.### 2005-04-20 07:19:39 GMT
20-04-2005