question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Excess whitespace character - java.net.ProtocolException: Unexpected status line: ' HTTP/1.1 200 OK'

See original GitHub issue
protected OkHttpClient getHttpClient() {
    OkHttpClient.Builder builder = new OkHttpClient.Builder()
            .addInterceptor(new Cookies())
            .addInterceptor(new Headers());
    return builder.build();
}

protected Retrofit getRetrofit() {
    return new Retrofit.Builder()
            .baseUrl(getBaseUrl())
            .client(getHttpClient())
            .addConverterFactory(GsonConverterFactory.create())
            .build();
}

public interface ApiFiles {
    @GET("api/files/images/{name}")
    Call<ResponseBody> image(@Path("name") String name);
}

Bottom code code works correctly but produce memory leak. After a large number of requests, an exception is thrown android.system.ErrnoException: connect failed: EMFILE (Too many open files)

//works correctly but creates a memory leak after a large number of requests
getRetrofit().create(ApiFiles.class).image("name.jpg").execute();
getRetrofit().create(ApiFiles.class).image("name.jpg").execute(); 
getRetrofit().create(ApiFiles.class).image("name.jpg").execute();

This code produce java.net.ProtocolException: Unexpected status line: " HTTP/1.1 200 OK" on second call. Extra space at the beginning of the status line

ApiFiles call = getRetrofit().create(ApiFiles.class);
call.image("name.jpg").execute();
//next line throws java.net.ProtocolException
call.image("name.jpg").execute();
call.image("name.jpg").execute();

Without retrofit everything works correctly

//works correctly
OkHttpClient client = getHttpClient();
client.newCall(new Request.Builder().url(getBaseUrl() + "api/files/images/name.jpg").build()).execute();
client.newCall(new Request.Builder().url(getBaseUrl() + "api/files/images/name.jpg").build()).execute();

The server receives identical requests and gives identical answers.

If I add “Connection: close” header, everything gets fine

But the server needs to process sequential queries in one close, and this header will increase the load on the server

I think, this is some sort of okhttp problem, when sending requests to the server that does not close the connection after the first request, because after requests to the server that close the connection, such an exception does not thrown.

How to get rid of ProtocolException when using retrofit?

I prepared an android project in which you can repeat and test the problem. Write if necessary

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:9 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
KursXcommented, Apr 4, 2018

I noticed that in Retrofit2, unlike OkHttp3, with multiple requests, the response is read from the same Buffer. After the first request, the buffer size is one byte greater than the Content-Length. Because of this, after reading the entire response, there is a byte in the buffer, which is most likely a space. When reading the response to the second request in the same buffer, this space goes to the beginning. There is status line In the beginning. Since the heder is truncated by the \n character, this space is at the top of the status line and throws ProtocolException. It seems to me necessary to clear this buffer after processing of request, or before new request.

0reactions
KursXcommented, Apr 21, 2018

@JakeWharton, you can repeat this problem yourself

public class MainActivity extends AppCompatActivity {

    private OkHttpClient httpClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {

            public void run() {
                try {
                    //works correctly
                    OkHttpClient client = getHttpClient();
                    client.newCall(new Request.Builder().url(getBaseUrl() + "api/files/slides/videos/covers/name.jpg").build()).execute();
                    client.newCall(new Request.Builder().url(getBaseUrl() + "api/files/slides/videos/covers/name.jpg").build()).execute();


                    ApiFiles call = getRetrofit().create(ApiFiles.class);
                    call.image("name.jpg").execute();
                    //next line throws java.net.ProtocolException: Unexpected status line:  HTTP/1.1 500 Internal Server Error
                    call.image("name.jpg").execute();
                    call.image("name.jpg").execute();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public String getBaseUrl() {
        return "https://api.dev1.wise-rep.com/";
    }

    protected Retrofit getRetrofit() {
        return new Retrofit.Builder()
                .baseUrl(getBaseUrl())
                .client(getHttpClient())
                .build();
    }

    public OkHttpClient getHttpClient() {
        return new OkHttpClient.Builder().build();
    }

    public interface ApiFiles {
        @GET("api/files/slides/videos/covers/{name}")
        Call<ResponseBody> image(@Path("name") String name);
    }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

OkHttp "java.net.ProtocolException: Unexpected status line ...
Looks like your webserver is claiming the prior response has no body, but then writing a four character body “null”.
Read more >
JDK-8209178 Proxied HttpsURLConnection doesn't ... - Bug ID
I'm switching this from security-libs/javax.net.ssl. I believe TLS is not causing the problem and the exception is caused by http-client. The TLS read...
Read more >
java.net.ProtocolException: Unexpected status line - B4X
The http response is invalid. It should start with the status line (ex: Http/1.1 200 OK). You can use Socket with AsyncStreams to...
Read more >
RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
This specification defines the protocol referred to as "HTTP/1.1", ... The server responds with a status line, including the message's protocol version and ......
Read more >
jdk/jdk: 4254bed3c09d - Java.net
wrapWithExtraDetail; /** * Encapsulates one HTTP/1.1 request/response exchange. ... protocolException("Bad trailing char, \"%s\", when parsing status line, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found