Skip to content

Race condition causing reuse of leaked connections #9240

@ifedorenko

Description

@ifedorenko

OkHttp 5.3.2 fails with ProtocolException: Unexpected status line when client app leaks Response objects. The problem did not exist in 4.12 and may be related to this "Very small behavior change".

package com.salesforce.test.extensions

import mockwebserver3.Dispatcher
import mockwebserver3.MockResponse
import mockwebserver3.MockWebServer
import mockwebserver3.RecordedRequest
import okhttp3.OkHttpClient
import okhttp3.Request
import org.junit.jupiter.api.Test

internal class CorruptedConnectionTest {
    @Test
    fun test() {
        val server = MockWebServer()
        server.dispatcher = object : Dispatcher() {
            override fun dispatch(request: RecordedRequest): MockResponse {
                return MockResponse.Builder()
                    .code(200)
                    .body("body-"+request.url.pathSegments.single())
                    .build()
            }
        }
        server.start()

        val client = OkHttpClient.Builder().build()

        // leak a few responses
        client.newCall(Request.Builder().url(server.url("/a")).build()).execute()
        client.newCall(Request.Builder().url(server.url("/b")).build()).execute()

        // run gc to trigger connection pool leak detection logic
        System.gc()

        // run more requests
        client.newCall(Request.Builder().url(server.url("/c")).build()).execute().close()
        client.newCall(Request.Builder().url(server.url("/d")).build()).execute().close()
    }
}

The test above fails with the following exception

java.net.ProtocolException: Unexpected status line: body-aHTTP/1.1 200 OK

	at okhttp3.internal.http.StatusLine$Companion.parse(StatusLine.kt:73)
	at okhttp3.internal.http1.Http1ExchangeCodec.readResponseHeaders(Http1ExchangeCodec.kt:196)
	at okhttp3.internal.connection.Exchange.readResponseHeaders(Exchange.kt:117)
	at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:97)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:126)
	at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:126)
	at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:101)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:126)
	at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:85)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:126)
	at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:74)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:126)
	at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:226)
	at okhttp3.internal.connection.RealCall.execute(RealCall.kt:178)
	at com.salesforce.test.extensions.CorruptedConnectionTest.test(CorruptedConnectionTest.kt:36)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugBug in existing code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions