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 {
1114
1114
public final fun networkResponse ()Lokhttp3/Response;
1115
1115
public final fun newBuilder ()Lokhttp3/Response$Builder;
1116
1116
public final fun peekBody (J)Lokhttp3/ResponseBody;
1117
+ public final fun peekTrailers ()Lokhttp3/Headers;
1117
1118
public final fun priorResponse ()Lokhttp3/Response;
1118
1119
public final fun protocol ()Lokhttp3/Protocol;
1119
1120
public final fun receivedResponseAtMillis ()J
@@ -1219,11 +1220,16 @@ public abstract interface class okhttp3/TrailersSource {
1219
1220
public static final field Companion Lokhttp3/TrailersSource$Companion;
1220
1221
public static final field EMPTY Lokhttp3/TrailersSource;
1221
1222
public abstract fun get ()Lokhttp3/Headers;
1223
+ public fun peek ()Lokhttp3/Headers;
1222
1224
}
1223
1225
1224
1226
public final class okhttp3/TrailersSource$Companion {
1225
1227
}
1226
1228
1229
+ public final class okhttp3/TrailersSource$DefaultImpls {
1230
+ public static fun peek (Lokhttp3/TrailersSource;)Lokhttp3/Headers;
1231
+ }
1232
+
1227
1233
public abstract interface class okhttp3/WebSocket {
1228
1234
public abstract fun cancel ()V
1229
1235
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 {
1114
1114
public final fun networkResponse ()Lokhttp3/Response;
1115
1115
public final fun newBuilder ()Lokhttp3/Response$Builder;
1116
1116
public final fun peekBody (J)Lokhttp3/ResponseBody;
1117
+ public final fun peekTrailers ()Lokhttp3/Headers;
1117
1118
public final fun priorResponse ()Lokhttp3/Response;
1118
1119
public final fun protocol ()Lokhttp3/Protocol;
1119
1120
public final fun receivedResponseAtMillis ()J
@@ -1219,11 +1220,16 @@ public abstract interface class okhttp3/TrailersSource {
1219
1220
public static final field Companion Lokhttp3/TrailersSource$Companion;
1220
1221
public static final field EMPTY Lokhttp3/TrailersSource;
1221
1222
public abstract fun get ()Lokhttp3/Headers;
1223
+ public fun peek ()Lokhttp3/Headers;
1222
1224
}
1223
1225
1224
1226
public final class okhttp3/TrailersSource$Companion {
1225
1227
}
1226
1228
1229
+ public final class okhttp3/TrailersSource$DefaultImpls {
1230
+ public static fun peek (Lokhttp3/TrailersSource;)Lokhttp3/Headers;
1231
+ }
1232
+
1227
1233
public abstract interface class okhttp3/WebSocket {
1228
1234
public abstract fun cancel ()V
1229
1235
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(
192
192
@Throws(IOException ::class )
193
193
fun trailers (): Headers = trailersSource.get()
194
194
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
+
195
215
/* *
196
216
* Peeks up to [byteCount] bytes from the response body and returns them as a new response
197
217
* 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
27
27
* This interface is for test and production code that creates [Response] instances without making
28
28
* an HTTP call to a remote server.
29
29
*/
30
- fun interface TrailersSource {
30
+ interface TrailersSource {
31
+ @Throws(IOException ::class )
32
+ fun peek (): Headers ? = null
33
+
31
34
@Throws(IOException ::class )
32
35
fun get (): Headers
33
36
34
37
companion object {
35
38
@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
+ }
37
45
}
38
46
}
Original file line number Diff line number Diff line change @@ -141,7 +141,7 @@ class Exchange(
141
141
}
142
142
143
143
@Throws(IOException ::class )
144
- fun trailers (): Headers = codec.trailers ()
144
+ fun peekTrailers (): Headers ? = codec.peekTrailers ()
145
145
146
146
@Throws(SocketException ::class )
147
147
fun newWebSocketStreams (): RealWebSocket .Streams {
Original file line number Diff line number Diff line change @@ -17,8 +17,10 @@ package okhttp3.internal.http
17
17
18
18
import java.io.IOException
19
19
import java.net.ProtocolException
20
+ import okhttp3.Headers
20
21
import okhttp3.Interceptor
21
22
import okhttp3.Response
23
+ import okhttp3.TrailersSource
22
24
import okhttp3.internal.connection.Exchange
23
25
import okhttp3.internal.http2.ConnectionShutdownException
24
26
import okhttp3.internal.skipAll
@@ -134,13 +136,19 @@ class CallServerInterceptor(
134
136
response
135
137
.newBuilder()
136
138
.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()
144
152
}
145
153
if (" close" .equals(response.request.header(" Connection" ), ignoreCase = true ) ||
146
154
" close" .equals(response.header(" Connection" ), ignoreCase = true )
Original file line number Diff line number Diff line change @@ -66,9 +66,9 @@ interface ExchangeCodec {
66
66
@Throws(IOException ::class )
67
67
fun openResponseBodySource (response : Response ): Source
68
68
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. */
70
70
@Throws(IOException ::class )
71
- fun trailers (): Headers
71
+ fun peekTrailers (): Headers ?
72
72
73
73
/* *
74
74
* 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(
147
147
}
148
148
}
149
149
150
- override fun trailers (): Headers {
150
+ override fun peekTrailers (): Headers ? {
151
151
if (trailers == = TRAILERS_RESPONSE_BODY_TRUNCATED ) {
152
152
throw IOException (" Trailers cannot be read because the response body was truncated" )
153
153
}
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
155
158
}
156
159
157
160
override fun flushRequest () {
Original file line number Diff line number Diff line change @@ -115,7 +115,7 @@ class Http2ExchangeCodec(
115
115
116
116
override fun openResponseBodySource (response : Response ): Source = stream!! .source
117
117
118
- override fun trailers (): Headers = stream!! .trailers ()
118
+ override fun peekTrailers (): Headers ? = stream!! .peekTrailers ()
119
119
120
120
override fun cancel () {
121
121
canceled = true
Original file line number Diff line number Diff line change @@ -168,19 +168,18 @@ class Http2Stream internal constructor(
168
168
}
169
169
170
170
/* *
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.
173
172
*/
174
173
@Throws(IOException ::class )
175
- fun trailers (): Headers {
174
+ fun peekTrailers (): Headers ? {
176
175
withLock {
177
176
if (source.finished && source.receiveBuffer.exhausted() && source.readBuffer.exhausted()) {
178
177
return source.trailers ? : Headers .EMPTY
179
178
}
180
179
if (errorCode != null ) {
181
180
throw errorException ? : StreamResetException (errorCode!! )
182
181
}
183
- throw IllegalStateException ( " too early; can't read the trailers yet " )
182
+ return null
184
183
}
185
184
}
186
185
You can’t perform that action at this time.
0 commit comments