Issue
The server response body is "[]" and the Content-Length = 0. When client is trying to read mentioned response body it always once gets "-1". Also, if I intercept the server response and change the Content-Length to "2" - everything works. I can make conclusion that apache http client returns -1 when Content-Length = 0, but the response body is not empty actually. I'm looking for a workaround to be able to read response body even if the Content-length is incorrect, i.e. can I setup http client to ignore the Content-length header value? I don't have a chance to modify server and I cannot use HttpUrlConnection instead apache client for some reasons. Please, any suggestion.
Solution
The problem with faulty Content-length
is that HttpClient does not know when the response is over, this also breaks the next request over this connection in case of Keep-Alive connection.
The easiest option is to extend org.apache.http.impl.entity.LaxContentLengthStrategy and make it return content length "2" when in header it is "0", but if the length is really 0, the thread will hang waiting to read more from the socket:
class MyLaxContentLengthStrategy extends LaxContentLengthStrategy{
public long determineLength(final HttpMessage message) throws HttpException {
final Header contentLengthHeader = message.getFirstHeader(HTTP.CONTENT_LEN);
if (contentLengthHeader != null) {
long contentlen = -1;
final Header[] headers = message.getHeaders(HTTP.CONTENT_LEN);
for (int i = headers.length - 1; i >= 0; i--) {
final Header header = headers[i];
try {
contentlen = Long.parseLong(header.getValue());
break;
} catch (final NumberFormatException ignore) {
}
// See if we can have better luck with another header, if present
}
if (contentlen == 0) {
return 2;
}
}
return super.determineLength(message);
}
}
Setting of which in the HttpClient might be a little bit tricky: http://mail-archives.apache.org/mod_mbox/hc-httpclient-users/201301.mbox/%3C1359388867.10617.16.camel@ubuntu%3E Since 4.4 it is quite easier:
ManagedHttpClientConnectionFactory cliConnFactory = new ManagedHttpClientConnectionFactory(
null, null, null,
new MyLaxContentLengthStrategy());
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(cliConnFactory);
HttpClients.custom
.....
.setConnectionManager(cm)
.build();
So if you actually does not need the body with "[]", you can instruct the HttpClient to close this connection and abandon the faulty response. This can be done by overriding the org.apache.http.impl.client.DefaultClientConnectionReuseStrategy with something like this:
class MyConnectionReuseStrategy extends DefaultClientConnectionReuseStrategy{
@Override
public boolean keepAlive(final HttpResponse response, final HttpContext context) {
final HttpRequest request = (HttpRequest) context.getAttribute(HttpCoreContext.HTTP_REQUEST);
if (request != null) {
final Header[] contLenHeaders = request.getHeaders(HttpHeaders.CONTENT_LENGTH);
for(Header h : contLenHeaders){
if("0".equalsIgnoreCase(h.getValue())){
return false;
}
}
}
return super.keepAlive(response, context);
}
}
Which you can set like this:
HttpClients.custom
.....
.setConnectionReuseStrategy(new MyConnectionReuseStrategy())
.build();
Answered By - Anton Krosnev
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.