From 447139588925ab6d8ec16196fd9010af45c0c9f1 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sat, 14 Sep 2019 13:45:38 -0400 Subject: [PATCH] Cancel calls on unexpected exceptions (3.14.x branch) Closes: https://github.com/square/okhttp/issues/5151 --- .../src/test/java/okhttp3/InterceptorTest.java | 15 +++++++++++---- okhttp/src/main/java/okhttp3/RealCall.java | 8 ++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/okhttp-tests/src/test/java/okhttp3/InterceptorTest.java b/okhttp-tests/src/test/java/okhttp3/InterceptorTest.java index 92b580959..28d048a5e 100644 --- a/okhttp-tests/src/test/java/okhttp3/InterceptorTest.java +++ b/okhttp-tests/src/test/java/okhttp3/InterceptorTest.java @@ -517,11 +517,12 @@ public final class InterceptorTest { } /** - * When an interceptor throws an unexpected exception, asynchronous callers are left hanging. The + * When an interceptor throws an unexpected exception, asynchronous calls are canceled. The * exception goes to the uncaught exception handler. */ private void interceptorThrowsRuntimeExceptionAsynchronous(boolean network) throws Exception { - addInterceptor(network, chain -> { throw new RuntimeException("boom!"); }); + RuntimeException boom = new RuntimeException("boom!"); + addInterceptor(network, chain -> { throw boom; }); ExceptionCatchingExecutor executor = new ExceptionCatchingExecutor(); client = client.newBuilder() @@ -531,9 +532,15 @@ public final class InterceptorTest { Request request = new Request.Builder() .url(server.url("/")) .build(); - client.newCall(request).enqueue(callback); + Call call = client.newCall(request); + call.enqueue(callback); + RecordedResponse recordedResponse = callback.await(server.url("/")); + assertThat(recordedResponse.failure) + .hasMessage("canceled due to java.lang.RuntimeException: boom!"); + assertThat(recordedResponse.failure).hasSuppressedException(boom); + assertThat(call.isCanceled()).isTrue(); - assertThat(executor.takeException().getMessage()).isEqualTo("boom!"); + assertThat(executor.takeException()).isEqualTo(boom); } @Test public void applicationInterceptorReturnsNull() throws Exception { diff --git a/okhttp/src/main/java/okhttp3/RealCall.java b/okhttp/src/main/java/okhttp3/RealCall.java index bb108764d..b0436fa92 100644 --- a/okhttp/src/main/java/okhttp3/RealCall.java +++ b/okhttp/src/main/java/okhttp3/RealCall.java @@ -179,6 +179,14 @@ final class RealCall implements Call { } else { responseCallback.onFailure(RealCall.this, e); } + } catch (Throwable t) { + cancel(); + if (!signalledCallback) { + IOException canceledException = new IOException("canceled due to " + t); + canceledException.addSuppressed(t); + responseCallback.onFailure(RealCall.this, canceledException); + } + throw t; } finally { client.dispatcher().finished(this); }