Hi
Thanks for this analysis.
CXF 2.6.x is not supported any longer but CXF 2.7.x still is,
It is a bit late so I only checked the trunk (CXF 3.1.0-SNAPSHOT), can
you please check
URLConnectionHttpConduit.getInputStream() ? It appears to be doing the
right code
In CXF 2.7.x this method is probably directly in HttpConduit...
Besides that I guess WebClient can auto-close InputStream it reads.
There's a property for it, "response.stream.auto.close". Or if you read
InputStream directly then it needs to be closed manually
Cheers, Sergey
On 13/04/15 16:55, Canning, Charles wrote:
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