From b565eecf167918253145bce2c348b0bb0ef58b0c Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sun, 16 Oct 2022 21:32:03 +0100 Subject: [PATCH] Ignore early hints for 4.9.x (#7444) --- .../internal/http/CallServerInterceptor.kt | 18 ++++++++++-- .../internal/http1/Http1ExchangeCodec.kt | 6 ++++ okhttp/src/jvmTest/java/okhttp3/CallTest.kt | 28 +++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/okhttp/src/jvmMain/kotlin/okhttp3/internal/http/CallServerInterceptor.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/http/CallServerInterceptor.kt index 6cb8f0317b93..87c3fda482bd 100644 --- a/okhttp/src/jvmMain/kotlin/okhttp3/internal/http/CallServerInterceptor.kt +++ b/okhttp/src/jvmMain/kotlin/okhttp3/internal/http/CallServerInterceptor.kt @@ -18,7 +18,9 @@ package okhttp3.internal.http import java.io.IOException import java.net.ProtocolException import okhttp3.Interceptor +import okhttp3.Protocol import okhttp3.Response +import okhttp3.internal.connection.Exchange import okhttp3.internal.http2.ConnectionShutdownException import okhttp3.internal.stripBody import okio.buffer @@ -103,9 +105,8 @@ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor { .receivedResponseAtMillis(System.currentTimeMillis()) .build() var code = response.code - if (code == 100) { - // Server sent a 100-continue even though we did not request one. Try again to read the - // actual response status. + + if (shouldIgnoreAndWaitForRealResponse(code, exchange)) { responseBuilder = exchange.readResponseHeaders(expectContinue = false)!! if (invokeStartEvent) { exchange.responseHeadersStart() @@ -146,4 +147,15 @@ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor { throw e } } + + private fun shouldIgnoreAndWaitForRealResponse(code: Int, exchange: Exchange): Boolean = when { + // Server sent a 100-continue even though we did not request one. Try again to read the + // actual response status. + code == 100 -> true + + // Early Hints (103) but not supported yet in OkHttp + code == 103 -> true + + else -> false + } } diff --git a/okhttp/src/jvmMain/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt index 7d307d19fbc9..b615211350c1 100644 --- a/okhttp/src/jvmMain/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt +++ b/okhttp/src/jvmMain/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt @@ -34,6 +34,7 @@ import okhttp3.internal.http.StatusLine import okhttp3.internal.http.promisesBody import okhttp3.internal.http.receiveHeaders import okhttp3.internal.http.HTTP_CONTINUE +import okhttp3.internal.http.HTTP_EARLY_HINTS import okhttp3.internal.skipAll import okio.Buffer import okio.BufferedSink @@ -192,6 +193,11 @@ class Http1ExchangeCodec( state = STATE_READ_RESPONSE_HEADERS responseBuilder } + statusLine.code == HTTP_EARLY_HINTS -> { + // Early Hints will mean a second header are coming. + state = STATE_READ_RESPONSE_HEADERS + responseBuilder + } else -> { state = STATE_OPEN_RESPONSE_BODY responseBuilder diff --git a/okhttp/src/jvmTest/java/okhttp3/CallTest.kt b/okhttp/src/jvmTest/java/okhttp3/CallTest.kt index 18a85761eef1..33ba20355c17 100644 --- a/okhttp/src/jvmTest/java/okhttp3/CallTest.kt +++ b/okhttp/src/jvmTest/java/okhttp3/CallTest.kt @@ -2744,6 +2744,34 @@ open class CallTest { assertThat(recordedRequest.body.readUtf8()).isEqualTo("abc") } + @Test fun serverRespondsWithEarlyHintsHttp2() { + enableProtocol(Protocol.HTTP_2) + serverRespondsWithEarlyHints() + } + + @Test fun serverRespondsWithEarlyHints() { + val mockResponse = MockResponse() + server.enqueue( + mockResponse.apply { + addInformationalResponse( + MockResponse() + .setResponseCode(103) + .setHeaders(headersOf("Link", "; rel=preload; as=style")) + ) + } + ) + val request = Request( + url = server.url("/"), + body = "abc".toRequestBody("text/plain".toMediaType()), + ) + executeSynchronously(request) + .assertCode(200) + .assertSuccessful() + val recordedRequest = server.takeRequest() + assertThat(recordedRequest.body.readUtf8()).isEqualTo("abc") + assertThat(recordedRequest.headers["Link"]).isNull() + } + @Test fun serverRespondsWithUnsolicited100Continue_HTTP2() { enableProtocol(Protocol.HTTP_2) serverRespondsWithUnsolicited100Continue()