New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HTTP/2 not properly supported for PUT requests #2637
Comments
If I'm not mistaken there are no implementations of HTTP/2 without TLS. So my guess is that you set up a http stub that is served with HTTP/1.1. So it might be Java HttpClient's bug for not downgrading to HTTP/1.1 on non-TLS connection or not handling failed upgrade attempt properly. Or maybe underlying Jetty is not configured to use h2c for not-TLS HTTP/2 connections (probably need some configuration to enable it). return RestClient.builder()
.requestFactory(new JdkClientHttpRequestFactory(HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.build()))
.baseUrl(properties.baseUrl())
.build(); and it works. |
The point is that Wiremock is that HTTP stub and forcing HTTP/1.1 should not be needed. |
Well, I can only add that I could not reproduce error by using plain Jdk var httpClient = HttpClient.newHttpClient();
HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder()
.uri(new URI(runtimeInfo.getHttpBaseUrl() + "/something"))
.header("Content-Type", "application/json")
.PUT(HttpRequest.BodyPublishers.ofString("{ \"data\": \"test\" }"))
.build(),
HttpResponse.BodyHandlers.ofString()
); Same using |
The Spring Rewriting the code to use something streaming makes it fail with a plain var client = HttpClient.newHttpClient();
var body = new ObjectMapper().writeValueAsBytes(new SomeRequest(16));
var publisher = HttpRequest.BodyPublishers.ofByteArray(body, 0, body.length);
var request = HttpRequest.newBuilder().
.uri(URI.create(runtimeInfo.getHttpBaseUrl() + "/something"))
.header("Content-Type", "application/json")
.PUT(HttpRequest.BodyPublishers.fromPublisher(publisher))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body()); Result: I've attached the logging for the UPDATE: Fails with a simple |
This issue seems to discuss/elaborate the issue. Apparently HTTP/2 with an InputStream body is only supported on HTTPS. |
Same issue here #2585, the reason it can be hard to reproduce is that it is also linked to the size of the request. |
From a quick tcpdump session, as far as I can tell after WireMock has sent the 101 Upgrade response to HTTP/2 the client starts sending encrypted data despite us still being on a plain text connection. The reproducer test passes if you set the app's base URL to use HTTPS and disable certificate validation. I'm not sure there's much we can do here apart from add the option to disable HTTP/2 so that no upgrade happens. |
On further inspection, this isn't encryption related but definitely seems to be triggered by the combination of upgrade + PUT + chunked encoded request body. Seems this is undefined behaviour as far as Jetty is concerned unfortunately: |
HTTP/2 toggles added: 363e2ff |
Proposal
When writing a wiremock test that tests a PUT request via Spring's
RestClient
that uses the JDK 11 HttpClient as the underlying client, I getjava.io.EOFException: EOF reached while reading
error.By explicitly configuring to use HTTP 1.1 instead of HTTP/2, the error no longer happens.
See https://stackoverflow.com/questions/78151993/eof-reached-while-reading-with-spring-restclient-and-wiremock-using-jdkclienth for my SO post about the issue.
Reproduction steps
There is a reproducer project at https://github.com/wimdeblauwe/restclient-jdk-issue
References
No response
The text was updated successfully, but these errors were encountered: