diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 2304f6627..5a1f153d2 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,6 +1,10 @@ Changes since 4.0 beta 2 ------------------- +* NonRepeatableRequestExceptions now include the cause that the original + request failed. + Contributed by Sam Berlin + * [HTTPCLIENT-837] Fixed problem with the wire log skipping zero byte values if read one byte at a time. Contributed by Kirill Safonov diff --git a/httpclient/src/main/java/org/apache/http/client/NonRepeatableRequestException.java b/httpclient/src/main/java/org/apache/http/client/NonRepeatableRequestException.java index a840315d6..b64aeecc4 100644 --- a/httpclient/src/main/java/org/apache/http/client/NonRepeatableRequestException.java +++ b/httpclient/src/main/java/org/apache/http/client/NonRepeatableRequestException.java @@ -62,4 +62,16 @@ public class NonRepeatableRequestException extends ProtocolException { super(message); } + /** + * Creates a new NonRepeatableEntityException with the specified detail message. + * + * @param message The exception detail message + * @param cause the cause + */ + public NonRepeatableRequestException(String message, Throwable cause) { + super(message, cause); + } + + + } diff --git a/httpclient/src/main/java/org/apache/http/impl/client/DefaultRequestDirector.java b/httpclient/src/main/java/org/apache/http/impl/client/DefaultRequestDirector.java index e29669dc7..3e25eb325 100644 --- a/httpclient/src/main/java/org/apache/http/impl/client/DefaultRequestDirector.java +++ b/httpclient/src/main/java/org/apache/http/impl/client/DefaultRequestDirector.java @@ -392,14 +392,21 @@ public class DefaultRequestDirector implements RequestDirector { requestExec.preProcess(wrapper, httpProcessor, context); boolean retrying = true; + Exception retryReason = null; while (retrying) { // Increment total exec count (with redirects) execCount++; // Increment exec count for this particular request wrapper.incrementExecCount(); if (wrapper.getExecCount() > 1 && !wrapper.isRepeatable()) { - throw new NonRepeatableRequestException("Cannot retry request " + - "with a non-repeatable request entity"); + if(retryReason != null) { + throw new NonRepeatableRequestException("Cannot retry request " + + "with a non-repeatable request entity. The cause lists the " + + "reason the original request failed.", retryReason); + } else { + throw new NonRepeatableRequestException("Cannot retry request " + + "with a non-repeatable request entity."); + } } try { @@ -422,6 +429,7 @@ public class DefaultRequestDirector implements RequestDirector { this.log.debug(ex.getMessage(), ex); } this.log.info("Retrying request"); + retryReason = ex; } else { throw ex; } diff --git a/httpclient/src/test/java/org/apache/http/impl/client/TestDefaultClientRequestDirector.java b/httpclient/src/test/java/org/apache/http/impl/client/TestDefaultClientRequestDirector.java index 22b105d41..c49e92a52 100644 --- a/httpclient/src/test/java/org/apache/http/impl/client/TestDefaultClientRequestDirector.java +++ b/httpclient/src/test/java/org/apache/http/impl/client/TestDefaultClientRequestDirector.java @@ -638,9 +638,15 @@ public class TestDefaultClientRequestDirector extends ServerTestBase { } private static class FaultyHttpRequestExecutor extends HttpRequestExecutor { - + private static final String MARKER = "marker"; + private final String failureMsg; + + public FaultyHttpRequestExecutor(String failureMsg) { + this.failureMsg = failureMsg; + } + @Override public HttpResponse execute( final HttpRequest request, @@ -650,7 +656,7 @@ public class TestDefaultClientRequestDirector extends ServerTestBase { Object marker = context.getAttribute(MARKER); if (marker == null) { context.setAttribute(MARKER, Boolean.TRUE); - throw new IOException("Oppsie"); + throw new IOException(failureMsg); } return super.execute(request, conn, context); } @@ -658,10 +664,20 @@ public class TestDefaultClientRequestDirector extends ServerTestBase { } private static class FaultyHttpClient extends DefaultHttpClient { + + private final String failureMsg; + + public FaultyHttpClient() { + this("Oppsie"); + } + + public FaultyHttpClient(String failureMsg) { + this.failureMsg = failureMsg; + } @Override protected HttpRequestExecutor createRequestExecutor() { - return new FaultyHttpRequestExecutor(); + return new FaultyHttpRequestExecutor(failureMsg); } } @@ -716,11 +732,13 @@ public class TestDefaultClientRequestDirector extends ServerTestBase { assertEquals(1, myheaders.length); } - public void testNonRepatableEntity() throws Exception { + public void testNonRepeatableEntity() throws Exception { int port = this.localServer.getServicePort(); this.localServer.register("*", new SimpleService()); - FaultyHttpClient client = new FaultyHttpClient(); + String failureMsg = "a message showing that this failed"; + + FaultyHttpClient client = new FaultyHttpClient(failureMsg); HttpContext context = new BasicHttpContext(); String s = "http://localhost:" + port; @@ -735,7 +753,9 @@ public class TestDefaultClientRequestDirector extends ServerTestBase { fail("ClientProtocolException should have been thrown"); } catch (ClientProtocolException ex) { assertTrue(ex.getCause() instanceof NonRepeatableRequestException); - // expected + NonRepeatableRequestException nonRepeat = (NonRepeatableRequestException)ex.getCause(); + assertTrue(nonRepeat.getCause() instanceof IOException); + assertEquals(failureMsg, nonRepeat.getCause().getMessage()); } }