File tree Expand file tree Collapse file tree 13 files changed +217
-34
lines changed
commonJvmAndroid/kotlin/okhttp3 Expand file tree Collapse file tree 13 files changed +217
-34
lines changed Original file line number Diff line number Diff line change @@ -1114,6 +1114,7 @@ public final class okhttp3/Response : java/io/Closeable {
11141114 public final fun networkResponse ()Lokhttp3/Response;
11151115 public final fun newBuilder ()Lokhttp3/Response$Builder;
11161116 public final fun peekBody (J)Lokhttp3/ResponseBody;
1117+ public final fun peekTrailers ()Lokhttp3/Headers;
11171118 public final fun priorResponse ()Lokhttp3/Response;
11181119 public final fun protocol ()Lokhttp3/Protocol;
11191120 public final fun receivedResponseAtMillis ()J
@@ -1219,11 +1220,16 @@ public abstract interface class okhttp3/TrailersSource {
12191220 public static final field Companion Lokhttp3/TrailersSource$Companion;
12201221 public static final field EMPTY Lokhttp3/TrailersSource;
12211222 public abstract fun get ()Lokhttp3/Headers;
1223+ public fun peek ()Lokhttp3/Headers;
12221224}
12231225
12241226public final class okhttp3/TrailersSource$Companion {
12251227}
12261228
1229+ public final class okhttp3/TrailersSource$DefaultImpls {
1230+ public static fun peek (Lokhttp3/TrailersSource;)Lokhttp3/Headers;
1231+ }
1232+
12271233public abstract interface class okhttp3/WebSocket {
12281234 public abstract fun cancel ()V
12291235 public abstract fun close (ILjava/lang/String;)Z
Original file line number Diff line number Diff line change @@ -1114,6 +1114,7 @@ public final class okhttp3/Response : java/io/Closeable {
11141114 public final fun networkResponse ()Lokhttp3/Response;
11151115 public final fun newBuilder ()Lokhttp3/Response$Builder;
11161116 public final fun peekBody (J)Lokhttp3/ResponseBody;
1117+ public final fun peekTrailers ()Lokhttp3/Headers;
11171118 public final fun priorResponse ()Lokhttp3/Response;
11181119 public final fun protocol ()Lokhttp3/Protocol;
11191120 public final fun receivedResponseAtMillis ()J
@@ -1219,11 +1220,16 @@ public abstract interface class okhttp3/TrailersSource {
12191220 public static final field Companion Lokhttp3/TrailersSource$Companion;
12201221 public static final field EMPTY Lokhttp3/TrailersSource;
12211222 public abstract fun get ()Lokhttp3/Headers;
1223+ public fun peek ()Lokhttp3/Headers;
12221224}
12231225
12241226public final class okhttp3/TrailersSource$Companion {
12251227}
12261228
1229+ public final class okhttp3/TrailersSource$DefaultImpls {
1230+ public static fun peek (Lokhttp3/TrailersSource;)Lokhttp3/Headers;
1231+ }
1232+
12271233public abstract interface class okhttp3/WebSocket {
12281234 public abstract fun cancel ()V
12291235 public abstract fun close (ILjava/lang/String;)Z
Original file line number Diff line number Diff line change @@ -192,6 +192,26 @@ class Response internal constructor(
192192 @Throws(IOException ::class )
193193 fun trailers (): Headers = trailersSource.get()
194194
195+ /* *
196+ * Returns the trailers after the HTTP response, if they are available to read immediately. Unlike
197+ * [trailers], this doesn't block if the trailers are not immediately available, and instead
198+ * returns null.
199+ *
200+ * This will typically return null until [ResponseBody.source] has buffered the last byte of the
201+ * response body. Call `body.source().request(1024 * 1024)` to block until either that's done, or
202+ * 1 MiB of response data is loaded into memory. (You could use any size here, though large values
203+ * risk exhausting memory.)
204+ *
205+ * This returns an empty value if the trailers are available, but have no data.
206+ *
207+ * It is not safe to call this concurrently with code that is processing the response body.
208+ *
209+ * @throws IOException if the trailers cannot be loaded, such as if the network connection is
210+ * dropped.
211+ */
212+ @Throws(IOException ::class )
213+ fun peekTrailers (): Headers ? = trailersSource.peek()
214+
195215 /* *
196216 * Peeks up to [byteCount] bytes from the response body and returns them as a new response
197217 * body. If fewer than [byteCount] bytes are in the response body, the full response body is
Original file line number Diff line number Diff line change @@ -27,12 +27,20 @@ import okio.IOException
2727 * This interface is for test and production code that creates [Response] instances without making
2828 * an HTTP call to a remote server.
2929 */
30- fun interface TrailersSource {
30+ interface TrailersSource {
31+ @Throws(IOException ::class )
32+ fun peek (): Headers ? = null
33+
3134 @Throws(IOException ::class )
3235 fun get (): Headers
3336
3437 companion object {
3538 @JvmField
36- val EMPTY : TrailersSource = TrailersSource { Headers .EMPTY }
39+ val EMPTY : TrailersSource =
40+ object : TrailersSource {
41+ override fun peek () = Headers .EMPTY
42+
43+ override fun get () = Headers .EMPTY
44+ }
3745 }
3846}
Original file line number Diff line number Diff line change @@ -141,7 +141,7 @@ class Exchange(
141141 }
142142
143143 @Throws(IOException ::class )
144- fun trailers (): Headers = codec.trailers ()
144+ fun peekTrailers (): Headers ? = codec.peekTrailers ()
145145
146146 @Throws(SocketException ::class )
147147 fun newWebSocketStreams (): RealWebSocket .Streams {
Original file line number Diff line number Diff line change @@ -17,8 +17,10 @@ package okhttp3.internal.http
1717
1818import java.io.IOException
1919import java.net.ProtocolException
20+ import okhttp3.Headers
2021import okhttp3.Interceptor
2122import okhttp3.Response
23+ import okhttp3.TrailersSource
2224import okhttp3.internal.connection.Exchange
2325import okhttp3.internal.http2.ConnectionShutdownException
2426import okhttp3.internal.skipAll
@@ -134,13 +136,19 @@ class CallServerInterceptor(
134136 response
135137 .newBuilder()
136138 .body(responseBody)
137- .trailers {
138- val source = responseBody.source()
139- if (source.isOpen) {
140- source.skipAll()
141- }
142- exchange.trailers()
143- }.build()
139+ .trailers(
140+ object : TrailersSource {
141+ override fun peek () = exchange.peekTrailers()
142+
143+ override fun get (): Headers {
144+ val source = responseBody.source()
145+ if (source.isOpen) {
146+ source.skipAll()
147+ }
148+ return peek() ? : error(" null trailers after exhausting response body?!" )
149+ }
150+ },
151+ ).build()
144152 }
145153 if (" close" .equals(response.request.header(" Connection" ), ignoreCase = true ) ||
146154 " close" .equals(response.header(" Connection" ), ignoreCase = true )
Original file line number Diff line number Diff line change @@ -66,9 +66,9 @@ interface ExchangeCodec {
6666 @Throws(IOException ::class )
6767 fun openResponseBodySource (response : Response ): Source
6868
69- /* * Returns the trailers after the HTTP response. May be empty. */
69+ /* * Returns the trailers after the HTTP response if they're ready . May be empty. */
7070 @Throws(IOException ::class )
71- fun trailers (): Headers
71+ fun peekTrailers (): Headers ?
7272
7373 /* *
7474 * Cancel this stream. Resources held by this stream will be cleaned up, though not synchronously.
Original file line number Diff line number Diff line change @@ -147,11 +147,14 @@ class Http1ExchangeCodec(
147147 }
148148 }
149149
150- override fun trailers (): Headers {
150+ override fun peekTrailers (): Headers ? {
151151 if (trailers == = TRAILERS_RESPONSE_BODY_TRUNCATED ) {
152152 throw IOException (" Trailers cannot be read because the response body was truncated" )
153153 }
154- return trailers ? : error(" state: $state " )
154+ check(state == STATE_READING_RESPONSE_BODY || state == STATE_CLOSED ) {
155+ " Trailers cannot be read because the state is $state "
156+ }
157+ return trailers
155158 }
156159
157160 override fun flushRequest () {
Original file line number Diff line number Diff line change @@ -115,7 +115,7 @@ class Http2ExchangeCodec(
115115
116116 override fun openResponseBodySource (response : Response ): Source = stream!! .source
117117
118- override fun trailers (): Headers = stream!! .trailers ()
118+ override fun peekTrailers (): Headers ? = stream!! .peekTrailers ()
119119
120120 override fun cancel () {
121121 canceled = true
Original file line number Diff line number Diff line change @@ -168,19 +168,18 @@ class Http2Stream internal constructor(
168168 }
169169
170170 /* *
171- * Returns the trailers. It is only safe to call this once the source stream has been completely
172- * exhausted.
171+ * Returns the trailers if they're immediately available.
173172 */
174173 @Throws(IOException ::class )
175- fun trailers (): Headers {
174+ fun peekTrailers (): Headers ? {
176175 withLock {
177176 if (source.finished && source.receiveBuffer.exhausted() && source.readBuffer.exhausted()) {
178177 return source.trailers ? : Headers .EMPTY
179178 }
180179 if (errorCode != null ) {
181180 throw errorException ? : StreamResetException (errorCode!! )
182181 }
183- throw IllegalStateException ( " too early; can't read the trailers yet " )
182+ return null
184183 }
185184 }
186185
You can’t perform that action at this time.
0 commit comments