Okhttp: HTTP/2 fails with PROTOCOL_ERROR on nginx, including wordpress.com

Created on 5 Oct 2015  Â·  16Comments  Â·  Source: square/okhttp

In android 5.1.1 (Moto G 3) call to the url "https://public-api.wordpress.com/rest/v1/sites/73350021/posts/60915" gave the exception "android java.io.IOException: stream was reset: PROTOCOL_ERROR". The same works fine in devices with older OS.The stacktrace is :

10-05 20:32:41.195 15373-15373/? D/NetworkError﹕ stream was reset: PROTOCOL_ERROR
java.io.IOException: stream was reset: PROTOCOL_ERROR
at com.squareup.okhttp.internal.spdy.SpdyStream.getResponseHeaders(SpdyStream.java:145)
at com.squareup.okhttp.internal.http.SpdyTransport.readResponseHeaders(SpdyTransport.java:104)
at com.squareup.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:830)
at com.squareup.okhttp.internal.http.HttpEngine.access$200(HttpEngine.java:95)
at com.squareup.okhttp.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:823)
at com.squareup.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:684)
at com.squareup.okhttp.Call.getResponse(Call.java:272)
at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:228)
at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:199)
at com.squareup.okhttp.Call.execute(Call.java:79)

Most helpful comment

How dit you set it to use HTTP1.1? for me this worked:

OkHttpClient client = new OkHttpClient().setProtocols(Collections.singletonList(Protocol.HTTP_1_1));

All 16 comments

It works fine on an S3 running 4.4.4

I see this on a Samsung S5 running 5.0

The phone received an update the other day (that fixes Stagefright among other things), do not know if that is related.

Hi everybody
I have the same error here. My current setup is:

compile 'com.google.code.gson:gson:2.3.1'
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.5.0'
compile 'com.squareup.okhttp:okhttp:2.5.0'
compile 'com.squareup.okio:okio:1.6.0'
RestAdapter apiRestAdapter = new RestAdapter.Builder()
    .setEndpoint(endpoint)
    .setLogLevel(RestAdapter.LogLevel.BASIC)
    .build();
mService = apiRestAdapter.create(WordpressService.class);

Hitting

https://public-api.wordpress.com/rest/v1/freshly-pressed?number=30

  • KitKat 4.4.4 works fine
  • Marshmallow 6 java.io.IOException: stream was reset: PROTOCOL_ERROR

If I switch to retrofit 2.0 beta, as suggested in #1844, both phones fail. If I force okhttp to use HTTP 1.1, as suggested in #1844 and in a couple of SO threads, I get _404 Page not found_.
Any clue?
Thanks

How dit you set it to use HTTP1.1? for me this worked:

OkHttpClient client = new OkHttpClient().setProtocols(Collections.singletonList(Protocol.HTTP_1_1));

@jedrivisser I tried that during my tests with retrofit 2 and it didn't work. Which version of retrofit/okhttp are you using?

I am using okhttp directly:

compile 'com.squareup.okhttp:okhttp:2.5.0'

Unfortunately, I'm using it with retrofit. I hope I can get some feedback here https://github.com/square/retrofit/issues/1181

can you paste the code for how you forced retrofit to use HTTP 1.1?

I switched the project to retrofit 2 and I removed the dependency from okhttp, that should be implicitly imported:

build.gradle

compile 'com.google.code.gson:gson:2.4'
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'
compile 'com.squareup.okio:okio:1.6.0'

Api Client

I edited the baseurl: it now ends with "/" and I forced HTTP 1.1 again, as @jedrivisser suggested :+1:

public WordpressApiManager(String endpoint) {
    OkHttpClient client = 
                new OkHttpClient().setProtocols(Collections.singletonList(Protocol.HTTP_1_1));

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(endpoint)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .build();

    mService = retrofit.create(WordpressService.class);
}

I fixed the endpoint accordingly to the new baseurl:

public interface WordpressService {

    @GET("freshly-pressed")
    Observable<PostsResponse> getPosts(@Query("number") int number);
}

It's working on Android 4.4.4, 5.0.2 and 6. I couldn't test it on 5.1.1.
Thank you for your help.
device-2015-10-08-180938

This is sth with h2 negotiation.

@praveenbb thanks for reporting this, I've been able to reproduce on the desktop JVM.

I think it’s a bug in the nginx beta.

OkHttp sends this header:

accept-encoding: gzip

This causes nginx to incorrectly report a protocol error.

I believe it's related to nginx’s HPACK decoder. I’m led to this assumption because I see similar PROTOCOL_ERRORs reported when using other headers in the indexed set, such as accept-charset.

thanks for all the feedback!

OkHttpClient client = new OkHttpClient().setProtocols(Collections.singletonList(Protocol.HTTP_1_1))

This worked for me.

Before that line of code added, the images were displaying on some android devices, but not others. The same image in the same Activity was working on 1 device and not on others.

forcing the protocol to HTTP1 fixed the issue.

okHttpClient.setProtocols(Collections.singletonList(Protocol.HTTP_1_1));

Was this page helpful?
0 / 5 - 0 ratings