Hi,

We are using the 2.6.1 WebClient for REST calls and we are running into issues 
where the sockets try to connect to 0.0.0.0 (anywhere address) after the client 
has been running for a while. After some analysis of the symptoms and going 
through the source for the sun.net and cxf code, we believe it is related to 
this Oracle document

https://docs.oracle.com/javase/7/docs/technotes/guides/net/http-keepalive.html

And around properly supporting 4xx/5xx status codes and the internal keep-alive 
cache.

Here is what I think is the relevant excerpt:

What's new in Tiger?

When the application encounters a HTTP 400 or 500 response, it may ignore the 
IOException and then may issue another HTTP request. In this case, the 
underlying TCP connection won't be Kept-Alive because the response body is 
still there to be consumed, so the socket connection is not cleared, therefore 
not available for reuse. What the application needs to do is call 
HttpURLConnection.getErrorStream() after catching the IOException , read the 
response body, then close the stream. However, some existing applications are 
not doing this. As a result, they do not benefit from persistent connections. 
To address this problem, we have introduced a workaround.

The workaround involves buffering the response body if the response is >=400, 
up to a certain amount and within a time limit, thus freeing up the underlying 
socket connection for reuse. The rationale behind this is that when the server 
responds with a >=400 error (client error or server error. One example is "404: 
File Not Found" error), the server usually sends a small response body to 
explain whom to contact and what to do to recover.

Several new Sun implementation specific properties are introduced to help clean 
up the connections after error response from the server.

The major one is:

sun.net.http.errorstream.enableBuffering=<boolean>
default: false

With the above system property set to true (default is false), when the 
response code is >=400, the HTTP handler will try to buffer the response body. 
Thus freeing up the underlying socket connection for reuse. Thus, even if the 
application doesn't call getErrorStream(), read the response body, and then 
call close(), the underlying socket connection may still be kept-alive and 
reused.

The following two system properties provide further control to the error stream 
buffering behavior:

sun.net.http.errorstream.timeout=<int> in millisecond
default: 300 millisecond

sun.net.http.errorstream.bufferSize=<int> in bytes
default: 4096 bytes

What can you do to help with Keep-Alive?

Do not abandon a connection by ignoring the response body. Doing so may results 
in idle TCP connections. That needs to be garbage collected when they are no 
longer referenced.

If getInputStream() successfully returns, read the entire response body.

When calling getInputStream() from HttpURLConnection, if an IOException occurs, 
catch the exception and call getErrorStream() to get the response body (if 
there is any).

Reading the response body cleans up the connection even if you are not 
interested in the response content itself. But if the response body is long and 
you are not interested in the rest of it after seeing the beginning, you can 
close the InputStream. But you need to be aware that more data could be on its 
way. Thus the connection may not be cleared for reuse.

Here's a code example that complies to the above recommendation:

try {
        URL a = new URL(args[0]);
        URLConnection urlc = a.openConnection();
        is = conn.getInputStream();
        int ret = 0;
        while ((ret = is.read(buf)) > 0) {
          processBuf(buf);
        }
        // close the inputstream
        is.close();
} catch (IOException e) {
        try {
                respCode = ((HttpURLConnection)conn).getResponseCode();
                es = ((HttpURLConnection)conn).getErrorStream();
                int ret = 0;
                // read the response body
                while ((ret = es.read(buf)) > 0) {
                        processBuf(buf);
                }
                // close the errorstream
                es.close();
        } catch(IOException ex) {
                // deal with the exception
        }
}


My question(s) are:


  *   Does CXF WebClient handle this?
     *   If so, which versions?
     *   Where is the code that handles this located
  *   Are users of WebClient supposed to manage this?
  *   Have you seen this error before?

Any help/pointers would be greatly appreciated.

Thanks,
Chuck

Reply via email to