Skip to content

Commit b565eec

Browse files
authored
Ignore early hints for 4.9.x (#7444)
1 parent 6e5dfe7 commit b565eec

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

okhttp/src/jvmMain/kotlin/okhttp3/internal/http/CallServerInterceptor.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ package okhttp3.internal.http
1818
import java.io.IOException
1919
import java.net.ProtocolException
2020
import okhttp3.Interceptor
21+
import okhttp3.Protocol
2122
import okhttp3.Response
23+
import okhttp3.internal.connection.Exchange
2224
import okhttp3.internal.http2.ConnectionShutdownException
2325
import okhttp3.internal.stripBody
2426
import okio.buffer
@@ -103,9 +105,8 @@ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor {
103105
.receivedResponseAtMillis(System.currentTimeMillis())
104106
.build()
105107
var code = response.code
106-
if (code == 100) {
107-
// Server sent a 100-continue even though we did not request one. Try again to read the
108-
// actual response status.
108+
109+
if (shouldIgnoreAndWaitForRealResponse(code, exchange)) {
109110
responseBuilder = exchange.readResponseHeaders(expectContinue = false)!!
110111
if (invokeStartEvent) {
111112
exchange.responseHeadersStart()
@@ -146,4 +147,15 @@ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor {
146147
throw e
147148
}
148149
}
150+
151+
private fun shouldIgnoreAndWaitForRealResponse(code: Int, exchange: Exchange): Boolean = when {
152+
// Server sent a 100-continue even though we did not request one. Try again to read the
153+
// actual response status.
154+
code == 100 -> true
155+
156+
// Early Hints (103) but not supported yet in OkHttp
157+
code == 103 -> true
158+
159+
else -> false
160+
}
149161
}

okhttp/src/jvmMain/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import okhttp3.internal.http.StatusLine
3434
import okhttp3.internal.http.promisesBody
3535
import okhttp3.internal.http.receiveHeaders
3636
import okhttp3.internal.http.HTTP_CONTINUE
37+
import okhttp3.internal.http.HTTP_EARLY_HINTS
3738
import okhttp3.internal.skipAll
3839
import okio.Buffer
3940
import okio.BufferedSink
@@ -192,6 +193,11 @@ class Http1ExchangeCodec(
192193
state = STATE_READ_RESPONSE_HEADERS
193194
responseBuilder
194195
}
196+
statusLine.code == HTTP_EARLY_HINTS -> {
197+
// Early Hints will mean a second header are coming.
198+
state = STATE_READ_RESPONSE_HEADERS
199+
responseBuilder
200+
}
195201
else -> {
196202
state = STATE_OPEN_RESPONSE_BODY
197203
responseBuilder

okhttp/src/jvmTest/java/okhttp3/CallTest.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2744,6 +2744,34 @@ open class CallTest {
27442744
assertThat(recordedRequest.body.readUtf8()).isEqualTo("abc")
27452745
}
27462746

2747+
@Test fun serverRespondsWithEarlyHintsHttp2() {
2748+
enableProtocol(Protocol.HTTP_2)
2749+
serverRespondsWithEarlyHints()
2750+
}
2751+
2752+
@Test fun serverRespondsWithEarlyHints() {
2753+
val mockResponse = MockResponse()
2754+
server.enqueue(
2755+
mockResponse.apply {
2756+
addInformationalResponse(
2757+
MockResponse()
2758+
.setResponseCode(103)
2759+
.setHeaders(headersOf("Link", "</style.css>; rel=preload; as=style"))
2760+
)
2761+
}
2762+
)
2763+
val request = Request(
2764+
url = server.url("/"),
2765+
body = "abc".toRequestBody("text/plain".toMediaType()),
2766+
)
2767+
executeSynchronously(request)
2768+
.assertCode(200)
2769+
.assertSuccessful()
2770+
val recordedRequest = server.takeRequest()
2771+
assertThat(recordedRequest.body.readUtf8()).isEqualTo("abc")
2772+
assertThat(recordedRequest.headers["Link"]).isNull()
2773+
}
2774+
27472775
@Test fun serverRespondsWithUnsolicited100Continue_HTTP2() {
27482776
enableProtocol(Protocol.HTTP_2)
27492777
serverRespondsWithUnsolicited100Continue()

0 commit comments

Comments
 (0)