1
0
mirror of https://github.com/square/okhttp.git synced 2025-11-29 06:23:09 +03:00

Keep the response body alive after the callback.

This commit is contained in:
Jesse Wilson
2014-06-10 19:31:46 -04:00
parent ac6ac338a3
commit aa7e7a751c
3 changed files with 44 additions and 2 deletions

View File

@@ -34,11 +34,13 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@@ -1285,6 +1287,44 @@ public final class CallTest {
.assertRequestHeader("Accept-Encoding", "gzip"); .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 { private RecordedResponse executeSynchronously(Request request) throws IOException {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
return new RecordedResponse(request, response, response.body().string(), null); return new RecordedResponse(request, response, response.body().string(), null);

View File

@@ -146,13 +146,13 @@ public final class Call {
responseCallback.onFailure(request, new IOException("Canceled")); responseCallback.onFailure(request, new IOException("Canceled"));
} else { } else {
signalledCallback = true; signalledCallback = true;
engine.releaseConnection();
responseCallback.onResponse(response); responseCallback.onResponse(response);
} }
} catch (IOException e) { } catch (IOException e) {
if (signalledCallback) throw new RuntimeException(e); // Do not signal the callback twice! if (signalledCallback) throw new RuntimeException(e); // Do not signal the callback twice!
responseCallback.onFailure(request, e); responseCallback.onFailure(request, e);
} finally { } finally {
engine.close(); // Close the connection if it isn't already.
dispatcher.finished(this); dispatcher.finished(this);
} }
} }

View File

@@ -29,7 +29,9 @@ public interface Callback {
/** /**
* Called when the HTTP response was successfully returned by the remote * Called when the HTTP response was successfully returned by the remote
* server. The callback may proceed to read the response body with {@link * 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, * <p>Note that transport-layer success (receiving a HTTP response code,
* headers and body) does not necessarily indicate application-layer * headers and body) does not necessarily indicate application-layer