okhttp: H2 issue with unknown settings parameter causes malformed requests
My team recently tracked down an issue with okhttp where multiple requests on the same H2 connection would fail due to a new unexpected parameter in the H2 settings frame. Other clients and browser do not seem to have an issue with it however okhttp does, per the RFC 7540 (section 6.5.2) the client must ignore any setting it does not understand.
From the client side we see the first request succeed then subsequent requests fail. From the server side we see the first request succeed then subsequent requests come in with a malformed payload body. Also worth noting the size of the payload matters in reproducing the issue.
Sample code to reproduce the issue (the server is important as it is setup with the extra settings frame parameter):
public class Demo {
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient().newBuilder().build();
String post(String url) throws IOException {
String json="{'test':'grrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr'}";
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
public static void main(String[] args) throws IOException {
Demo example = new Demo();
for(int i=0;i<100;i++)
{
String response2 = example.post("https://rk.losgiova.com/okhttp/test.html?"+i);
System.out.println(response2);
}
}
}
Results
ok
Exception in thread "main" java.net.SocketTimeoutException: timeout
at okhttp3@4.9.1/okhttp3.internal.http2.Http2Stream$StreamTimeout.newTimeoutException(Http2Stream.kt:677)
at okhttp3@4.9.1/okhttp3.internal.http2.Http2Stream$StreamTimeout.exitAndThrowIfTimedOut(Http2Stream.kt:686)
at okhttp3@4.9.1/okhttp3.internal.http2.Http2Stream$FramingSink.emitFrame(Http2Stream.kt:557)
at okhttp3@4.9.1/okhttp3.internal.http2.Http2Stream$FramingSink.close(Http2Stream.kt:614)
at okio.ForwardingSink.close(ForwardingSink.kt:37)
at okhttp3@4.9.1/okhttp3.internal.connection.Exchange$RequestBodySink.close(Exchange.kt:242)
at okio.RealBufferedSink.close(RealBufferedSink.kt:286)
at okhttp3@4.9.1/okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:60)
at okhttp3@4.9.1/okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3@4.9.1/okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34)
at okhttp3@4.9.1/okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3@4.9.1/okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
at okhttp3@4.9.1/okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3@4.9.1/okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
at okhttp3@4.9.1/okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3@4.9.1/okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
at okhttp3@4.9.1/okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3@4.9.1/okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
at okhttp3@4.9.1/okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
at okhttptestclient/okhttptestclient.Demo.post(Demo.java:30)
at okhttptestclient/okhttptestclient.Demo.main(Demo.java:43)
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 21 (5 by maintainers)
Sounds like a problem with HTTP/2 window updates.