src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java
changeset 50681 4254bed3c09d
parent 49765 ee6f7a61f3a5
child 51364 31d9e82b2e64
child 56795 03ece2518428
--- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java	Wed Jun 20 17:15:16 2018 +0200
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java	Wed Jun 20 09:05:57 2018 -0700
@@ -26,7 +26,7 @@
 package jdk.internal.net.http;
 
 import java.io.IOException;
-import java.lang.System.Logger.Level;
+import java.net.ConnectException;
 import java.time.Duration;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -69,7 +69,7 @@
     final AccessControlContext acc;
     final HttpClientImpl client;
     final HttpResponse.BodyHandler<T> responseHandler;
-    final Executor executor;
+    final HttpClientImpl.DelegatingExecutor executor;
     final AtomicInteger attempts = new AtomicInteger();
     HttpRequestImpl currentreq; // used for retries & redirect
     HttpRequestImpl previousreq; // used for retries & redirect
@@ -124,8 +124,8 @@
 
         if (pushPromiseHandler != null) {
             Executor executor = acc == null
-                    ? this.executor
-                    : new PrivilegedExecutor(this.executor, acc);
+                    ? this.executor.delegate()
+                    : new PrivilegedExecutor(this.executor.delegate(), acc);
             this.pushGroup = new PushGroup<>(pushPromiseHandler, request, executor);
         } else {
             pushGroup = null;
@@ -193,7 +193,7 @@
         getExchange().cancel(cause);
     }
 
-    public CompletableFuture<HttpResponse<T>> responseAsync() {
+    public CompletableFuture<HttpResponse<T>> responseAsync(Executor executor) {
         CompletableFuture<Void> start = new MinimalFuture<>();
         CompletableFuture<HttpResponse<T>> cf = responseAsync0(start);
         start.completeAsync( () -> null, executor); // trigger execution
@@ -285,13 +285,22 @@
 
     private static boolean retryPostValue() {
         String s = Utils.getNetProperty("jdk.httpclient.enableAllMethodRetry");
-        if (s == "" || "true".equals(s))
-            return true;
-        return false;
+        if (s == null)
+            return false;
+        return s.isEmpty() ? true : Boolean.parseBoolean(s);
+    }
+
+    private static boolean retryConnect() {
+        String s = Utils.getNetProperty("jdk.httpclient.disableRetryConnect");
+        if (s == null)
+            return false;
+        return s.isEmpty() ? true : Boolean.parseBoolean(s);
     }
 
     /** True if ALL ( even non-idempotent ) requests can be automatic retried. */
     private static final boolean RETRY_ALWAYS = retryPostValue();
+    /** True if ConnectException should cause a retry. Enabled by default */
+    private static final boolean RETRY_CONNECT = retryConnect();
 
     /** Returns true is given request has an idempotent method. */
     private static boolean isIdempotentRequest(HttpRequest request) {
@@ -307,13 +316,23 @@
 
     /** Returns true if the given request can be automatically retried. */
     private static boolean canRetryRequest(HttpRequest request) {
+        if (RETRY_ALWAYS)
+            return true;
         if (isIdempotentRequest(request))
             return true;
-        if (RETRY_ALWAYS)
-            return true;
         return false;
     }
 
+    private boolean retryOnFailure(Throwable t) {
+        return t instanceof ConnectionExpiredException
+                || (RETRY_CONNECT && (t instanceof ConnectException));
+    }
+
+    private Throwable retryCause(Throwable t) {
+        Throwable cause = t instanceof ConnectionExpiredException ? t.getCause() : t;
+        return cause == null ? t : cause;
+    }
+
     /**
      * Takes a Throwable and returns a suitable CompletableFuture that is
      * completed exceptionally, or null.
@@ -326,21 +345,20 @@
         }
         if (cancelled && t instanceof IOException) {
             t = new HttpTimeoutException("request timed out");
-        } else if (t instanceof ConnectionExpiredException) {
-            Throwable cause = t;
-            if (t.getCause() != null) {
-                cause = t.getCause(); // unwrap the ConnectionExpiredException
-            }
+        } else if (retryOnFailure(t)) {
+            Throwable cause = retryCause(t);
 
-            if (!canRetryRequest(currentreq)) {
-                return failedFuture(cause); // fails with original cause
+            if (!(t instanceof ConnectException)) {
+                if (!canRetryRequest(currentreq)) {
+                    return failedFuture(cause); // fails with original cause
+                }
             }
 
             // allow the retry mechanism to do its work
             retryCause = cause;
             if (!expiredOnce) {
                 if (debug.on())
-                    debug.log("ConnectionExpiredException (async): retrying...", t);
+                    debug.log(t.getClass().getSimpleName() + " (async): retrying...", t);
                 expiredOnce = true;
                 // The connection was abruptly closed.
                 // We return null to retry the same request a second time.
@@ -350,9 +368,11 @@
                 previousreq = currentreq;
                 return null;
             } else {
-                if (debug.on())
-                    debug.log("ConnectionExpiredException (async): already retried once.", t);
-                if (t.getCause() != null) t = t.getCause();
+                if (debug.on()) {
+                    debug.log(t.getClass().getSimpleName()
+                            + " (async): already retried once.", t);
+                }
+                t = cause;
             }
         }
         return failedFuture(t);
@@ -364,9 +384,10 @@
         }
         @Override
         public void handle() {
-            if (debug.on())
+            if (debug.on()) {
                 debug.log("Cancelling MultiExchange due to timeout for request %s",
-                          request);
+                        request);
+            }
             cancel(new HttpTimeoutException("request timed out"));
         }
     }