[using httpcore 4.1.4, httpclient 4.2.5, Oracle JDK 1.7.0_25]
I'm trying to 'proxy' a connection to a third party web service on behalf of a webapp's javascript (AJAX) code and it seems to fail on large chunked
responses, erroring part way through a chunk by sending multiple RSTs and throwing a org.apache.http.TruncatedChunkException
.
So I'm wondering:
My basic approach is to copy everything from a servlet's request object to an apache components httpclient request and execute. More specfically, I:
host
header on the new request with the host/port I'm proxying to,The bit that is causing me issues is the last one. It seems to fail half way through a chunk and I get the following stacktrace:
org.apache.http.TruncatedChunkException: Truncated chunk ( expected size: 7752; actual size: 4077)
at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:186)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:138)
at <mypackage>.<MyServlet>.service(<MyServlet>.java:XXX)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.resteasy.plugins.server.servlet.FilterDispatcher.doFilter(FilterDispatcher.java:63)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:724)
I've snooped it with Wireshark and get a process something like this:
source dest info
client server [SYN] seq=0
server client [SYN, ACK] seq=0 ack=1
client server [ACK] seq=1 ack=1
client server GET /url?param=value... HTTP/1.1
server client [ACK] seq=1 ack=221
server client [TCP segment of a reassembled PDU]
client server [ACK] seq=221 ack=4345
client server [FIN, ACK] seq=221 ack=4345
server client [TCP segment of a reassembled PDU]
client server [RST] seq=221
server client Continuation or non-HTTP traffic
client server [RST] seq=221
In my limited understanding, FIN means 'I'm done sending', which IMO is fair enough since the client headers are already sent. However RST/reset seems to just attempt to drop the connection.
The HTTP headers for client are:
GET /some/path?params=values HTTP/1.1
connection: Keep-Alive
host: target.host.com
accept: */*
user-agent: Wget/1.14 (linux-gnu)
And for the server:
HTTP/1.1 200 OK
Date: Mon, 16 Sep 2013 03:59:37 GMT
Server: Apache-Coyote/1.1
Content-Disposition: inline; filename=geoserver-GetFeature.text
Content-Type: text/xml; subtype=gml/2.1.2
Vary: Accept-Encoding
Connection: close
Transfer-Encoding: chunked
btw, this question: [restlet ]TruncatedChunkException: looks similar, but doesn't seem to have any helpful info.
Update: I've tried with a non-chunked site (/. :-) ) and it fails similarly with a:
org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body
But each HttpClient uses an HttpMessageHandler that's pooled and reused by the IHttpClientFactory to reduce resource consumption, as long as the HttpMessageHandler's lifetime hasn't expired.
Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. That issue will result in SocketException errors. Possible approaches to solve that problem are based on the creation of the HttpClient object as singleton or static.
This post focuses on dotnet core, the benchmarks are run on dotnet core 3 preview3. HttpClient is really easy to use, and because of that, it's also really easy to use it wrong.
OK, I found out what I'd done. I'd cleaned up my connection too early - basically the boilerplate in my connection method had a
finally
{
client.getConnectionManager().shutdown();
}
but the method returned the stream object, so reading wasn't completed when the shutdown occurred.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With