diff --git a/okhttp-tests/src/test/java/okhttp3/CallTest.java b/okhttp-tests/src/test/java/okhttp3/CallTest.java index a87ecc7b5..44a0a987e 100644 --- a/okhttp-tests/src/test/java/okhttp3/CallTest.java +++ b/okhttp-tests/src/test/java/okhttp3/CallTest.java @@ -619,6 +619,42 @@ public final class CallTest { assertEquals("SyncApiTest", server.takeRequest().getHeader("User-Agent")); } + @Test public void legalToExecuteTwiceCloning() throws Exception { + server.enqueue(new MockResponse().setBody("abc")); + server.enqueue(new MockResponse().setBody("def")); + + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + + Call call = client.newCall(request); + Response response1 = call.execute(); + + Call cloned = call.clone(); + Response response2 = cloned.execute(); + + assertEquals(response1.body().string(), "abc"); + assertEquals(response2.body().string(), "def"); + } + + @Test public void legalToExecuteTwiceCloning_Async() throws Exception { + server.enqueue(new MockResponse().setBody("abc")); + server.enqueue(new MockResponse().setBody("def")); + + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + + Call call = client.newCall(request); + call.enqueue(callback); + + Call cloned = call.clone(); + cloned.enqueue(callback); + + callback.await(request.url()).assertBody("abc"); + callback.await(request.url()).assertBody("def"); + } + @Test public void get_Async() throws Exception { server.enqueue(new MockResponse() .setBody("abc") diff --git a/okhttp/src/main/java/okhttp3/Call.java b/okhttp/src/main/java/okhttp3/Call.java index 02b8976e6..fccf857c1 100644 --- a/okhttp/src/main/java/okhttp3/Call.java +++ b/okhttp/src/main/java/okhttp3/Call.java @@ -21,7 +21,7 @@ import java.io.IOException; * A call is a request that has been prepared for execution. A call can be canceled. As this object * represents a single request/response pair (stream), it cannot be executed twice. */ -public interface Call { +public interface Call extends Cloneable { /** Returns the original request that initiated this call. */ Request request(); @@ -67,6 +67,12 @@ public interface Call { boolean isCanceled(); + /** + * Create a new, identical call to this one which can be enqueued or executed even if this call + * has already been. + */ + Call clone(); + interface Factory { Call newCall(Request request); } diff --git a/okhttp/src/main/java/okhttp3/RealCall.java b/okhttp/src/main/java/okhttp3/RealCall.java index 4aa45ef44..11b6f1774 100644 --- a/okhttp/src/main/java/okhttp3/RealCall.java +++ b/okhttp/src/main/java/okhttp3/RealCall.java @@ -90,6 +90,11 @@ final class RealCall implements Call { return retryAndFollowUpInterceptor.isCanceled(); } + @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state. + @Override public RealCall clone() { + return new RealCall(client, originalRequest); + } + StreamAllocation streamAllocation() { return retryAndFollowUpInterceptor.streamAllocation(); }