File tree Expand file tree Collapse file tree 3 files changed +49
-3
lines changed
jvmMain/kotlin/okhttp3/internal Expand file tree Collapse file tree 3 files changed +49
-3
lines changed Original file line number Diff line number Diff line change @@ -18,7 +18,9 @@ package okhttp3.internal.http
1818import java.io.IOException
1919import java.net.ProtocolException
2020import okhttp3.Interceptor
21+ import okhttp3.Protocol
2122import okhttp3.Response
23+ import okhttp3.internal.connection.Exchange
2224import okhttp3.internal.http2.ConnectionShutdownException
2325import okhttp3.internal.stripBody
2426import 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}
Original file line number Diff line number Diff line change @@ -34,6 +34,7 @@ import okhttp3.internal.http.StatusLine
3434import okhttp3.internal.http.promisesBody
3535import okhttp3.internal.http.receiveHeaders
3636import okhttp3.internal.http.HTTP_CONTINUE
37+ import okhttp3.internal.http.HTTP_EARLY_HINTS
3738import okhttp3.internal.skipAll
3839import okio.Buffer
3940import 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
Original file line number Diff line number Diff 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()
You can’t perform that action at this time.
0 commit comments