You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2017/05/01 11:11:11 UTC

svn commit: r1793308 [8/11] - in /httpcomponents/httpclient/trunk: httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/ httpclient5-cache/src/test/java/org/apache/...

Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ChainElements.java (from r1793305, httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsStore.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ChainElements.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ChainElements.java&p1=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsStore.java&r1=1793305&r2=1793308&rev=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsStore.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ChainElements.java Mon May  1 11:11:09 2017
@@ -24,34 +24,11 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.client5.http.auth;
 
-/**
- * Abstract store of authentication credentials.
- * <p>
- * Implementations of this interface must be thread-safe. Access to shared
- * data must be synchronized as methods of this interface may be executed
- * from multiple threads.
- *
- * @since 4.0
- */
-public interface CredentialsStore extends CredentialsProvider {
+package org.apache.hc.client5.http.impl.sync;
 
-    /**
-     * Sets the {@link Credentials credentials} for the given authentication
-     * scope. Any previous credentials for the given scope will be overwritten.
-     *
-     * @param authscope the {@link AuthScope authentication scope}
-     * @param credentials the authentication {@link Credentials credentials}
-     * for the given scope.
-     *
-     * @see #getCredentials(AuthScope, HttpContext)
-     */
-    void setCredentials(AuthScope authscope, Credentials credentials);
+public enum ChainElements {
 
-    /**
-     * Clears all credentials.
-     */
-    void clear();
+    REDIRECT, BACK_OFF, RETRY_SERVICE_UNAVAILABLE, RETRY_IO_ERROR, PROTOCOL, MAIN_TRANSPORT
 
-}
+}
\ No newline at end of file

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/CloseableHttpResponse.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/CloseableHttpResponse.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/CloseableHttpResponse.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/CloseableHttpResponse.java Mon May  1 11:11:09 2017
@@ -27,11 +27,11 @@
 
 package org.apache.hc.client5.http.impl.sync;
 
-import java.io.Closeable;
 import java.io.IOException;
 import java.util.Iterator;
 import java.util.Locale;
 
+import org.apache.hc.client5.http.sync.ExecRuntime;
 import org.apache.hc.core5.http.ClassicHttpResponse;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpEntity;
@@ -47,9 +47,9 @@ import org.apache.hc.core5.util.Args;
 public final class CloseableHttpResponse implements ClassicHttpResponse {
 
     private final ClassicHttpResponse response;
-    private final Closeable closeable;
+    private final ExecRuntime execRuntime;
 
-    public static CloseableHttpResponse adapt(final ClassicHttpResponse response) {
+    static CloseableHttpResponse adapt(final ClassicHttpResponse response) {
         if (response == null) {
             return null;
         }
@@ -60,9 +60,9 @@ public final class CloseableHttpResponse
         }
     }
 
-    public CloseableHttpResponse(final ClassicHttpResponse response, final Closeable closeable) {
+    CloseableHttpResponse(final ClassicHttpResponse response, final ExecRuntime execRuntime) {
         this.response = Args.notNull(response, "Response");
-        this.closeable = closeable;
+        this.execRuntime = execRuntime;
     }
 
     @Override
@@ -197,12 +197,15 @@ public final class CloseableHttpResponse
 
     @Override
     public void close() throws IOException {
-        try {
-            response.close();
-        } finally {
-            if (closeable != null) {
-                closeable.close();
+        if (execRuntime != null) {
+            try {
+                response.close();
+                execRuntime.disconnect();
+            } finally {
+                execRuntime.discardConnection();
             }
+        } else {
+            response.close();
         }
     }
 

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/DefaultHttpRequestRetryHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/DefaultHttpRequestRetryHandler.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/DefaultHttpRequestRetryHandler.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/DefaultHttpRequestRetryHandler.java Mon May  1 11:11:09 2017
@@ -42,7 +42,7 @@ import java.util.concurrent.ConcurrentHa
 import javax.net.ssl.SSLException;
 
 import org.apache.hc.client5.http.sync.HttpRequestRetryHandler;
-import org.apache.hc.client5.http.sync.methods.HttpUriRequest;
+import org.apache.hc.client5.http.sync.methods.HttpUriRequestBase;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.HttpRequest;
@@ -153,7 +153,7 @@ public class DefaultHttpRequestRetryHand
                 }
             }
         }
-        if (request instanceof HttpUriRequest && ((HttpUriRequest)request).isAborted()) {
+        if (request instanceof HttpUriRequestBase && ((HttpUriRequestBase)request).isAborted()) {
             return false;
         }
         if (handleAsIdempotent(request)) {

Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecChainElement.java (from r1793305, httpcomponents/httpclient/trunk/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/DummyBackend.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecChainElement.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecChainElement.java&p1=httpcomponents/httpclient/trunk/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/DummyBackend.java&r1=1793305&r2=1793308&rev=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/DummyBackend.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecChainElement.java Mon May  1 11:11:09 2017
@@ -24,46 +24,47 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.client5.http.impl.cache;
+
+package org.apache.hc.client5.http.impl.sync;
 
 import java.io.IOException;
 
-import org.apache.hc.client5.http.impl.sync.ClientExecChain;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.client5.http.sync.methods.HttpExecutionAware;
-import org.apache.hc.client5.http.impl.sync.RoutedHttpRequest;
+import org.apache.hc.client5.http.sync.ExecChain;
+import org.apache.hc.client5.http.sync.ExecChainHandler;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ClassicHttpResponse;
 import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpRequest;
-import org.apache.hc.core5.http.HttpStatus;
-import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
-
-public class DummyBackend implements ClientExecChain {
-
-    private ClassicHttpRequest request;
-    private ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_OK, "OK");
-    private int executions = 0;
 
-    public void setResponse(final ClassicHttpResponse resp) {
-        response = resp;
-    }
+class ExecChainElement {
+
+    private final ExecChainHandler handler;
+    private final ExecChainElement next;
 
-    public HttpRequest getCapturedRequest() {
-        return request;
+    ExecChainElement(final ExecChainHandler handler, final ExecChainElement next) {
+        this.handler = handler;
+        this.next = next;
     }
 
-    @Override
     public ClassicHttpResponse execute(
-            final RoutedHttpRequest request,
-            final HttpClientContext clientContext,
-            final HttpExecutionAware execAware) throws IOException, HttpException {
-        this.request = request;
-        executions++;
-        return response;
+            final ClassicHttpRequest request,
+            final ExecChain.Scope scope) throws IOException, HttpException {
+        return handler.execute(request, scope, new ExecChain() {
+
+            @Override
+            public ClassicHttpResponse proceed(
+                    final ClassicHttpRequest request,
+                    final Scope scope) throws IOException, HttpException {
+                return next.execute(request, scope);
+            }
+
+        });
     }
 
-    public int getExecutions() {
-        return executions;
+    @Override
+    public String toString() {
+        return "{" +
+                "handler=" + handler.getClass() +
+                ", next=" + (next != null ? next.handler.getClass() : "null") +
+                '}';
     }
-}
+}
\ No newline at end of file

Added: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecRuntimeImpl.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecRuntimeImpl.java?rev=1793308&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecRuntimeImpl.java (added)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecRuntimeImpl.java Mon May  1 11:11:09 2017
@@ -0,0 +1,250 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.client5.http.impl.sync;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.hc.client5.http.CancellableAware;
+import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.io.ConnectionEndpoint;
+import org.apache.hc.client5.http.io.HttpClientConnectionManager;
+import org.apache.hc.client5.http.io.LeaseRequest;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.sync.ExecRuntime;
+import org.apache.hc.core5.concurrent.Cancellable;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
+import org.apache.hc.core5.io.ShutdownType;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.logging.log4j.Logger;
+
+class ExecRuntimeImpl implements ExecRuntime, Cancellable {
+
+    private final Logger log;
+
+    private final HttpClientConnectionManager manager;
+    private final HttpRequestExecutor requestExecutor;
+    private final CancellableAware cancellableAware;
+    private final AtomicReference<ConnectionEndpoint> endpointRef;
+
+    private volatile boolean reusable;
+    private volatile Object state;
+    private volatile TimeValue validDuration;
+
+    ExecRuntimeImpl(
+            final Logger log,
+            final HttpClientConnectionManager manager,
+            final HttpRequestExecutor requestExecutor,
+            final CancellableAware cancellableAware) {
+        super();
+        this.log = log;
+        this.manager = manager;
+        this.requestExecutor = requestExecutor;
+        this.cancellableAware = cancellableAware;
+        this.endpointRef = new AtomicReference<>(null);
+        this.validDuration = TimeValue.NEG_ONE_MILLISECONDS;
+    }
+
+    @Override
+    public boolean isExecutionAborted() {
+        return cancellableAware != null && cancellableAware.isCancelled();
+    }
+
+    @Override
+    public boolean isConnectionAcquired() {
+        return endpointRef.get() != null;
+    }
+
+    @Override
+    public void acquireConnection(final HttpRoute route, final Object object, final HttpClientContext context) throws IOException {
+        if (endpointRef.get() == null) {
+            final LeaseRequest connRequest = manager.lease(route, object);
+            state = object;
+            if (cancellableAware != null) {
+                if (cancellableAware.isCancelled()) {
+                    connRequest.cancel();
+                    throw new RequestFailedException("Request aborted");
+                }
+                cancellableAware.setCancellable(connRequest);
+            }
+            try {
+                final RequestConfig requestConfig = context.getRequestConfig();
+                final TimeValue timeout = requestConfig.getConnectionRequestTimeout();
+                final ConnectionEndpoint connectionEndpoint = connRequest.get(timeout.getDuration(), timeout.getTimeUnit());
+                endpointRef.set(connectionEndpoint);
+                if (!connectionEndpoint.isConnected()) {
+                    reusable = false;
+                }
+                if (cancellableAware != null) {
+                    cancellableAware.setCancellable(this);
+                }
+            } catch(final TimeoutException ex) {
+                throw new ConnectionRequestTimeoutException(ex.getMessage());
+            } catch(final InterruptedException interrupted) {
+                Thread.currentThread().interrupt();
+                throw new RequestFailedException("Request aborted", interrupted);
+            } catch(final ExecutionException ex) {
+                Throwable cause = ex.getCause();
+                if (cause == null) {
+                    cause = ex;
+                }
+                throw new RequestFailedException("Request execution failed", cause);
+            }
+        } else {
+            throw new IllegalStateException("Endpoint already acquired");
+        }
+    }
+
+    ConnectionEndpoint ensureValid() {
+        final ConnectionEndpoint endpoint = endpointRef.get();
+        if (endpoint == null) {
+            throw new IllegalStateException("Endpoint not acquired / already released");
+        }
+        return endpoint;
+    }
+
+    @Override
+    public boolean isConnected() {
+        final ConnectionEndpoint endpoint = endpointRef.get();
+        return endpoint != null && endpoint.isConnected();
+    }
+
+    @Override
+    public void connect(final HttpClientContext context) throws IOException {
+        final ConnectionEndpoint endpoint = ensureValid();
+        if (!endpoint.isConnected()) {
+            if (cancellableAware != null) {
+                if (cancellableAware.isCancelled()) {
+                    throw new RequestFailedException("Request aborted");
+                }
+            }
+            final RequestConfig requestConfig = context.getRequestConfig();
+            final TimeValue connectTimeout = requestConfig.getConnectTimeout();
+            manager.connect(endpoint, connectTimeout, context);
+            final TimeValue socketTimeout = requestConfig.getSocketTimeout();
+            if (socketTimeout.getDuration() >= 0) {
+                endpoint.setSocketTimeout(socketTimeout.toMillisIntBound());
+            }
+        }
+    }
+
+    @Override
+    public void disconnect() throws IOException {
+        final ConnectionEndpoint endpoint = endpointRef.get();
+        if (endpoint != null) {
+            endpoint.close();
+        }
+    }
+
+    @Override
+    public void upgradeTls(final HttpClientContext context) throws IOException {
+        final ConnectionEndpoint endpoint = ensureValid();
+        manager.upgrade(endpoint, context);
+    }
+
+    @Override
+    public ClassicHttpResponse execute(final ClassicHttpRequest request, final HttpClientContext context) throws IOException, HttpException {
+        final ConnectionEndpoint endpoint = ensureValid();
+        return endpoint.execute(request, requestExecutor, context);
+    }
+
+    @Override
+    public boolean isConnectionReusable() {
+        return reusable;
+    }
+
+    @Override
+    public void markConnectionReusable() {
+        reusable = true;
+    }
+
+    @Override
+    public void markConnectionNonReusable() {
+        reusable = false;
+    }
+
+    @Override
+    public void setConnectionState(final Object state) {
+        this.state = state;
+    }
+
+    @Override
+    public void setConnectionValidFor(final TimeValue duration) {
+        validDuration = duration;
+    }
+
+    @Override
+    public void releaseConnection() {
+        final ConnectionEndpoint endpoint = endpointRef.getAndSet(null);
+        if (endpoint != null) {
+            if (reusable) {
+                manager.release(endpoint, state, validDuration);
+            } else {
+                try {
+                    endpoint.close();
+                    log.debug("Connection discarded");
+                } catch (final IOException ex) {
+                    if (log.isDebugEnabled()) {
+                        log.debug(ex.getMessage(), ex);
+                    }
+                } finally {
+                    manager.release(endpoint, null, TimeValue.ZERO_MILLISECONDS);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void discardConnection() {
+        final ConnectionEndpoint endpoint = endpointRef.getAndSet(null);
+        if (endpoint != null) {
+            try {
+                endpoint.shutdown(ShutdownType.IMMEDIATE);
+                log.debug("Connection discarded");
+            } finally {
+                manager.release(endpoint, null, TimeValue.ZERO_MILLISECONDS);
+            }
+        }
+    }
+
+    @Override
+    public boolean cancel() {
+        final boolean alreadyReleased = endpointRef.get() == null;
+        log.debug("Cancelling request execution");
+        discardConnection();
+        return !alreadyReleased;
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecRuntimeImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecRuntimeImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/ExecRuntimeImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/FutureRequestExecutionService.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/FutureRequestExecutionService.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/FutureRequestExecutionService.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/FutureRequestExecutionService.java Mon May  1 11:11:09 2017
@@ -32,10 +32,10 @@ import java.util.concurrent.ExecutorServ
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.hc.client5.http.sync.HttpClient;
-import org.apache.hc.client5.http.sync.methods.HttpUriRequest;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.io.ResponseHandler;
 import org.apache.hc.core5.http.protocol.HttpContext;
 
@@ -83,7 +83,7 @@ public class FutureRequestExecutionServi
      * @return HttpAsyncClientFutureTask for the scheduled request.
      */
     public <T> HttpRequestFutureTask<T> execute(
-            final HttpUriRequest request,
+            final ClassicHttpRequest request,
             final HttpContext context,
             final ResponseHandler<T> responseHandler) {
         return execute(request, context, responseHandler, null);
@@ -106,7 +106,7 @@ public class FutureRequestExecutionServi
      * @return HttpAsyncClientFutureTask for the scheduled request.
      */
     public <T> HttpRequestFutureTask<T> execute(
-            final HttpUriRequest request,
+            final ClassicHttpRequest request,
             final HttpContext context,
             final ResponseHandler<T> responseHandler,
             final FutureCallback<T> callback) {

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClientBuilder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClientBuilder.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClientBuilder.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClientBuilder.java Mon May  1 11:11:09 2017
@@ -53,6 +53,7 @@ import org.apache.hc.client5.http.impl.D
 import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
 import org.apache.hc.client5.http.impl.DefaultUserTokenHandler;
 import org.apache.hc.client5.http.impl.IdleConnectionEvictor;
+import org.apache.hc.client5.http.impl.NamedElementChain;
 import org.apache.hc.client5.http.impl.NoopUserTokenHandler;
 import org.apache.hc.client5.http.impl.auth.BasicSchemeFactory;
 import org.apache.hc.client5.http.impl.auth.CredSspSchemeFactory;
@@ -82,8 +83,10 @@ import org.apache.hc.client5.http.protoc
 import org.apache.hc.client5.http.routing.HttpRoutePlanner;
 import org.apache.hc.client5.http.sync.BackoffManager;
 import org.apache.hc.client5.http.sync.ConnectionBackoffStrategy;
+import org.apache.hc.client5.http.sync.ExecChainHandler;
 import org.apache.hc.client5.http.sync.HttpRequestRetryHandler;
 import org.apache.hc.client5.http.sync.ServiceUnavailableRetryStrategy;
+import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.http.ConnectionReuseStrategy;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpHost;
@@ -97,12 +100,12 @@ import org.apache.hc.core5.http.impl.Def
 import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
 import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
 import org.apache.hc.core5.http.protocol.HttpContext;
-import org.apache.hc.core5.http.protocol.HttpProcessor;
 import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
 import org.apache.hc.core5.http.protocol.RequestContent;
 import org.apache.hc.core5.http.protocol.RequestTargetHost;
 import org.apache.hc.core5.http.protocol.RequestUserAgent;
 import org.apache.hc.core5.pool.ConnPoolControl;
+import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.VersionInfo;
 
@@ -132,6 +135,54 @@ import org.apache.hc.core5.util.VersionI
  */
 public class HttpClientBuilder {
 
+    private static class RequestInterceptorEntry {
+
+        enum Postion { FIRST, LAST }
+
+        final Postion postion;
+        final HttpRequestInterceptor interceptor;
+
+        private RequestInterceptorEntry(final Postion postion, final HttpRequestInterceptor interceptor) {
+            this.postion = postion;
+            this.interceptor = interceptor;
+        }
+    }
+
+    private static class ResponseInterceptorEntry {
+
+        enum Postion { FIRST, LAST }
+
+        final Postion postion;
+        final HttpResponseInterceptor interceptor;
+
+        private ResponseInterceptorEntry(final Postion postion, final HttpResponseInterceptor interceptor) {
+            this.postion = postion;
+            this.interceptor = interceptor;
+        }
+    }
+
+    private static class ExecInterceptorEntry {
+
+        enum Postion { BEFORE, AFTER, REPLACE }
+
+        final Postion postion;
+        final String name;
+        final ExecChainHandler interceptor;
+        final String existing;
+
+        private ExecInterceptorEntry(
+                final Postion postion,
+                final String name,
+                final ExecChainHandler interceptor,
+                final String existing) {
+            this.postion = postion;
+            this.name = name;
+            this.interceptor = interceptor;
+            this.existing = existing;
+        }
+
+    }
+
     private HttpRequestExecutor requestExec;
     private HttpClientConnectionManager connManager;
     private boolean connManagerShared;
@@ -142,10 +193,9 @@ public class HttpClientBuilder {
     private AuthenticationStrategy proxyAuthStrategy;
     private UserTokenHandler userTokenHandler;
 
-    private LinkedList<HttpRequestInterceptor> requestFirst;
-    private LinkedList<HttpRequestInterceptor> requestLast;
-    private LinkedList<HttpResponseInterceptor> responseFirst;
-    private LinkedList<HttpResponseInterceptor> responseLast;
+    private LinkedList<RequestInterceptorEntry> requestInterceptors;
+    private LinkedList<ResponseInterceptorEntry> responseInterceptors;
+    private LinkedList<ExecInterceptorEntry> execInterceptors;
 
     private HttpRequestRetryHandler retryHandler;
     private HttpRoutePlanner routePlanner;
@@ -307,56 +357,89 @@ public class HttpClientBuilder {
     /**
      * Adds this protocol interceptor to the head of the protocol processing list.
      */
-    public final HttpClientBuilder addInterceptorFirst(final HttpResponseInterceptor itcp) {
-        if (itcp == null) {
-            return this;
-        }
-        if (responseFirst == null) {
-            responseFirst = new LinkedList<>();
+    public final HttpClientBuilder addRequestInterceptorFirst(final HttpResponseInterceptor interceptor) {
+        Args.notNull(interceptor, "Interceptor");
+        if (responseInterceptors == null) {
+            responseInterceptors = new LinkedList<>();
         }
-        responseFirst.addFirst(itcp);
+        responseInterceptors.add(new ResponseInterceptorEntry(ResponseInterceptorEntry.Postion.FIRST, interceptor));
         return this;
     }
 
     /**
      * Adds this protocol interceptor to the tail of the protocol processing list.
      */
-    public final HttpClientBuilder addInterceptorLast(final HttpResponseInterceptor itcp) {
-        if (itcp == null) {
-            return this;
-        }
-        if (responseLast == null) {
-            responseLast = new LinkedList<>();
+    public final HttpClientBuilder addResponseInterceptorLast(final HttpResponseInterceptor interceptor) {
+        Args.notNull(interceptor, "Interceptor");
+        if (responseInterceptors == null) {
+            responseInterceptors = new LinkedList<>();
         }
-        responseLast.addLast(itcp);
+        responseInterceptors.add(new ResponseInterceptorEntry(ResponseInterceptorEntry.Postion.LAST, interceptor));
         return this;
     }
 
     /**
      * Adds this protocol interceptor to the head of the protocol processing list.
      */
-    public final HttpClientBuilder addInterceptorFirst(final HttpRequestInterceptor itcp) {
-        if (itcp == null) {
-            return this;
+    public final HttpClientBuilder addRequestInterceptorFirst(final HttpRequestInterceptor interceptor) {
+        Args.notNull(interceptor, "Interceptor");
+        if (requestInterceptors == null) {
+            requestInterceptors = new LinkedList<>();
         }
-        if (requestFirst == null) {
-            requestFirst = new LinkedList<>();
-        }
-        requestFirst.addFirst(itcp);
+        requestInterceptors.add(new RequestInterceptorEntry(RequestInterceptorEntry.Postion.FIRST, interceptor));
         return this;
     }
 
     /**
      * Adds this protocol interceptor to the tail of the protocol processing list.
      */
-    public final HttpClientBuilder addInterceptorLast(final HttpRequestInterceptor itcp) {
-        if (itcp == null) {
-            return this;
+    public final HttpClientBuilder addResponseInterceptorLast(final HttpRequestInterceptor interceptor) {
+        Args.notNull(interceptor, "Interceptor");
+        if (requestInterceptors == null) {
+            requestInterceptors = new LinkedList<>();
+        }
+        requestInterceptors.add(new RequestInterceptorEntry(RequestInterceptorEntry.Postion.LAST, interceptor));
+        return this;
+    }
+
+    /**
+     * Adds this execution interceptor before an existing interceptor.
+     */
+    public final HttpClientBuilder addExecInterceptorBefore(final String existing, final String name, final ExecChainHandler interceptor) {
+        Args.notBlank(existing, "Existing");
+        Args.notBlank(name, "Name");
+        Args.notNull(interceptor, "Interceptor");
+        if (execInterceptors == null) {
+            execInterceptors = new LinkedList<>();
         }
-        if (requestLast == null) {
-            requestLast = new LinkedList<>();
+        execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.BEFORE, name, interceptor, existing));
+        return this;
+    }
+
+    /**
+     * Adds this execution interceptor after interceptor with the given name.
+     */
+    public final HttpClientBuilder addExecInterceptorAfter(final String existing, final String name, final ExecChainHandler interceptor) {
+        Args.notBlank(existing, "Existing");
+        Args.notBlank(name, "Name");
+        Args.notNull(interceptor, "Interceptor");
+        if (execInterceptors == null) {
+            execInterceptors = new LinkedList<>();
+        }
+        execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.AFTER, name, interceptor, existing));
+        return this;
+    }
+
+    /**
+     * Replace an existing interceptor with the given name with new interceptor.
+     */
+    public final HttpClientBuilder replaceExecInterceptor(final String existing, final ExecChainHandler interceptor) {
+        Args.notBlank(existing, "Existing");
+        Args.notNull(interceptor, "Interceptor");
+        if (execInterceptors == null) {
+            execInterceptors = new LinkedList<>();
         }
-        requestLast.addLast(itcp);
+        execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.REPLACE, existing, interceptor, existing));
         return this;
     }
 
@@ -589,54 +672,20 @@ public class HttpClientBuilder {
     }
 
     /**
-     * Produces an instance of {@link ClientExecChain} to be used as a main exec.
-     * <p>
-     * Default implementation produces an instance of {@link MainClientExec}
-     * </p>
+     * Request exec chain customization and extension.
      * <p>
      * For internal use.
-     * </p>
-     *
-     * @since 4.4
-     */
-    protected ClientExecChain createMainExec(
-            final HttpRequestExecutor requestExec,
-            final HttpClientConnectionManager connManager,
-            final ConnectionReuseStrategy reuseStrategy,
-            final ConnectionKeepAliveStrategy keepAliveStrategy,
-            final HttpProcessor proxyHttpProcessor,
-            final AuthenticationStrategy targetAuthStrategy,
-            final AuthenticationStrategy proxyAuthStrategy,
-            final UserTokenHandler userTokenHandler)
-    {
-        return new MainClientExec(
-                requestExec,
-                connManager,
-                reuseStrategy,
-                keepAliveStrategy,
-                proxyHttpProcessor,
-                targetAuthStrategy,
-                proxyAuthStrategy,
-                userTokenHandler);
-    }
-
-    /**
-     * For internal use.
-     */
-    protected ClientExecChain decorateMainExec(final ClientExecChain mainExec) {
-        return mainExec;
-    }
-
-    /**
-     * For internal use.
      */
-    protected ClientExecChain decorateProtocolExec(final ClientExecChain protocolExec) {
-        return protocolExec;
+    @Internal
+    protected void customizeExecChain(final NamedElementChain<ExecChainHandler> execChainDefinition) {
     }
 
     /**
+     * Adds to the list of {@link Closeable} resources to be managed by the client.
+     * <p>
      * For internal use.
      */
+    @Internal
     protected void addCloseable(final Closeable closeable) {
         if (closeable == null) {
             return;
@@ -709,27 +758,30 @@ public class HttpClientBuilder {
             }
         }
 
-        ClientExecChain execChain = createMainExec(
-                requestExecCopy,
-                connManagerCopy,
-                reuseStrategyCopy,
-                keepAliveStrategyCopy,
-                new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
-                targetAuthStrategyCopy,
-                proxyAuthStrategyCopy,
-                userTokenHandlerCopy);
-
-        execChain = decorateMainExec(execChain);
+        final NamedElementChain<ExecChainHandler> execChainDefinition = new NamedElementChain<>();
+        execChainDefinition.addLast(
+                new MainClientExec(
+                        reuseStrategyCopy,
+                        keepAliveStrategyCopy,
+                        new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
+                        targetAuthStrategyCopy,
+                        proxyAuthStrategyCopy,
+                        userTokenHandlerCopy),
+                ChainElements.MAIN_TRANSPORT.name());
 
         final HttpProcessorBuilder b = HttpProcessorBuilder.create();
-        if (requestFirst != null) {
-            for (final HttpRequestInterceptor i: requestFirst) {
-                b.addFirst(i);
+        if (requestInterceptors != null) {
+            for (final RequestInterceptorEntry entry: requestInterceptors) {
+                if (entry.postion == RequestInterceptorEntry.Postion.FIRST) {
+                    b.addFirst(entry.interceptor);
+                }
             }
         }
-        if (responseFirst != null) {
-            for (final HttpResponseInterceptor i: responseFirst) {
-                b.addFirst(i);
+        if (responseInterceptors != null) {
+            for (final ResponseInterceptorEntry entry: responseInterceptors) {
+                if (entry.postion == ResponseInterceptorEntry.Postion.FIRST) {
+                    b.addFirst(entry.interceptor);
+                }
             }
         }
         b.addAll(
@@ -768,19 +820,23 @@ public class HttpClientBuilder {
                 b.add(new ResponseContentEncoding());
             }
         }
-        if (requestLast != null) {
-            for (final HttpRequestInterceptor i: requestLast) {
-                b.addLast(i);
+        if (requestInterceptors != null) {
+            for (final RequestInterceptorEntry entry: requestInterceptors) {
+                if (entry.postion == RequestInterceptorEntry.Postion.LAST) {
+                    b.addFirst(entry.interceptor);
+                }
             }
         }
-        if (responseLast != null) {
-            for (final HttpResponseInterceptor i: responseLast) {
-                b.addLast(i);
+        if (responseInterceptors != null) {
+            for (final ResponseInterceptorEntry entry: responseInterceptors) {
+                if (entry.postion == ResponseInterceptorEntry.Postion.LAST) {
+                    b.addFirst(entry.interceptor);
+                }
             }
         }
-        execChain = new ProtocolExec(execChain, b.build());
-
-        execChain = decorateProtocolExec(execChain);
+        execChainDefinition.addFirst(
+                new ProtocolExec(b.build()),
+                ChainElements.PROTOCOL.name());
 
         // Add request retry executor, if not disabled
         if (!automaticRetriesDisabled) {
@@ -788,7 +844,9 @@ public class HttpClientBuilder {
             if (retryHandlerCopy == null) {
                 retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
             }
-            execChain = new RetryExec(execChain, retryHandlerCopy);
+            execChainDefinition.addFirst(
+                    new RetryExec(retryHandlerCopy),
+                    ChainElements.RETRY_IO_ERROR.name());
         }
 
         HttpRoutePlanner routePlannerCopy = this.routePlanner;
@@ -810,7 +868,9 @@ public class HttpClientBuilder {
         // Optionally, add service unavailable retry executor
         final ServiceUnavailableRetryStrategy serviceUnavailStrategyCopy = this.serviceUnavailStrategy;
         if (serviceUnavailStrategyCopy != null) {
-            execChain = new ServiceUnavailableRetryExec(execChain, serviceUnavailStrategyCopy);
+            execChainDefinition.addFirst(
+                    new ServiceUnavailableRetryExec(serviceUnavailStrategyCopy),
+                    ChainElements.RETRY_SERVICE_UNAVAILABLE.name());
         }
 
         // Add redirect executor, if not disabled
@@ -819,12 +879,40 @@ public class HttpClientBuilder {
             if (redirectStrategyCopy == null) {
                 redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
             }
-            execChain = new RedirectExec(execChain, routePlannerCopy, redirectStrategyCopy);
+            execChainDefinition.addFirst(
+                    new RedirectExec(routePlannerCopy, redirectStrategyCopy),
+                    ChainElements.REDIRECT.name());
         }
 
         // Optionally, add connection back-off executor
         if (this.backoffManager != null && this.connectionBackoffStrategy != null) {
-            execChain = new BackoffStrategyExec(execChain, this.connectionBackoffStrategy, this.backoffManager);
+            execChainDefinition.addFirst(new BackoffStrategyExec(this.connectionBackoffStrategy, this.backoffManager),
+                    ChainElements.BACK_OFF.name());
+        }
+
+        if (execInterceptors != null) {
+            for (final ExecInterceptorEntry entry: execInterceptors) {
+                switch (entry.postion) {
+                    case AFTER:
+                        execChainDefinition.addAfter(entry.existing, entry.interceptor, entry.name);
+                        break;
+                    case BEFORE:
+                        execChainDefinition.addBefore(entry.existing, entry.interceptor, entry.name);
+                        break;
+                    case REPLACE:
+                        execChainDefinition.replace(entry.existing, entry.interceptor);
+                        break;
+                }
+            }
+        }
+
+        customizeExecChain(execChainDefinition);
+
+        NamedElementChain<ExecChainHandler>.Node current = execChainDefinition.getLast();
+        ExecChainElement execChain = null;
+        while (current != null) {
+            execChain = new ExecChainElement(current.getValue(), execChain);
+            current = current.getPrevious();
         }
 
         Lookup<AuthSchemeProvider> authSchemeRegistryCopy = this.authSchemeRegistry;
@@ -886,6 +974,8 @@ public class HttpClientBuilder {
         }
 
         return new InternalHttpClient(
+                connManagerCopy,
+                requestExecCopy,
                 execChain,
                 routePlannerCopy,
                 cookieSpecRegistryCopy,

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClients.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClients.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClients.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpClients.java Mon May  1 11:11:09 2017
@@ -68,7 +68,7 @@ public class HttpClients {
      * Creates {@link CloseableHttpClient} instance that implements
      * the most basic HTTP protocol support.
      */
-    public static CloseableHttpClient createMinimal() {
+    public static MinimalHttpClient createMinimal() {
         return new MinimalHttpClient(new PoolingHttpClientConnectionManager());
     }
 
@@ -76,7 +76,7 @@ public class HttpClients {
      * Creates {@link CloseableHttpClient} instance that implements
      * the most basic HTTP protocol support.
      */
-    public static CloseableHttpClient createMinimal(final HttpClientConnectionManager connManager) {
+    public static MinimalHttpClient createMinimal(final HttpClientConnectionManager connManager) {
         return new MinimalHttpClient(connManager);
     }
 

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpRequestFutureTask.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpRequestFutureTask.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpRequestFutureTask.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpRequestFutureTask.java Mon May  1 11:11:09 2017
@@ -28,7 +28,8 @@ package org.apache.hc.client5.http.impl.
 
 import java.util.concurrent.FutureTask;
 
-import org.apache.hc.client5.http.sync.methods.HttpUriRequest;
+import org.apache.hc.core5.concurrent.Cancellable;
+import org.apache.hc.core5.http.ClassicHttpRequest;
 
 /**
  * FutureTask implementation that wraps a HttpAsyncClientCallable and exposes various task
@@ -38,11 +39,11 @@ import org.apache.hc.client5.http.sync.m
  */
 public class HttpRequestFutureTask<V> extends FutureTask<V> {
 
-    private final HttpUriRequest request;
+    private final ClassicHttpRequest request;
     private final HttpRequestTaskCallable<V> callable;
 
     public HttpRequestFutureTask(
-            final HttpUriRequest request,
+            final ClassicHttpRequest request,
             final HttpRequestTaskCallable<V> httpCallable) {
         super(httpCallable);
         this.request = request;
@@ -56,8 +57,8 @@ public class HttpRequestFutureTask<V> ex
     @Override
     public boolean cancel(final boolean mayInterruptIfRunning) {
         callable.cancel();
-        if (mayInterruptIfRunning) {
-            request.abort();
+        if (mayInterruptIfRunning && request instanceof Cancellable) {
+            ((Cancellable) request).cancel();
         }
         return super.cancel(mayInterruptIfRunning);
     }

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpRequestTaskCallable.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpRequestTaskCallable.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpRequestTaskCallable.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/HttpRequestTaskCallable.java Mon May  1 11:11:09 2017
@@ -30,14 +30,14 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.hc.client5.http.sync.HttpClient;
-import org.apache.hc.client5.http.sync.methods.HttpUriRequest;
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.io.ResponseHandler;
 import org.apache.hc.core5.http.protocol.HttpContext;
 
 class HttpRequestTaskCallable<V> implements Callable<V> {
 
-    private final HttpUriRequest request;
+    private final ClassicHttpRequest request;
     private final HttpClient httpclient;
     private final AtomicBoolean cancelled = new AtomicBoolean(false);
 
@@ -53,7 +53,7 @@ class HttpRequestTaskCallable<V> impleme
 
     HttpRequestTaskCallable(
             final HttpClient httpClient,
-            final HttpUriRequest request,
+            final ClassicHttpRequest request,
             final HttpContext context,
             final ResponseHandler<V> responseHandler,
             final FutureCallback<V> callback,

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/InternalHttpClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/InternalHttpClient.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/InternalHttpClient.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/InternalHttpClient.java Mon May  1 11:11:09 2017
@@ -31,6 +31,7 @@ import java.io.Closeable;
 import java.io.IOException;
 import java.util.List;
 
+import org.apache.hc.client5.http.CancellableAware;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.auth.AuthSchemeProvider;
 import org.apache.hc.client5.http.auth.CredentialsProvider;
@@ -38,10 +39,13 @@ import org.apache.hc.client5.http.config
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.cookie.CookieSpecProvider;
 import org.apache.hc.client5.http.cookie.CookieStore;
+import org.apache.hc.client5.http.impl.ExecSupport;
+import org.apache.hc.client5.http.io.HttpClientConnectionManager;
 import org.apache.hc.client5.http.protocol.ClientProtocolException;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.routing.HttpRoutePlanner;
-import org.apache.hc.client5.http.sync.methods.HttpExecutionAware;
+import org.apache.hc.client5.http.sync.ExecChain;
+import org.apache.hc.client5.http.sync.ExecRuntime;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.ClassicHttpRequest;
@@ -50,6 +54,7 @@ import org.apache.hc.core5.http.HttpExce
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.config.Lookup;
+import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
 import org.apache.hc.core5.http.protocol.BasicHttpContext;
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.net.URIAuthority;
@@ -67,7 +72,9 @@ class InternalHttpClient extends Closeab
 
     private final Logger log = LogManager.getLogger(getClass());
 
-    private final ClientExecChain execChain;
+    private final HttpClientConnectionManager connManager;
+    private final HttpRequestExecutor requestExecutor;
+    private final ExecChainElement execChain;
     private final HttpRoutePlanner routePlanner;
     private final Lookup<CookieSpecProvider> cookieSpecRegistry;
     private final Lookup<AuthSchemeProvider> authSchemeRegistry;
@@ -77,7 +84,9 @@ class InternalHttpClient extends Closeab
     private final List<Closeable> closeables;
 
     public InternalHttpClient(
-            final ClientExecChain execChain,
+            final HttpClientConnectionManager connManager,
+            final HttpRequestExecutor requestExecutor,
+            final ExecChainElement execChain,
             final HttpRoutePlanner routePlanner,
             final Lookup<CookieSpecProvider> cookieSpecRegistry,
             final Lookup<AuthSchemeProvider> authSchemeRegistry,
@@ -86,10 +95,10 @@ class InternalHttpClient extends Closeab
             final RequestConfig defaultConfig,
             final List<Closeable> closeables) {
         super();
-        Args.notNull(execChain, "HTTP client exec chain");
-        Args.notNull(routePlanner, "HTTP route planner");
-        this.execChain = execChain;
-        this.routePlanner = routePlanner;
+        this.connManager = Args.notNull(connManager, "Connection manager");
+        this.requestExecutor = Args.notNull(requestExecutor, "Request executor");
+        this.execChain = Args.notNull(execChain, "Execution chain");
+        this.routePlanner = Args.notNull(routePlanner, "Route planner");
         this.cookieSpecRegistry = cookieSpecRegistry;
         this.authSchemeRegistry = authSchemeRegistry;
         this.cookieStore = cookieStore;
@@ -130,10 +139,6 @@ class InternalHttpClient extends Closeab
             final ClassicHttpRequest request,
             final HttpContext context) throws IOException {
         Args.notNull(request, "HTTP request");
-        HttpExecutionAware execAware = null;
-        if (request instanceof HttpExecutionAware) {
-            execAware = (HttpExecutionAware) request;
-        }
         try {
             if (request.getScheme() == null && target != null) {
                 request.setScheme(target.getSchemeName());
@@ -152,8 +157,10 @@ class InternalHttpClient extends Closeab
             }
             setupContext(localcontext);
             final HttpRoute route = determineRoute(target, request, localcontext);
-            final ClassicHttpResponse response = this.execChain.execute(
-                    RoutedHttpRequest.adapt(request, route), localcontext, execAware);
+            final ExecRuntime execRuntime = new ExecRuntimeImpl(log, connManager, requestExecutor,
+                    request instanceof CancellableAware ? (CancellableAware) request : null);
+            final ExecChain.Scope scope = new ExecChain.Scope(route, request, execRuntime, localcontext);
+            final ClassicHttpResponse response = this.execChain.execute(ExecSupport.copy(request), scope);
             return CloseableHttpResponse.adapt(response);
         } catch (final HttpException httpException) {
             throw new ClientProtocolException(httpException.getMessage(), httpException);

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MainClientExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MainClientExec.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MainClientExec.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MainClientExec.java Mon May  1 11:11:09 2017
@@ -29,8 +29,6 @@ package org.apache.hc.client5.http.impl.
 
 import java.io.IOException;
 import java.io.InterruptedIOException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
 
 import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
 import org.apache.hc.client5.http.HttpRoute;
@@ -41,20 +39,18 @@ import org.apache.hc.client5.http.config
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
 import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
 import org.apache.hc.client5.http.impl.routing.BasicRouteDirector;
-import org.apache.hc.client5.http.io.ConnectionEndpoint;
-import org.apache.hc.client5.http.io.HttpClientConnectionManager;
-import org.apache.hc.client5.http.io.LeaseRequest;
 import org.apache.hc.client5.http.protocol.AuthenticationStrategy;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.protocol.NonRepeatableRequestException;
 import org.apache.hc.client5.http.protocol.UserTokenHandler;
 import org.apache.hc.client5.http.routing.HttpRouteDirector;
-import org.apache.hc.client5.http.sync.methods.HttpExecutionAware;
+import org.apache.hc.client5.http.sync.ExecChain;
+import org.apache.hc.client5.http.sync.ExecChainHandler;
+import org.apache.hc.client5.http.sync.ExecRuntime;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ClassicHttpResponse;
-import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
 import org.apache.hc.core5.http.ConnectionReuseStrategy;
 import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpException;
@@ -64,7 +60,6 @@ import org.apache.hc.core5.http.HttpRequ
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.HttpVersion;
-import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
 import org.apache.hc.core5.http.io.entity.BufferedHttpEntity;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
@@ -73,6 +68,7 @@ import org.apache.hc.core5.http.message.
 import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
 import org.apache.hc.core5.http.protocol.HttpProcessor;
 import org.apache.hc.core5.http.protocol.RequestTargetHost;
+import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.logging.log4j.LogManager;
@@ -89,12 +85,10 @@ import org.apache.logging.log4j.Logger;
  * @since 4.3
  */
 @Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL)
-public class MainClientExec implements ClientExecChain {
+final class MainClientExec implements ExecChainHandler {
 
     private final Logger log = LogManager.getLogger(getClass());
 
-    private final HttpRequestExecutor requestExecutor;
-    private final HttpClientConnectionManager connManager;
     private final ConnectionReuseStrategy reuseStrategy;
     private final ConnectionKeepAliveStrategy keepAliveStrategy;
     private final HttpProcessor proxyHttpProcessor;
@@ -108,16 +102,12 @@ public class MainClientExec implements C
      * @since 4.4
      */
     public MainClientExec(
-            final HttpRequestExecutor requestExecutor,
-            final HttpClientConnectionManager connManager,
             final ConnectionReuseStrategy reuseStrategy,
             final ConnectionKeepAliveStrategy keepAliveStrategy,
             final HttpProcessor proxyHttpProcessor,
             final AuthenticationStrategy targetAuthStrategy,
             final AuthenticationStrategy proxyAuthStrategy,
             final UserTokenHandler userTokenHandler) {
-        Args.notNull(requestExecutor, "HTTP request executor");
-        Args.notNull(connManager, "Client connection manager");
         Args.notNull(reuseStrategy, "Connection reuse strategy");
         Args.notNull(keepAliveStrategy, "Connection keep alive strategy");
         Args.notNull(proxyHttpProcessor, "Proxy HTTP processor");
@@ -126,8 +116,6 @@ public class MainClientExec implements C
         Args.notNull(userTokenHandler, "User token handler");
         this.authenticator      = new HttpAuthenticator();
         this.routeDirector      = new BasicRouteDirector();
-        this.requestExecutor    = requestExecutor;
-        this.connManager        = connManager;
         this.reuseStrategy      = reuseStrategy;
         this.keepAliveStrategy  = keepAliveStrategy;
         this.proxyHttpProcessor = proxyHttpProcessor;
@@ -137,66 +125,34 @@ public class MainClientExec implements C
     }
 
     public MainClientExec(
-            final HttpRequestExecutor requestExecutor,
-            final HttpClientConnectionManager connManager,
             final ConnectionReuseStrategy reuseStrategy,
             final ConnectionKeepAliveStrategy keepAliveStrategy,
             final AuthenticationStrategy targetAuthStrategy,
             final AuthenticationStrategy proxyAuthStrategy,
             final UserTokenHandler userTokenHandler) {
-        this(requestExecutor, connManager, reuseStrategy, keepAliveStrategy,
+        this(reuseStrategy, keepAliveStrategy,
                 new DefaultHttpProcessor(new RequestTargetHost()),
                 targetAuthStrategy, proxyAuthStrategy, userTokenHandler);
     }
 
     @Override
     public ClassicHttpResponse execute(
-            final RoutedHttpRequest request,
-            final HttpClientContext context,
-            final HttpExecutionAware execAware) throws IOException, HttpException {
+            final ClassicHttpRequest request,
+            final ExecChain.Scope scope,
+            final ExecChain chain) throws IOException, HttpException {
         Args.notNull(request, "HTTP request");
-        Args.notNull(context, "HTTP context");
-        final HttpRoute route = request.getRoute();
+        Args.notNull(scope, "Scope");
+        final HttpRoute route = scope.route;
+        final HttpClientContext context = scope.clientContext;
+        final ExecRuntime execRuntime = scope.execRuntime;
 
         RequestEntityProxy.enhance(request);
 
         Object userToken = context.getUserToken();
-
-        final LeaseRequest leaseRequest = connManager.lease(route, userToken);
-        if (execAware != null) {
-            if (execAware.isAborted()) {
-                leaseRequest.cancel();
-                throw new RequestAbortedException("Request aborted");
-            } else {
-                execAware.setCancellable(leaseRequest);
-            }
-        }
-
-        final RequestConfig config = context.getRequestConfig();
-
-        final ConnectionEndpoint endpoint;
-        try {
-            final TimeValue timeout = config.getConnectionRequestTimeout();
-            endpoint = leaseRequest.get(timeout.getDuration(), timeout.getTimeUnit());
-        } catch(final TimeoutException ex) {
-            throw new ConnectionRequestTimeoutException(ex.getMessage());
-        } catch(final InterruptedException interrupted) {
-            Thread.currentThread().interrupt();
-            throw new RequestAbortedException("Request aborted", interrupted);
-        } catch(final ExecutionException ex) {
-            Throwable cause = ex.getCause();
-            if (cause == null) {
-                cause = ex;
-            }
-            throw new RequestAbortedException("Request execution failed", cause);
+        if (!execRuntime.isConnectionAcquired()) {
+            execRuntime.acquireConnection(route, userToken, context);
         }
-
-        final EndpointHolder endpointHolder = new EndpointHolder(this.log, this.connManager, endpoint);
         try {
-            if (execAware != null) {
-                execAware.setCancellable(endpointHolder);
-            }
-
             final AuthExchange targetAuthExchange = context.getAuthExchange(route.getTargetHost());
             final AuthExchange proxyAuthExchange = route.getProxyHost() != null ?
                     context.getAuthExchange(route.getProxyHost()) : new AuthExchange();
@@ -209,16 +165,10 @@ public class MainClientExec implements C
                             "with a non-repeatable request entity.");
                 }
 
-                if (execAware != null && execAware.isAborted()) {
-                    throw new RequestAbortedException("Request aborted");
-                }
-
-                if (!endpoint.isConnected()) {
-                    endpointHolder.markNonReusable();
+                if (!execRuntime.isConnected()) {
                     this.log.debug("Opening connection " + route);
                     try {
-                        establishRoute(endpoint, route, request, context);
-                        endpointHolder.markReusable();
+                        establishRoute(route, request, execRuntime, context);
                     } catch (final TunnelRefusedException ex) {
                         if (this.log.isDebugEnabled()) {
                             this.log.debug(ex.getMessage());
@@ -227,15 +177,6 @@ public class MainClientExec implements C
                         break;
                     }
                 }
-                final TimeValue timeout = config.getSocketTimeout();
-                if (TimeValue.isPositive(timeout)) {
-                    endpoint.setSocketTimeout(timeout.toMillisIntBound());
-                }
-
-                if (execAware != null && execAware.isAborted()) {
-                    throw new RequestAbortedException("Request aborted");
-                }
-
                 if (this.log.isDebugEnabled()) {
                     this.log.debug("Executing request " + new RequestLine(request));
                 }
@@ -255,7 +196,7 @@ public class MainClientExec implements C
                             route.getProxyHost(), ChallengeType.PROXY, request, proxyAuthExchange, context);
                 }
 
-                response = endpoint.execute(request, requestExecutor, context);
+                response = execRuntime.execute(request, context);
 
                 // The connection is in or can be brought to a re-usable state.
                 if (reuseStrategy.keepAlive(request, response, context)) {
@@ -270,10 +211,10 @@ public class MainClientExec implements C
                         }
                         this.log.debug("Connection can be kept alive " + s);
                     }
-                    endpointHolder.setValidFor(duration);
-                    endpointHolder.markReusable();
+                    execRuntime.setConnectionValidFor(duration);
+                    execRuntime.markConnectionReusable();
                 } else {
-                    endpointHolder.markNonReusable();
+                    execRuntime.markConnectionNonReusable();
                 }
 
                 if (request.getMethod().equalsIgnoreCase("TRACE")) {
@@ -285,10 +226,10 @@ public class MainClientExec implements C
                         targetAuthExchange, proxyAuthExchange, route, request, response, context)) {
                     // Make sure the response body is fully consumed, if present
                     final HttpEntity entity = response.getEntity();
-                    if (endpointHolder.isReusable()) {
+                    if (execRuntime.isConnectionReusable()) {
                         EntityUtils.consume(entity);
                     } else {
-                        endpoint.close();
+                        execRuntime.disconnect();
                         if (proxyAuthExchange.getState() == AuthExchange.State.SUCCESS
                                 && proxyAuthExchange.getAuthScheme() != null
                                 && proxyAuthExchange.getAuthScheme().isConnectionBased()) {
@@ -303,7 +244,7 @@ public class MainClientExec implements C
                         }
                     }
                     // discard previous auth headers
-                    final HttpRequest original = request.getOriginal();
+                    final HttpRequest original = scope.originalRequest;
                     if (!original.containsHeader(HttpHeaders.AUTHORIZATION)) {
                         request.removeHeaders(HttpHeaders.AUTHORIZATION);
                     }
@@ -320,26 +261,27 @@ public class MainClientExec implements C
                 context.setAttribute(HttpClientContext.USER_TOKEN, userToken);
             }
             if (userToken != null) {
-                endpointHolder.setState(userToken);
+                execRuntime.setConnectionState(userToken);
             }
 
             // check for entity, release connection if possible
             final HttpEntity entity = response.getEntity();
             if (entity == null || !entity.isStreaming()) {
                 // connection not needed and (assumed to be) in re-usable state
-                endpointHolder.releaseConnection();
+                execRuntime.releaseConnection();
                 return new CloseableHttpResponse(response, null);
             } else {
-                ResponseEntityProxy.enchance(response, endpointHolder);
-                return new CloseableHttpResponse(response, endpointHolder);
+                ResponseEntityProxy.enchance(response, execRuntime);
+                return new CloseableHttpResponse(response, execRuntime);
             }
         } catch (final ConnectionShutdownException ex) {
             final InterruptedIOException ioex = new InterruptedIOException(
                     "Connection has been shut down");
             ioex.initCause(ex);
+            execRuntime.discardConnection();
             throw ioex;
         } catch (final HttpException | RuntimeException | IOException ex) {
-            endpointHolder.abortConnection();
+            execRuntime.discardConnection();
             throw ex;
         }
     }
@@ -348,12 +290,10 @@ public class MainClientExec implements C
      * Establishes the target route.
      */
     void establishRoute(
-            final ConnectionEndpoint endpoint,
             final HttpRoute route,
             final HttpRequest request,
+            final ExecRuntime execRuntime,
             final HttpClientContext context) throws HttpException, IOException {
-        final RequestConfig config = context.getRequestConfig();
-        final TimeValue timeout = config.getConnectTimeout();
         final RouteTracker tracker = new RouteTracker(route);
         int step;
         do {
@@ -363,16 +303,16 @@ public class MainClientExec implements C
             switch (step) {
 
             case HttpRouteDirector.CONNECT_TARGET:
-                this.connManager.connect(endpoint, timeout, context);
+                execRuntime.connect(context);
                 tracker.connectTarget(route.isSecure());
                 break;
             case HttpRouteDirector.CONNECT_PROXY:
-                this.connManager.connect(endpoint, timeout, context);
+                execRuntime.connect(context);
                 final HttpHost proxy  = route.getProxyHost();
                 tracker.connectProxy(proxy, false);
                 break;
             case HttpRouteDirector.TUNNEL_TARGET: {
-                final boolean secure = createTunnelToTarget(endpoint, route, request, context);
+                final boolean secure = createTunnelToTarget(route, request, execRuntime, context);
                 this.log.debug("Tunnel to target created.");
                 tracker.tunnelTarget(secure);
             }   break;
@@ -389,7 +329,7 @@ public class MainClientExec implements C
             }   break;
 
             case HttpRouteDirector.LAYER_PROTOCOL:
-                this.connManager.upgrade(endpoint, context);
+                execRuntime.upgradeTls(context);
                 tracker.layerProtocol(route.isSecure());
                 break;
 
@@ -415,9 +355,9 @@ public class MainClientExec implements C
      * information about the tunnel, that is left to the caller.
      */
     private boolean createTunnelToTarget(
-            final ConnectionEndpoint endpoint,
             final HttpRoute route,
             final HttpRequest request,
+            final ExecRuntime execRuntime,
             final HttpClientContext context) throws HttpException, IOException {
 
         final RequestConfig config = context.getRequestConfig();
@@ -431,17 +371,17 @@ public class MainClientExec implements C
         final ClassicHttpRequest connect = new BasicClassicHttpRequest("CONNECT", target, authority);
         connect.setVersion(HttpVersion.HTTP_1_1);
 
-        this.requestExecutor.preProcess(connect, this.proxyHttpProcessor, context);
+        this.proxyHttpProcessor.process(connect, null, context);
 
         while (response == null) {
-            if (!endpoint.isConnected()) {
-                this.connManager.connect(endpoint, config.getConnectTimeout(), context);
+            if (!execRuntime.isConnected()) {
+                execRuntime.connect(context);
             }
 
             connect.removeHeaders(HttpHeaders.PROXY_AUTHORIZATION);
             this.authenticator.addAuthResponse(proxy, ChallengeType.PROXY, connect, proxyAuthExchange, context);
 
-            response = endpoint.execute(connect, this.requestExecutor, context);
+            response = execRuntime.execute(connect, context);
 
             final int status = response.getCode();
             if (status < HttpStatus.SC_SUCCESS) {
@@ -460,7 +400,7 @@ public class MainClientExec implements C
                             final HttpEntity entity = response.getEntity();
                             EntityUtils.consume(entity);
                         } else {
-                            endpoint.close();
+                            execRuntime.disconnect();
                         }
                         response = null;
                     }
@@ -477,7 +417,8 @@ public class MainClientExec implements C
                 response.setEntity(new BufferedHttpEntity(entity));
             }
 
-            endpoint.close();
+            execRuntime.disconnect();
+            execRuntime.discardConnection();
             throw new TunnelRefusedException("CONNECT refused by proxy: " +
                     new StatusLine(response), response);
         }
@@ -515,12 +456,14 @@ public class MainClientExec implements C
             final AuthExchange targetAuthExchange,
             final AuthExchange proxyAuthExchange,
             final HttpRoute route,
-            final RoutedHttpRequest request,
+            final ClassicHttpRequest request,
             final HttpResponse response,
             final HttpClientContext context) {
         final RequestConfig config = context.getRequestConfig();
         if (config.isAuthenticationEnabled()) {
-            HttpHost target = request.getTargetHost();
+            final URIAuthority authority = request.getAuthority();
+            final String scheme = request.getScheme();
+            HttpHost target = authority != null ? new HttpHost(authority, scheme) : route.getTargetHost();;
             if (target.getPort() < 0) {
                 target = new HttpHost(
                         target.getHostName(),

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MinimalClientExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MinimalClientExec.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MinimalClientExec.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MinimalClientExec.java Mon May  1 11:11:09 2017
@@ -29,29 +29,24 @@ package org.apache.hc.client5.http.impl.
 
 import java.io.IOException;
 import java.io.InterruptedIOException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
 
 import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
 import org.apache.hc.client5.http.HttpRoute;
-import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
 import org.apache.hc.client5.http.impl.DefaultConnectionKeepAliveStrategy;
-import org.apache.hc.client5.http.io.ConnectionEndpoint;
-import org.apache.hc.client5.http.io.HttpClientConnectionManager;
-import org.apache.hc.client5.http.io.LeaseRequest;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.protocol.RequestClientConnControl;
-import org.apache.hc.client5.http.sync.methods.HttpExecutionAware;
+import org.apache.hc.client5.http.sync.ExecChain;
+import org.apache.hc.client5.http.sync.ExecChainHandler;
+import org.apache.hc.client5.http.sync.ExecRuntime;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ClassicHttpResponse;
-import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
 import org.apache.hc.core5.http.ConnectionReuseStrategy;
 import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
-import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
 import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
 import org.apache.hc.core5.http.protocol.HttpCoreContext;
 import org.apache.hc.core5.http.protocol.HttpProcessor;
@@ -74,23 +69,17 @@ import org.apache.logging.log4j.Logger;
  * @since 4.3
  */
 @Contract(threading = ThreadingBehavior.IMMUTABLE)
-public class MinimalClientExec implements ClientExecChain {
+final class MinimalClientExec implements ExecChainHandler {
 
     private final Logger log = LogManager.getLogger(getClass());
 
-    private final HttpRequestExecutor requestExecutor;
-    private final HttpClientConnectionManager connManager;
     private final ConnectionReuseStrategy reuseStrategy;
     private final ConnectionKeepAliveStrategy keepAliveStrategy;
     private final HttpProcessor httpProcessor;
 
     public MinimalClientExec(
-            final HttpRequestExecutor requestExecutor,
-            final HttpClientConnectionManager connManager,
             final ConnectionReuseStrategy reuseStrategy,
             final ConnectionKeepAliveStrategy keepAliveStrategy) {
-        this.requestExecutor = Args.notNull(requestExecutor, "Request executor");
-        this.connManager = Args.notNull(connManager, "Connection manager");
         this.reuseStrategy = reuseStrategy != null ? reuseStrategy : DefaultConnectionReuseStrategy.INSTANCE;
         this.keepAliveStrategy = keepAliveStrategy != null ? keepAliveStrategy : DefaultConnectionKeepAliveStrategy.INSTANCE;
         this.httpProcessor = new DefaultHttpProcessor(
@@ -103,92 +92,56 @@ public class MinimalClientExec implement
 
     @Override
     public ClassicHttpResponse execute(
-            final RoutedHttpRequest request,
-            final HttpClientContext context,
-            final HttpExecutionAware execAware) throws IOException, HttpException {
+            final ClassicHttpRequest request,
+            final ExecChain.Scope scope,
+            final ExecChain chain) throws IOException, HttpException {
         Args.notNull(request, "HTTP request");
-        Args.notNull(context, "HTTP context");
-
-        final HttpRoute route = request.getRoute();
-        final LeaseRequest connRequest = connManager.lease(route, null);
-        if (execAware != null) {
-            if (execAware.isAborted()) {
-                connRequest.cancel();
-                throw new RequestAbortedException("Request aborted");
-            }
-            execAware.setCancellable(connRequest);
-        }
-
-        final RequestConfig config = context.getRequestConfig();
-
-        final ConnectionEndpoint endpoint;
-        try {
-            final TimeValue timeout = config.getConnectionRequestTimeout();
-            endpoint = connRequest.get(timeout.getDuration(), timeout.getTimeUnit());
-        } catch(final TimeoutException ex) {
-            throw new ConnectionRequestTimeoutException(ex.getMessage());
-        } catch(final InterruptedException interrupted) {
-            Thread.currentThread().interrupt();
-            throw new RequestAbortedException("Request aborted", interrupted);
-        } catch(final ExecutionException ex) {
-            Throwable cause = ex.getCause();
-            if (cause == null) {
-                cause = ex;
-            }
-            throw new RequestAbortedException("Request execution failed", cause);
+        Args.notNull(scope, "Scope");
+        final HttpRoute route = scope.route;
+        final HttpClientContext context = scope.clientContext;
+        final ExecRuntime execRuntime = scope.execRuntime;
+        if (!execRuntime.isConnectionAcquired()) {
+            execRuntime.acquireConnection(route, null, context);
         }
-
-        final EndpointHolder endpointHolder = new EndpointHolder(log, connManager, endpoint);
         try {
-            if (execAware != null) {
-                if (execAware.isAborted()) {
-                    endpointHolder.close();
-                    throw new RequestAbortedException("Request aborted");
-                }
-                execAware.setCancellable(endpointHolder);
-            }
-            if (!endpoint.isConnected()) {
-                this.connManager.connect(endpoint, config.getConnectTimeout(), context);
-            }
-            final TimeValue timeout = config.getSocketTimeout();
-            if (TimeValue.isNonNegative(timeout)) {
-                endpoint.setSocketTimeout(timeout.toMillisIntBound());
+            if (!execRuntime.isConnected()) {
+                execRuntime.connect(context);
             }
 
             context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
             context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
 
             httpProcessor.process(request, request.getEntity(), context);
-            final ClassicHttpResponse response = endpoint.execute(request, requestExecutor, context);
+            final ClassicHttpResponse response = execRuntime.execute(request, context);
             httpProcessor.process(response, response.getEntity(), context);
 
             // The connection is in or can be brought to a re-usable state.
             if (reuseStrategy.keepAlive(request, response, context)) {
                 // Set the idle duration of this connection
                 final TimeValue duration = keepAliveStrategy.getKeepAliveDuration(response, context);
-                endpointHolder.setValidFor(duration);
-                endpointHolder.markReusable();
+                execRuntime.setConnectionValidFor(duration);
+                execRuntime.markConnectionReusable();
             } else {
-                endpointHolder.markNonReusable();
+                execRuntime.markConnectionNonReusable();
             }
 
             // check for entity, release connection if possible
             final HttpEntity entity = response.getEntity();
             if (entity == null || !entity.isStreaming()) {
                 // connection not needed and (assumed to be) in re-usable state
-                endpointHolder.releaseConnection();
+                execRuntime.releaseConnection();
                 return new CloseableHttpResponse(response, null);
             } else {
-                ResponseEntityProxy.enchance(response, endpointHolder);
-                return new CloseableHttpResponse(response, endpointHolder);
+                ResponseEntityProxy.enchance(response, execRuntime);
+                return new CloseableHttpResponse(response, execRuntime);
             }
         } catch (final ConnectionShutdownException ex) {
-            final InterruptedIOException ioex = new InterruptedIOException(
-                    "Connection has been shut down");
+            final InterruptedIOException ioex = new InterruptedIOException("Connection has been shut down");
             ioex.initCause(ex);
+            execRuntime.discardConnection();
             throw ioex;
         } catch (final HttpException | RuntimeException | IOException ex) {
-            endpointHolder.abortConnection();
+            execRuntime.discardConnection();
             throw ex;
         }
     }

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MinimalHttpClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MinimalHttpClient.java?rev=1793308&r1=1793307&r2=1793308&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MinimalHttpClient.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/MinimalHttpClient.java Mon May  1 11:11:09 2017
@@ -29,14 +29,17 @@ package org.apache.hc.client5.http.impl.
 
 import java.io.IOException;
 
+import org.apache.hc.client5.http.CancellableAware;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.config.Configurable;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.DefaultConnectionKeepAliveStrategy;
+import org.apache.hc.client5.http.impl.ExecSupport;
 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
 import org.apache.hc.client5.http.protocol.ClientProtocolException;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.client5.http.sync.methods.HttpExecutionAware;
+import org.apache.hc.client5.http.sync.ExecChain;
+import org.apache.hc.client5.http.sync.ExecRuntime;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.ClassicHttpRequest;
@@ -49,6 +52,8 @@ import org.apache.hc.core5.http.protocol
 import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.util.Args;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * Internal class.
@@ -56,20 +61,21 @@ import org.apache.hc.core5.util.Args;
  * @since 4.3
  */
 @Contract(threading = ThreadingBehavior.SAFE)
-class MinimalHttpClient extends CloseableHttpClient {
+public class MinimalHttpClient extends CloseableHttpClient {
+
+    private final Logger log = LogManager.getLogger(getClass());
 
     private final HttpClientConnectionManager connManager;
-    private final MinimalClientExec requestExecutor;
+    private final MinimalClientExec execChain;
+    private final HttpRequestExecutor requestExecutor;
 
-    public MinimalHttpClient(
-            final HttpClientConnectionManager connManager) {
+    MinimalHttpClient(final HttpClientConnectionManager connManager) {
         super();
         this.connManager = Args.notNull(connManager, "HTTP connection manager");
-        this.requestExecutor = new MinimalClientExec(
-                new HttpRequestExecutor(),
-                connManager,
+        this.execChain = new MinimalClientExec(
                 DefaultConnectionReuseStrategy.INSTANCE,
                 DefaultConnectionKeepAliveStrategy.INSTANCE);
+        this.requestExecutor = new HttpRequestExecutor(DefaultConnectionReuseStrategy.INSTANCE);
     }
 
     @Override
@@ -79,10 +85,6 @@ class MinimalHttpClient extends Closeabl
             final HttpContext context) throws IOException {
         Args.notNull(target, "Target host");
         Args.notNull(request, "HTTP request");
-        HttpExecutionAware execAware = null;
-        if (request instanceof HttpExecutionAware) {
-            execAware = (HttpExecutionAware) request;
-        }
         try {
             if (request.getScheme() == null) {
                 request.setScheme(target.getSchemeName());
@@ -99,9 +101,10 @@ class MinimalHttpClient extends Closeabl
             if (config != null) {
                 localcontext.setRequestConfig(config);
             }
-            final HttpRoute route = new HttpRoute(target);
-            final ClassicHttpResponse response = this.requestExecutor.execute(
-                    RoutedHttpRequest.adapt(request, route), localcontext, execAware);
+            final ExecRuntime execRuntime = new ExecRuntimeImpl(log, connManager, requestExecutor,
+                    request instanceof CancellableAware ? (CancellableAware) request : null);
+            final ExecChain.Scope scope = new ExecChain.Scope(new HttpRoute(target), request, execRuntime, localcontext);
+            final ClassicHttpResponse response = this.execChain.execute(ExecSupport.copy(request), scope, null);
             return CloseableHttpResponse.adapt(response);
         } catch (final HttpException httpException) {
             throw new ClientProtocolException(httpException);