Jetty client sometimes uses chunked transfer encoding for GET requests
Opened this issue · 4 comments
When sending a GET
request (no body) using the Jetty client sometimes it sends multiple network-level requests and uses Transfer-Encoding: chunked
. From local testing manually setting content-length
to 0
means this issue does not occur.
I've tried to produce a test with TestContext
from cats-effect
but trying to use the Jetty client leads to a deadlock (I can create it and tear it down with no issues).
If I had to guess I would say this is due to a race between the Jetty request being sent and the content for that request being populated, the lines are here:
If the request sends (jReq.send(rl)
) before the delayed content has written (dcp.write(req)
, dcp
is a StreamRequestContentProvider
) the request will be chunked.
Possibly just inverting these lines might mean the race is less likely? Unless are that way around for a reason (send before write).
http4s version: 0.21.0-M5
. Sorry, only just realised this isn't the latest but I think there have been no changes between versions.
I was looking at this and noticed a few things:
- Moving the
dcp.write
action before thejReq.send
seems to consistently give you theContent-Length
and noTransfer-Encoding
when there's no body. - Sleeping for a second after the
jReq.send
consistently gives you theTransfer-Encoding
instead ofContent-Length
. - If you explicitly set the content length everything's fine either way.
For context we ran into this issue when talking to an akka-http server that gives an annoying "Sending an 2xx early" warning for any GET request with Transfer-Encoding: chunked
.
We have seen some errors in production with the 0 content-lenth
"fix" that imply this is actually not a fix. An internal http4s "something terrible has happened" http4s error and a Jetty "incorrect content-length" error. In both cases the requests being sent a very simple GET
requests.
These are very infrequent in percentage terms, but they do occur.
ERROR o.h.c.j.StreamRequestContentProvider - Unable to write to Jetty sinkjava.lang.Exception: something terrible has happened
at org.http4s.client.jetty.StreamRequestContentProvider.$anonfun$pipe$3(StreamRequestContentProvider.scala:31)
ERROR o.h.client.jetty.ResponseListener - Failed requestorg.eclipse.jetty.http.BadMessageException: 500: Incorrect Content-Length 0!=46
at org.eclipse.jetty.http.HttpGenerator.generateHeaders(HttpGenerator.java:632)
at org.eclipse.jetty.http.HttpGenerator.generateRequest(HttpGenerator.java:236)
at org.eclipse.jetty.client.http.HttpSenderOverHTTP$HeadersCallback.process(HttpSenderOverHTTP.java:214)
at org.eclipse.jetty.util.IteratingCallback.processing(IteratingCallback.java:241)
at org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:223)
at org.eclipse.jetty.client.http.HttpSenderOverHTTP.sendHeaders(HttpSenderOverHTTP.java:62)
at org.eclipse.jetty.client.HttpSender.send(HttpSender.java:212)
at org.eclipse.jetty.client.http.HttpChannelOverHTTP.send(HttpChannelOverHTTP.java:85)
at org.eclipse.jetty.client.HttpChannel.send(HttpChannel.java:128)
at org.eclipse.jetty.client.HttpConnection.send(HttpConnection.java:201)
at org.eclipse.jetty.client.http.HttpConnectionOverHTTP$Delegate.send(HttpConnectionOverHTTP.java:242)
at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.send(HttpConnectionOverHTTP.java:121)
at org.eclipse.jetty.client.http.HttpDestinationOverHTTP.send(HttpDestinationOverHTTP.java:38)
at org.eclipse.jetty.client.HttpDestination.process(HttpDestination.java:362)
at org.eclipse.jetty.client.HttpDestination.process(HttpDestination.java:320)
at org.eclipse.jetty.client.HttpDestination.send(HttpDestination.java:310)
at org.eclipse.jetty.client.HttpDestination.send(HttpDestination.java:285)
at org.eclipse.jetty.client.HttpDestination.send(HttpDestination.java:262)
at org.eclipse.jetty.client.HttpClient.send(HttpClient.java:570)
at org.eclipse.jetty.client.HttpRequest.send(HttpRequest.java:754)
at org.eclipse.jetty.client.HttpRequest.send(HttpRequest.java:746)
at org.http4s.client.jetty.JettyClient$.$anonfun$allocate$8(JettyClient.scala:29)
do you use request bodies on those GET requests?
@hamnis No, it's just a simple .fetchAs[Json](GET(query))
.