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)

Most upvoted comments

Sounds like a problem with HTTP/2 window updates.