mirror of
https://github.com/square/okhttp.git
synced 2025-11-27 18:21:14 +03:00
Keep the response body alive after the callback.
This commit is contained in:
@@ -34,11 +34,13 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -1285,6 +1287,44 @@ public final class CallTest {
|
||||
.assertRequestHeader("Accept-Encoding", "gzip");
|
||||
}
|
||||
|
||||
@Test public void asyncResponseCanBeConsumedLater() throws Exception {
|
||||
server.enqueue(new MockResponse().setBody("abc"));
|
||||
server.enqueue(new MockResponse().setBody("def"));
|
||||
server.play();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(server.getUrl("/"))
|
||||
.header("User-Agent", "SyncApiTest")
|
||||
.build();
|
||||
|
||||
final BlockingQueue<Response> responseRef = new SynchronousQueue<Response>();
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override public void onFailure(Request request, Throwable throwable) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Override public void onResponse(Response response) throws IOException {
|
||||
try {
|
||||
responseRef.put(response);
|
||||
} catch (InterruptedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Response response = responseRef.take();
|
||||
assertEquals(200, response.code());
|
||||
assertEquals("abc", response.body().string());
|
||||
|
||||
// Make another request just to confirm that that connection can be reused...
|
||||
executeSynchronously(new Request.Builder().url(server.getUrl("/")).build()).assertBody("def");
|
||||
assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection.
|
||||
assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reused.
|
||||
|
||||
// ... even before we close the response body!
|
||||
response.body().close();
|
||||
}
|
||||
|
||||
private RecordedResponse executeSynchronously(Request request) throws IOException {
|
||||
Response response = client.newCall(request).execute();
|
||||
return new RecordedResponse(request, response, response.body().string(), null);
|
||||
|
||||
@@ -146,13 +146,13 @@ public final class Call {
|
||||
responseCallback.onFailure(request, new IOException("Canceled"));
|
||||
} else {
|
||||
signalledCallback = true;
|
||||
engine.releaseConnection();
|
||||
responseCallback.onResponse(response);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (signalledCallback) throw new RuntimeException(e); // Do not signal the callback twice!
|
||||
responseCallback.onFailure(request, e);
|
||||
} finally {
|
||||
engine.close(); // Close the connection if it isn't already.
|
||||
dispatcher.finished(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ public interface Callback {
|
||||
/**
|
||||
* Called when the HTTP response was successfully returned by the remote
|
||||
* server. The callback may proceed to read the response body with {@link
|
||||
* Response#body}.
|
||||
* Response#body}. The response is still live until its response body is
|
||||
* closed with {@code response.body().close()}. The recipient of the callback
|
||||
* may even consume the response body on another thread.
|
||||
*
|
||||
* <p>Note that transport-layer success (receiving a HTTP response code,
|
||||
* headers and body) does not necessarily indicate application-layer
|
||||
|
||||
Reference in New Issue
Block a user