hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r1793320 [3/5] - in /httpcomponents/httpclient/trunk: httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/ httpclient5-testing/src/main/java/org/apache/hc/client5/testing/classic/ httpclient5-testing/src/test/java/org/apac...
Date Mon, 01 May 2017 12:39:18 GMT
Modified: httpcomponents/httpclient/trunk/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientCustomSSL.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientCustomSSL.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientCustomSSL.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientCustomSSL.java Mon May  1 12:39:16 2017
@@ -26,20 +26,23 @@
  */
 package org.apache.hc.client5.http.examples;
 
-import java.io.File;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
 
 import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
 
 import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
 import org.apache.hc.client5.http.impl.sync.CloseableHttpClient;
 import org.apache.hc.client5.http.impl.sync.CloseableHttpResponse;
 import org.apache.hc.client5.http.impl.sync.HttpClients;
 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
-import org.apache.hc.client5.http.ssl.TrustSelfSignedStrategy;
 import org.apache.hc.client5.http.sync.methods.HttpGet;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 import org.apache.hc.core5.ssl.SSLContexts;
+import org.apache.hc.core5.ssl.TrustStrategy;
 
 /**
  * This example demonstrates how to create secure connections with a custom SSL
@@ -48,10 +51,19 @@ import org.apache.hc.core5.ssl.SSLContex
 public class ClientCustomSSL {
 
     public final static void main(final String[] args) throws Exception {
-        // Trust own CA and all self-signed certs
+        // Trust standard CA and those trusted by our custom strategy
         final SSLContext sslcontext = SSLContexts.custom()
-                .loadTrustMaterial(new File("my.keystore"), "nopassword".toCharArray(),
-                        new TrustSelfSignedStrategy())
+                .loadTrustMaterial(new TrustStrategy() {
+
+                    @Override
+                    public boolean isTrusted(
+                            final X509Certificate[] chain,
+                            final String authType) throws CertificateException {
+                        final X509Certificate cert = chain[0];
+                        return "CN=httpbin.org".equalsIgnoreCase(cert.getSubjectDN().getName());
+                    }
+
+                })
                 .build();
         // Allow TLSv1.2 protocol only
         final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
@@ -70,10 +82,17 @@ public class ClientCustomSSL {
 
             System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
 
-            try (CloseableHttpResponse response = httpclient.execute(httpget)) {
+            final HttpClientContext clientContext = HttpClientContext.create();
+            try (CloseableHttpResponse response = httpclient.execute(httpget, clientContext)) {
                 System.out.println("----------------------------------------");
                 System.out.println(response.getCode() + " " + response.getReasonPhrase());
                 System.out.println(EntityUtils.toString(response.getEntity()));
+
+                final SSLSession sslSession = clientContext.getSSLSession();
+                if (sslSession != null) {
+                    System.out.println("SSL protocol " + sslSession.getProtocol());
+                    System.out.println("SSL cipher suite " + sslSession.getCipherSuite());
+                }
             }
         }
     }

Modified: httpcomponents/httpclient/trunk/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientInterceptors.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientInterceptors.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientInterceptors.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/examples/org/apache/hc/client5/http/examples/ClientInterceptors.java Mon May  1 12:39:16 2017
@@ -97,14 +97,17 @@ public class ClientInterceptors {
 
                 })
                 .build()) {
-            final HttpGet httpget = new HttpGet("http://httpbin.org/get");
 
-            System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
+            for (int i = 0; i < 20; i++) {
+                final HttpGet httpget = new HttpGet("http://httpbin.org/get");
 
-            try (CloseableHttpResponse response = httpclient.execute(httpget)) {
-                System.out.println("----------------------------------------");
-                System.out.println(response.getCode() + " " + response.getReasonPhrase());
-                System.out.println(EntityUtils.toString(response.getEntity()));
+                System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
+
+                try (CloseableHttpResponse response = httpclient.execute(httpget)) {
+                    System.out.println("----------------------------------------");
+                    System.out.println(response.getCode() + " " + response.getReasonPhrase());
+                    System.out.println(EntityUtils.toString(response.getEntity()));
+                }
             }
         }
     }

Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecCallback.java (from r1793319, httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecCallback.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecCallback.java&p1=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java&r1=1793319&r2=1793320&rev=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecCallback.java Mon May  1 12:39:16 2017
@@ -24,16 +24,21 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.client5.http.async.methods;
+package org.apache.hc.client5.http.async;
 
-import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
-import org.apache.hc.core5.util.Args;
+import java.io.IOException;
 
-public final class SimpleRequestProducer extends DefaultAsyncRequestProducer {
+import org.apache.hc.core5.http.EntityDetails;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.nio.AsyncDataConsumer;
 
-    public SimpleRequestProducer(final SimpleHttpRequest request) {
-        super(Args.notNull(request, "Request"), request.getBody() != null ?
-                new StringAsyncEntityProducer(request.getBody(), request.getContentType()) : null);
-    }
+public interface AsyncExecCallback {
+
+    AsyncDataConsumer handleResponse(HttpResponse response, EntityDetails entityDetails) throws HttpException, IOException;
+
+    void completed();
+
+    void failed(Exception cause);
 
 }

Added: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChain.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChain.java?rev=1793320&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChain.java (added)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChain.java Mon May  1 12:39:16 2017
@@ -0,0 +1,69 @@
+/*
+ * ====================================================================
+ * 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.async;
+
+import java.io.IOException;
+
+import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.util.Args;
+
+public interface AsyncExecChain {
+
+    final class Scope {
+
+        public final String exchangeId;
+        public final HttpRoute route;
+        public final HttpRequest originalRequest;
+        public final AsyncExecRuntime execRuntime;
+        public final HttpClientContext clientContext;
+
+        public Scope(
+                final String exchangeId,
+                final HttpRoute route,
+                final HttpRequest originalRequest,
+                final HttpClientContext clientContext,
+                final AsyncExecRuntime execRuntime) {
+            this.exchangeId = Args.notBlank(exchangeId, "Exchange id");
+            this.route = Args.notNull(route, "Route");
+            this.originalRequest = Args.notNull(originalRequest, "Original request");
+            this.execRuntime = Args.notNull(execRuntime, "Exec runtime");
+            this.clientContext = clientContext != null ? clientContext : HttpClientContext.create();
+        }
+
+    }
+
+    void proceed(
+            HttpRequest request,
+            AsyncEntityProducer entityProducer,
+            Scope scope,
+            AsyncExecCallback asyncExecCallback) throws HttpException, IOException;
+
+}

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

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

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

Copied: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChainHandler.java (from r1793319, httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChainHandler.java?p2=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChainHandler.java&p1=httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java&r1=1793319&r2=1793320&rev=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecChainHandler.java Mon May  1 12:39:16 2017
@@ -24,16 +24,21 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.client5.http.async.methods;
+package org.apache.hc.client5.http.async;
 
-import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
-import org.apache.hc.core5.util.Args;
+import java.io.IOException;
 
-public final class SimpleRequestProducer extends DefaultAsyncRequestProducer {
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
 
-    public SimpleRequestProducer(final SimpleHttpRequest request) {
-        super(Args.notNull(request, "Request"), request.getBody() != null ?
-                new StringAsyncEntityProducer(request.getBody(), request.getContentType()) : null);
-    }
+public interface AsyncExecChainHandler {
+
+    void execute(
+            HttpRequest request,
+            AsyncEntityProducer entityProducer,
+            AsyncExecChain.Scope scope,
+            AsyncExecChain chain,
+            AsyncExecCallback asyncExecCallback) throws HttpException, IOException;
 
 }

Added: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecRuntime.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecRuntime.java?rev=1793320&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecRuntime.java (added)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/AsyncExecRuntime.java Mon May  1 12:39:16 2017
@@ -0,0 +1,90 @@
+/*
+ * ====================================================================
+ * 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.async;
+
+import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.annotation.Internal;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
+import org.apache.hc.core5.util.TimeValue;
+
+/**
+ * Execution runtime that provides access to the underlying connection endpoint and helps
+ * manager its life cycle.
+ * <p>
+ * This interface is considered internal and generally ought not be used or accessed
+ * by custom request exec handlers.
+ *
+ * @since 5.0
+ */
+@Internal
+public interface AsyncExecRuntime {
+
+    boolean isConnectionAcquired();
+
+    void acquireConnection(
+            HttpRoute route,
+            Object state,
+            HttpClientContext clientContext,
+            FutureCallback<AsyncExecRuntime> callback);
+
+    void releaseConnection();
+
+    void discardConnection();
+
+    boolean isConnected();
+
+    void disconnect();
+
+    void connect(
+            HttpClientContext clientContext,
+            FutureCallback<AsyncExecRuntime> callback);
+
+    void upgradeTls(HttpClientContext context);
+
+    /**
+     * Initiates a message exchange using the given handler.
+     */
+    void execute(
+            AsyncClientExchangeHandler exchangeHandler,
+            HttpClientContext context);
+
+    boolean validateConnection();
+
+    boolean isConnectionReusable();
+
+    void markConnectionReusable();
+
+    void markConnectionNonReusable();
+
+    void setConnectionState(Object state);
+
+    void setConnectionValidFor(TimeValue duration);
+
+}

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

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

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

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/HttpAsyncClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/HttpAsyncClient.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/HttpAsyncClient.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/HttpAsyncClient.java Mon May  1 12:39:16 2017
@@ -30,8 +30,6 @@ import java.util.concurrent.Future;
 
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.function.Supplier;
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.nio.AsyncClientEndpoint;
 import org.apache.hc.core5.http.nio.AsyncPushConsumer;
 import org.apache.hc.core5.http.nio.AsyncRequestProducer;
 import org.apache.hc.core5.http.nio.AsyncResponseConsumer;
@@ -48,17 +46,6 @@ import org.apache.hc.core5.http.protocol
 public interface HttpAsyncClient {
 
     /**
-     * Leases {@link AsyncClientEndpoint} for the given {@link HttpHost}.
-     * <p>
-     * The endpoint MUST be released back when no longer used by calling
-     * {@link AsyncClientEndpoint#releaseAndReuse()} or {@link AsyncClientEndpoint#releaseAndDiscard()}
-     */
-    Future<AsyncClientEndpoint> lease(
-            HttpHost host,
-            HttpContext context,
-            FutureCallback<AsyncClientEndpoint> callback);
-
-    /**
      * Initiates asynchronous HTTP request execution using the given context.
      * <p>
      * The request producer passed to this method will be used to generate

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/DefaultAsyncRequestProducer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/DefaultAsyncRequestProducer.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/DefaultAsyncRequestProducer.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/DefaultAsyncRequestProducer.java Mon May  1 12:39:16 2017
@@ -26,27 +26,18 @@
  */
 package org.apache.hc.client5.http.async.methods;
 
-import java.io.IOException;
-
 import org.apache.hc.client5.http.config.Configurable;
 import org.apache.hc.client5.http.config.RequestConfig;
-import org.apache.hc.core5.http.EntityDetails;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
-import org.apache.hc.core5.http.nio.AsyncRequestProducer;
-import org.apache.hc.core5.http.nio.DataStreamChannel;
-import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.http.nio.BasicRequestProducer;
 
-public class DefaultAsyncRequestProducer implements AsyncRequestProducer, Configurable {
+public class DefaultAsyncRequestProducer extends BasicRequestProducer implements Configurable {
 
-    private final HttpRequest request;
-    private final AsyncEntityProducer entityProducer;
     private final RequestConfig config;
 
     public DefaultAsyncRequestProducer(final HttpRequest request, final AsyncEntityProducer entityProducer, final RequestConfig config) {
-        Args.notNull(request, "Request");
-        this.request = request;
-        this.entityProducer = entityProducer;
+        super(request, entityProducer);
         this.config = config;
     }
 
@@ -59,38 +50,4 @@ public class DefaultAsyncRequestProducer
         return config;
     }
 
-    @Override
-    public final HttpRequest produceRequest() {
-        return request;
-    }
-
-    @Override
-    public final EntityDetails getEntityDetails() {
-        return entityProducer;
-    }
-
-    @Override
-    public final int available() {
-        return entityProducer != null ? entityProducer.available() : 0;
-    }
-
-    @Override
-    public final void produce(final DataStreamChannel channel) throws IOException {
-        if (entityProducer != null) {
-            entityProducer.produce(channel);
-        }
-    }
-
-    @Override
-    public final void failed(final Exception cause) {
-        releaseResources();
-    }
-
-    @Override
-    public final void releaseResources() {
-        if (entityProducer != null) {
-            entityProducer.releaseResources();
-        }
-    }
-
 }

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpRequest.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpRequest.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpRequest.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpRequest.java Mon May  1 12:39:16 2017
@@ -29,17 +29,131 @@ package org.apache.hc.client5.http.async
 
 import java.net.URI;
 
+import org.apache.hc.client5.http.StandardMethods;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.message.BasicHttpRequest;
 import org.apache.hc.core5.http.message.HttpRequestWrapper;
+import org.apache.hc.core5.util.Args;
 
 public final class SimpleHttpRequest extends HttpRequestWrapper {
 
     private final String body;
     private final ContentType contentType;
 
+    public static SimpleHttpRequest get(final URI requestUri) {
+        Args.notNull(requestUri, "Request URI");
+        return new SimpleHttpRequest(StandardMethods.GET, requestUri, null, null);
+    }
+
+    public static SimpleHttpRequest get(final String requestUri) {
+        return new SimpleHttpRequest(StandardMethods.GET, URI.create(requestUri), null, null);
+    }
+
+    public static SimpleHttpRequest get(final HttpHost host, final String path) {
+        Args.notNull(host, "Host");
+        return new SimpleHttpRequest(StandardMethods.GET, host, path, null, null);
+    }
+
+    public static SimpleHttpRequest head(final URI requestUri) {
+        Args.notNull(requestUri, "Request URI");
+        return new SimpleHttpRequest(StandardMethods.HEAD, requestUri, null, null);
+    }
+
+    public static SimpleHttpRequest head(final String requestUri) {
+        return new SimpleHttpRequest(StandardMethods.HEAD, URI.create(requestUri), null, null);
+    }
+
+    public static SimpleHttpRequest head(final HttpHost host, final String path) {
+        Args.notNull(host, "Host");
+        return new SimpleHttpRequest(StandardMethods.HEAD, host, path, null, null);
+    }
+
+    public static SimpleHttpRequest post(final URI requestUri, final String body, final ContentType contentType) {
+        Args.notNull(requestUri, "Request URI");
+        return new SimpleHttpRequest(StandardMethods.POST, requestUri, body, contentType);
+    }
+
+    public static SimpleHttpRequest post(final String requestUri, final String body, final ContentType contentType) {
+        return new SimpleHttpRequest(StandardMethods.POST, URI.create(requestUri), body, contentType);
+    }
+
+    public static SimpleHttpRequest post(final HttpHost host, final String path, final String body, final ContentType contentType) {
+        Args.notNull(host, "Host");
+        return new SimpleHttpRequest(StandardMethods.POST, host, path, body, contentType);
+    }
+
+    public static SimpleHttpRequest PUT(final URI requestUri, final String body, final ContentType contentType) {
+        Args.notNull(requestUri, "Request URI");
+        return new SimpleHttpRequest(StandardMethods.PUT, requestUri, body, contentType);
+    }
+
+    public static SimpleHttpRequest put(final String requestUri, final String body, final ContentType contentType) {
+        return new SimpleHttpRequest(StandardMethods.PUT, URI.create(requestUri), body, contentType);
+    }
+
+    public static SimpleHttpRequest put(final HttpHost host, final String path, final String body, final ContentType contentType) {
+        Args.notNull(host, "Host");
+        return new SimpleHttpRequest(StandardMethods.PUT, host, path, body, contentType);
+    }
+
+    public static SimpleHttpRequest delete(final URI requestUri) {
+        Args.notNull(requestUri, "Request URI");
+        return new SimpleHttpRequest(StandardMethods.DELETE, requestUri, null, null);
+    }
+
+    public static SimpleHttpRequest delete(final String requestUri) {
+        return new SimpleHttpRequest(StandardMethods.DELETE, URI.create(requestUri), null, null);
+    }
+
+    public static SimpleHttpRequest delete(final HttpHost host, final String path) {
+        Args.notNull(host, "Host");
+        return new SimpleHttpRequest(StandardMethods.DELETE, host, path, null, null);
+    }
+
+    public static SimpleHttpRequest trace(final URI requestUri) {
+        Args.notNull(requestUri, "Request URI");
+        return new SimpleHttpRequest(StandardMethods.TRACE, requestUri, null, null);
+    }
+
+    public static SimpleHttpRequest trace(final String requestUri) {
+        return new SimpleHttpRequest(StandardMethods.TRACE, URI.create(requestUri), null, null);
+    }
+
+    public static SimpleHttpRequest trace(final HttpHost host, final String path) {
+        Args.notNull(host, "Host");
+        return new SimpleHttpRequest(StandardMethods.TRACE, host, path, null, null);
+    }
+
+    public static SimpleHttpRequest options(final URI requestUri) {
+        Args.notNull(requestUri, "Request URI");
+        return new SimpleHttpRequest(StandardMethods.OPTIONS, requestUri, null, null);
+    }
+
+    public static SimpleHttpRequest options(final String requestUri) {
+        return new SimpleHttpRequest(StandardMethods.OPTIONS, URI.create(requestUri), null, null);
+    }
+
+    public static SimpleHttpRequest options(final HttpHost host, final String path) {
+        Args.notNull(host, "Host");
+        return new SimpleHttpRequest(StandardMethods.OPTIONS, host, path, null, null);
+    }
+
+    public static SimpleHttpRequest patch(final URI requestUri, final String body, final ContentType contentType) {
+        Args.notNull(requestUri, "Request URI");
+        return new SimpleHttpRequest(StandardMethods.PATCH, requestUri, body, contentType);
+    }
+
+    public static SimpleHttpRequest patch(final String requestUri, final String body, final ContentType contentType) {
+        return new SimpleHttpRequest(StandardMethods.PATCH, URI.create(requestUri), body, contentType);
+    }
+
+    public static SimpleHttpRequest patch(final HttpHost host, final String path, final String body, final ContentType contentType) {
+        Args.notNull(host, "Host");
+        return new SimpleHttpRequest(StandardMethods.PATCH, host, path, body, contentType);
+    }
+
     public SimpleHttpRequest(final HttpRequest head, final String body, final ContentType contentType) {
         super(head);
         this.body = body;
@@ -57,12 +171,25 @@ public final class SimpleHttpRequest ext
         this.contentType = contentType;
     }
 
+    SimpleHttpRequest(
+            final StandardMethods method,
+            final HttpHost host,
+            final String path,
+            final String body,
+            final ContentType contentType) {
+        this(method.name(), host, path, body, contentType);
+    }
+
     public SimpleHttpRequest(final String method, final URI requestUri, final String body, final ContentType contentType) {
         super(new BasicHttpRequest(method, requestUri));
         this.body = body;
         this.contentType = contentType;
     }
 
+    SimpleHttpRequest(final StandardMethods method, final URI requestUri, final String body, final ContentType contentType) {
+        this(method.name(), requestUri, body, contentType);
+    }
+
     public String getBody() {
         return body;
     }

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpResponse.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpResponse.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpResponse.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleHttpResponse.java Mon May  1 12:39:16 2017
@@ -62,6 +62,10 @@ public final class SimpleHttpResponse ex
         this.contentType = contentType;
     }
 
+    public SimpleHttpResponse(final int code) {
+        this(code, null, null);
+    }
+
     public String getBody() {
         return body;
     }

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleRequestProducer.java Mon May  1 12:39:16 2017
@@ -26,14 +26,19 @@
  */
 package org.apache.hc.client5.http.async.methods;
 
+import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
 import org.apache.hc.core5.util.Args;
 
 public final class SimpleRequestProducer extends DefaultAsyncRequestProducer {
 
-    public SimpleRequestProducer(final SimpleHttpRequest request) {
+    public SimpleRequestProducer(final SimpleHttpRequest request, final RequestConfig requestConfig) {
         super(Args.notNull(request, "Request"), request.getBody() != null ?
-                new StringAsyncEntityProducer(request.getBody(), request.getContentType()) : null);
+                new StringAsyncEntityProducer(request.getBody(), request.getContentType()) : null, requestConfig);
+    }
+
+    public SimpleRequestProducer(final SimpleHttpRequest request) {
+        this(request, null);
     }
 
 }

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleResponseConsumer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleResponseConsumer.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleResponseConsumer.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/async/methods/SimpleResponseConsumer.java Mon May  1 12:39:16 2017
@@ -29,6 +29,7 @@ package org.apache.hc.client5.http.async
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http.nio.support.AbstractAsyncResponseConsumer;
 
 public final class SimpleResponseConsumer extends AbstractAsyncResponseConsumer<SimpleHttpResponse, String> {
 

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ExecSupport.java Mon May  1 12:39:16 2017
@@ -27,6 +27,7 @@
 package org.apache.hc.client5.http.impl;
 
 import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicLong;
 
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ClassicHttpResponse;
@@ -42,6 +43,12 @@ import org.apache.hc.core5.http.message.
 
 public final class ExecSupport {
 
+    private static final AtomicLong COUNT = new AtomicLong(0);
+
+    public static long getNextExecNumber() {
+        return COUNT.incrementAndGet();
+    }
+
     private static void copyMessageProperties(final HttpMessage original, final HttpMessage copy) {
         copy.setVersion(original.getVersion());
         for (final Iterator<Header> it = original.headerIterator(); it.hasNext(); ) {
@@ -54,6 +61,7 @@ public final class ExecSupport {
         if (copy.getVersion() == null) {
             copy.setVersion(HttpVersion.DEFAULT);
         }
+        copy.setScheme(original.getScheme());
         copy.setAuthority(original.getAuthority());
     }
 

Modified: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AbstractHttpAsyncClientBase.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AbstractHttpAsyncClientBase.java?rev=1793320&r1=1793319&r2=1793320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AbstractHttpAsyncClientBase.java (original)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AbstractHttpAsyncClientBase.java Mon May  1 12:39:16 2017
@@ -32,20 +32,14 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicReference;
 
-import org.apache.hc.core5.function.Callback;
 import org.apache.hc.core5.function.Supplier;
 import org.apache.hc.core5.http.ExceptionListener;
 import org.apache.hc.core5.http.nio.AsyncPushConsumer;
-import org.apache.hc.core5.http.nio.command.ShutdownCommand;
 import org.apache.hc.core5.io.ShutdownType;
 import org.apache.hc.core5.reactor.ConnectionInitiator;
 import org.apache.hc.core5.reactor.DefaultConnectingIOReactor;
 import org.apache.hc.core5.reactor.ExceptionEvent;
-import org.apache.hc.core5.reactor.IOEventHandlerFactory;
-import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.reactor.IOReactorException;
 import org.apache.hc.core5.reactor.IOReactorStatus;
-import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -62,31 +56,20 @@ abstract class AbstractHttpAsyncClientBa
     private final ExecutorService executorService;
     private final AtomicReference<Status> status;
 
-    public AbstractHttpAsyncClientBase(
-            final IOEventHandlerFactory eventHandlerFactory,
+    AbstractHttpAsyncClientBase(
+            final DefaultConnectingIOReactor ioReactor,
             final AsyncPushConsumerRegistry pushConsumerRegistry,
-            final IOReactorConfig reactorConfig,
-            final ThreadFactory threadFactory,
-            final ThreadFactory workerThreadFactory) throws IOReactorException {
+            final ThreadFactory threadFactory) {
         super();
-        this.ioReactor = new DefaultConnectingIOReactor(
-                eventHandlerFactory,
-                reactorConfig,
-                workerThreadFactory,
-                new Callback<IOSession>() {
-
-                    @Override
-                    public void execute(final IOSession ioSession) {
-                        ioSession.addFirst(new ShutdownCommand(ShutdownType.GRACEFUL));
-                    }
-
-                });
+        this.ioReactor = ioReactor;
         this.pushConsumerRegistry = pushConsumerRegistry;
         this.exceptionListener = new ExceptionListener() {
+
             @Override
             public void onError(final Exception ex) {
                 log.error(ex.getMessage(), ex);
             }
+
         };
         this.executorService = Executors.newSingleThreadExecutor(threadFactory);
         this.status = new AtomicReference<>(Status.READY);
@@ -144,11 +127,17 @@ abstract class AbstractHttpAsyncClientBa
 
     @Override
     public final void initiateShutdown() {
+        if (log.isDebugEnabled()) {
+            log.debug("Initiating shutdown");
+        }
         ioReactor.initiateShutdown();
     }
 
     @Override
     public final void shutdown(final ShutdownType shutdownType) {
+        if (log.isDebugEnabled()) {
+            log.debug("Shutdown " + shutdownType);
+        }
         ioReactor.initiateShutdown();
         ioReactor.shutdown(shutdownType);
     }

Added: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncExecChainElement.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncExecChainElement.java?rev=1793320&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncExecChainElement.java (added)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncExecChainElement.java Mon May  1 12:39:16 2017
@@ -0,0 +1,77 @@
+/*
+ * ====================================================================
+ * 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.async;
+
+import java.io.IOException;
+
+import org.apache.hc.client5.http.async.AsyncExecCallback;
+import org.apache.hc.client5.http.async.AsyncExecChain;
+import org.apache.hc.client5.http.async.AsyncExecChainHandler;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+
+class AsyncExecChainElement {
+
+    private final AsyncExecChainHandler handler;
+    private final AsyncExecChainElement next;
+
+    AsyncExecChainElement(final AsyncExecChainHandler handler, final AsyncExecChainElement next) {
+        this.handler = handler;
+        this.next = next;
+    }
+
+    public void execute(
+            final HttpRequest request,
+            final AsyncEntityProducer entityProducer,
+            final AsyncExecChain.Scope scope,
+            final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
+        handler.execute(request, entityProducer, scope, new AsyncExecChain() {
+
+            @Override
+            public void proceed(
+                    final HttpRequest request,
+                    final AsyncEntityProducer entityProducer,
+                    final AsyncExecChain.Scope scope,
+                    final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
+                next.execute(request, entityProducer, scope, asyncExecCallback);
+            }
+
+        }, asyncExecCallback);
+
+    }
+
+    @Override
+    public String toString() {
+        return "{" +
+                "handler=" + handler.getClass() +
+                ", next=" + (next != null ? next.handler.getClass() : "null") +
+                '}';
+    }
+
+}
\ No newline at end of file

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

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

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

Added: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncExecRuntimeImpl.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncExecRuntimeImpl.java?rev=1793320&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncExecRuntimeImpl.java (added)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncExecRuntimeImpl.java Mon May  1 12:39:16 2017
@@ -0,0 +1,302 @@
+/*
+ * ====================================================================
+ * 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.async;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.async.AsyncExecRuntime;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.ConnPoolSupport;
+import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
+import org.apache.hc.client5.http.nio.AsyncConnectionEndpoint;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.reactor.ConnectionInitiator;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.logging.log4j.Logger;
+
+class AsyncExecRuntimeImpl implements AsyncExecRuntime {
+
+    private final Logger log;
+    private final AsyncClientConnectionManager manager;
+    private final ConnectionInitiator connectionInitiator;
+    private final HttpVersionPolicy versionPolicy;
+    private final AtomicReference<AsyncConnectionEndpoint> endpointRef;
+    private volatile boolean reusable;
+    private volatile Object state;
+    private volatile TimeValue validDuration;
+
+    AsyncExecRuntimeImpl(
+            final Logger log,
+            final AsyncClientConnectionManager manager,
+            final ConnectionInitiator connectionInitiator,
+            final HttpVersionPolicy versionPolicy) {
+        super();
+        this.log = log;
+        this.manager = manager;
+        this.connectionInitiator = connectionInitiator;
+        this.versionPolicy = versionPolicy;
+        this.endpointRef = new AtomicReference<>(null);
+        this.validDuration = TimeValue.NEG_ONE_MILLISECONDS;
+    }
+
+    @Override
+    public boolean isConnectionAcquired() {
+        return endpointRef.get() != null;
+    }
+
+    @Override
+    public void acquireConnection(
+            final HttpRoute route,
+            final Object object,
+            final HttpClientContext context,
+            final FutureCallback<AsyncExecRuntime> callback) {
+        if (endpointRef.get() == null) {
+            state = object;
+            final RequestConfig requestConfig = context.getRequestConfig();
+            manager.lease(route, object, requestConfig.getConnectionRequestTimeout(), new FutureCallback<AsyncConnectionEndpoint>() {
+
+                @Override
+                public void completed(final AsyncConnectionEndpoint connectionEndpoint) {
+                    endpointRef.set(connectionEndpoint);
+                    reusable = connectionEndpoint.isConnected();
+                    callback.completed(AsyncExecRuntimeImpl.this);
+                }
+
+                @Override
+                public void failed(final Exception ex) {
+                    callback.failed(ex);
+                }
+
+                @Override
+                public void cancelled() {
+                    callback.cancelled();
+                }
+            });
+        } else {
+            callback.completed(this);
+        }
+    }
+
+    @Override
+    public void releaseConnection() {
+        final AsyncConnectionEndpoint endpoint = endpointRef.getAndSet(null);
+        if (endpoint != null) {
+            if (reusable) {
+                if (log.isDebugEnabled()) {
+                    log.debug(ConnPoolSupport.getId(endpoint) + ": releasing valid endpoint");
+                }
+                manager.release(endpoint, state, validDuration);
+            } else {
+                try {
+                    if (log.isDebugEnabled()) {
+                        log.debug(ConnPoolSupport.getId(endpoint) + ": releasing invalid endpoint");
+                    }
+                    endpoint.close();
+                } catch (final IOException ex) {
+                    if (log.isDebugEnabled()) {
+                        log.debug(ConnPoolSupport.getId(endpoint) + ": " + ex.getMessage(), ex);
+                    }
+                } finally {
+                    manager.release(endpoint, null, TimeValue.ZERO_MILLISECONDS);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void discardConnection() {
+        final AsyncConnectionEndpoint endpoint = endpointRef.getAndSet(null);
+        if (endpoint != null) {
+            try {
+                endpoint.shutdown();
+                if (log.isDebugEnabled()) {
+                    log.debug(ConnPoolSupport.getId(endpoint) + ": discarding endpoint");
+                }
+            } catch (final IOException ex) {
+                if (log.isDebugEnabled()) {
+                    log.debug(ConnPoolSupport.getId(endpoint) + ": " + ex.getMessage(), ex);
+                }
+            } finally {
+                manager.release(endpoint, null, TimeValue.ZERO_MILLISECONDS);
+            }
+        }
+    }
+
+    AsyncConnectionEndpoint ensureValid() {
+        final AsyncConnectionEndpoint endpoint = endpointRef.get();
+        if (endpoint == null) {
+            throw new IllegalStateException("Endpoint not acquired / already released");
+        }
+        return endpoint;
+    }
+
+    @Override
+    public boolean isConnected() {
+        final AsyncConnectionEndpoint endpoint = endpointRef.get();
+        return endpoint != null && endpoint.isConnected();
+    }
+
+    @Override
+    public void disconnect() {
+        final AsyncConnectionEndpoint endpoint = endpointRef.get();
+        if (endpoint != null) {
+            try {
+                endpoint.close();
+            } catch (final IOException ex) {
+                if (log.isDebugEnabled()) {
+                    log.debug(ConnPoolSupport.getId(endpoint) + ": " + ex.getMessage(), ex);
+                }
+                discardConnection();
+            }
+        }
+
+    }
+
+    @Override
+    public void connect(
+            final HttpClientContext context,
+            final FutureCallback<AsyncExecRuntime> callback) {
+        final AsyncConnectionEndpoint endpoint = ensureValid();
+        if (endpoint.isConnected()) {
+            callback.completed(this);
+        } else {
+            final RequestConfig requestConfig = context.getRequestConfig();
+            manager.connect(
+                    endpoint,
+                    connectionInitiator,
+                    requestConfig.getConnectTimeout(),
+                    versionPolicy,
+                    context,
+                    new FutureCallback<AsyncConnectionEndpoint>() {
+
+                        @Override
+                        public void completed(final AsyncConnectionEndpoint endpoint) {
+                            final TimeValue socketTimeout = requestConfig.getSocketTimeout();
+                            if (TimeValue.isPositive(socketTimeout)) {
+                                endpoint.setSocketTimeout(socketTimeout.toMillisIntBound());
+                            }
+                            callback.completed(AsyncExecRuntimeImpl.this);
+                        }
+
+                        @Override
+                        public void failed(final Exception ex) {
+                            callback.failed(ex);
+                        }
+
+                        @Override
+                        public void cancelled() {
+                            callback.cancelled();
+                        }
+
+            });
+        }
+
+    }
+
+    @Override
+    public void upgradeTls(final HttpClientContext context) {
+        final AsyncConnectionEndpoint endpoint = ensureValid();
+        manager.upgrade(endpoint, context);
+    }
+
+    @Override
+    public void execute(final AsyncClientExchangeHandler exchangeHandler, final HttpClientContext context) {
+        final AsyncConnectionEndpoint endpoint = ensureValid();
+        if (endpoint.isConnected()) {
+            if (log.isDebugEnabled()) {
+                log.debug(ConnPoolSupport.getId(endpoint) + ": executing " + ConnPoolSupport.getId(exchangeHandler));
+            }
+            endpoint.execute(exchangeHandler, context);
+        } else {
+            connect(context, new FutureCallback<AsyncExecRuntime>() {
+
+                @Override
+                public void completed(final AsyncExecRuntime runtime) {
+                    if (log.isDebugEnabled()) {
+                        log.debug(ConnPoolSupport.getId(endpoint) + ": executing " + ConnPoolSupport.getId(exchangeHandler));
+                    }
+                    try {
+                        endpoint.execute(exchangeHandler, context);
+                    } catch (RuntimeException ex) {
+                        failed(ex);
+                    }
+                }
+
+                @Override
+                public void failed(final Exception ex) {
+                    exchangeHandler.failed(ex);
+                }
+
+                @Override
+                public void cancelled() {
+                    exchangeHandler.failed(new InterruptedIOException());
+                }
+
+            });
+        }
+
+    }
+
+    @Override
+    public boolean validateConnection() {
+        final AsyncConnectionEndpoint endpoint = endpointRef.get();
+        return endpoint != null && endpoint.isConnected();
+    }
+
+    @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;
+    }
+
+}

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

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

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

Added: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncMainClientExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncMainClientExec.java?rev=1793320&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncMainClientExec.java (added)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncMainClientExec.java Mon May  1 12:39:16 2017
@@ -0,0 +1,235 @@
+/*
+ * ====================================================================
+ * 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.async;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
+import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.async.AsyncExecCallback;
+import org.apache.hc.client5.http.async.AsyncExecChain;
+import org.apache.hc.client5.http.async.AsyncExecChainHandler;
+import org.apache.hc.client5.http.async.AsyncExecRuntime;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.protocol.UserTokenHandler;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.EntityDetails;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.message.RequestLine;
+import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
+import org.apache.hc.core5.http.nio.AsyncDataConsumer;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.nio.CapacityChannel;
+import org.apache.hc.core5.http.nio.DataStreamChannel;
+import org.apache.hc.core5.http.nio.RequestChannel;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+class AsyncMainClientExec implements AsyncExecChainHandler {
+
+    private final Logger log = LogManager.getLogger(getClass());
+
+    private final ConnectionKeepAliveStrategy keepAliveStrategy;
+    private final UserTokenHandler userTokenHandler;
+
+    AsyncMainClientExec(final ConnectionKeepAliveStrategy keepAliveStrategy, final UserTokenHandler userTokenHandler) {
+        this.keepAliveStrategy = keepAliveStrategy;
+        this.userTokenHandler = userTokenHandler;
+    }
+
+    @Override
+    public void execute(
+            final HttpRequest request,
+            final AsyncEntityProducer entityProducer,
+            final AsyncExecChain.Scope scope,
+            final AsyncExecChain chain,
+            final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
+        final String exchangeId = scope.exchangeId;
+        final HttpRoute route = scope.route;
+        final HttpClientContext clientContext = scope.clientContext;
+        final AsyncExecRuntime execRuntime = scope.execRuntime;
+        if (!execRuntime.isConnectionAcquired()) {
+            final Object userToken = clientContext.getUserToken();
+            if (log.isDebugEnabled()) {
+                log.debug(exchangeId + ": acquiring connection with route " + route);
+            }
+            execRuntime.acquireConnection(route, userToken, clientContext, new FutureCallback<AsyncExecRuntime>() {
+
+                @Override
+                public void completed(final AsyncExecRuntime execRuntime) {
+                    if (log.isDebugEnabled()) {
+                        log.debug(exchangeId + ": connection acquired");
+                    }
+                    execute(exchangeId, route, execRuntime, request, entityProducer, clientContext, asyncExecCallback);
+                }
+
+                @Override
+                public void failed(final Exception ex) {
+                    asyncExecCallback.failed(ex);
+                }
+
+                @Override
+                public void cancelled() {
+                    asyncExecCallback.failed(new InterruptedIOException());
+                }
+
+            });
+        } else {
+            execute(exchangeId, route, execRuntime, request, entityProducer, clientContext, asyncExecCallback);
+        }
+    }
+
+    private void execute(
+            final String exchangeId,
+            final HttpRoute route,
+            final AsyncExecRuntime execRuntime,
+            final HttpRequest request,
+            final AsyncEntityProducer entityProducer,
+            final HttpClientContext clientContext,
+            final AsyncExecCallback asyncExecCallback) {
+
+        if (log.isDebugEnabled()) {
+            log.debug(exchangeId + ": executing " + new RequestLine(request));
+        }
+
+        final AsyncClientExchangeHandler internalExchangeHandler = new AsyncClientExchangeHandler() {
+
+            private final AtomicReference<AsyncDataConsumer> entityConsumerRef = new AtomicReference<>(null);
+
+            @Override
+            public void releaseResources() {
+                final AsyncDataConsumer entityConsumer = entityConsumerRef.getAndSet(null);
+                if (entityConsumer != null) {
+                    entityConsumer.releaseResources();
+                }
+            }
+
+            @Override
+            public void failed(final Exception cause) {
+                execRuntime.markConnectionNonReusable();
+                asyncExecCallback.failed(cause);
+            }
+
+            @Override
+            public void cancel() {
+                failed(new InterruptedIOException());
+            }
+
+            @Override
+            public void produceRequest(final RequestChannel channel) throws HttpException, IOException {
+                channel.sendRequest(request, entityProducer);
+            }
+
+            @Override
+            public int available() {
+                return entityProducer.available();
+            }
+
+            @Override
+            public void produce(final DataStreamChannel channel) throws IOException {
+                entityProducer.produce(channel);
+            }
+
+            @Override
+            public void consumeInformation(final HttpResponse response) throws HttpException, IOException {
+            }
+
+            @Override
+            public void consumeResponse(final HttpResponse response, final EntityDetails entityDetails) throws HttpException, IOException {
+                entityConsumerRef.set(asyncExecCallback.handleResponse(response, entityDetails));
+                execRuntime.markConnectionReusable();
+                final TimeValue duration = keepAliveStrategy.getKeepAliveDuration(response, clientContext);
+                execRuntime.setConnectionValidFor(duration);
+                Object userToken = clientContext.getUserToken();
+                if (userToken == null) {
+                    userToken = userTokenHandler.getUserToken(route, clientContext);
+                    clientContext.setAttribute(HttpClientContext.USER_TOKEN, userToken);
+                }
+                if (userToken != null) {
+                    execRuntime.setConnectionState(userToken);
+                }
+                if (entityDetails == null) {
+                    if (!execRuntime.isConnectionReusable()) {
+                        execRuntime.discardConnection();
+                    } else {
+                        execRuntime.validateConnection();
+                    }
+                }
+            }
+
+            @Override
+            public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
+                final AsyncDataConsumer entityConsumer = entityConsumerRef.get();
+                if (entityConsumer != null) {
+                    entityConsumer.updateCapacity(capacityChannel);
+                } else {
+                    capacityChannel.update(Integer.MAX_VALUE);
+                }
+            }
+
+            @Override
+            public int consume(final ByteBuffer src) throws IOException {
+                final AsyncDataConsumer entityConsumer = entityConsumerRef.get();
+                if (entityConsumer != null) {
+                    return entityConsumer.consume(src);
+                } else {
+                    return Integer.MAX_VALUE;
+                }
+            }
+
+            @Override
+            public void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
+                final AsyncDataConsumer entityConsumer = entityConsumerRef.getAndSet(null);
+                if (entityConsumer != null) {
+                    // Release connection early
+                    execRuntime.releaseConnection();
+                    entityConsumer.streamEnd(trailers);
+                } else {
+                    if (!execRuntime.isConnectionReusable()) {
+                        execRuntime.discardConnection();
+                    } else {
+                        execRuntime.validateConnection();
+                    }
+                }
+                asyncExecCallback.completed();
+            }
+
+        };
+        execRuntime.execute(
+                log.isDebugEnabled() ? new LoggingAsyncClientExchangeHandler(log, exchangeId, internalExchangeHandler) : internalExchangeHandler,
+                clientContext);
+    }
+
+}

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

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

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

Added: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java?rev=1793320&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java (added)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java Mon May  1 12:39:16 2017
@@ -0,0 +1,102 @@
+/*
+ * ====================================================================
+ * 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.async;
+
+import java.io.IOException;
+
+import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.async.AsyncExecCallback;
+import org.apache.hc.client5.http.async.AsyncExecChain;
+import org.apache.hc.client5.http.async.AsyncExecChainHandler;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.client5.http.auth.CredentialsStore;
+import org.apache.hc.client5.http.auth.util.CredentialSupport;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.http.EntityDetails;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.nio.AsyncDataConsumer;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.http.protocol.HttpCoreContext;
+import org.apache.hc.core5.http.protocol.HttpProcessor;
+import org.apache.hc.core5.net.URIAuthority;
+
+class AsyncProtocolExec implements AsyncExecChainHandler {
+
+    private final HttpProcessor httpProcessor;
+
+    AsyncProtocolExec(final HttpProcessor httpProcessor) {
+        this.httpProcessor = httpProcessor;
+    }
+
+    @Override
+    public void execute(
+            final HttpRequest request,
+            final AsyncEntityProducer entityProducer,
+            final AsyncExecChain.Scope scope,
+            final AsyncExecChain chain,
+            final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
+        final HttpRoute route = scope.route;
+        final HttpClientContext clientContext = scope.clientContext;
+        final URIAuthority authority = request.getAuthority();
+        if (authority != null) {
+            final CredentialsProvider credsProvider = clientContext.getCredentialsProvider();
+            if (credsProvider instanceof CredentialsStore) {
+                CredentialSupport.extractFromAuthority(authority, (CredentialsStore) credsProvider);
+            }
+        }
+
+        clientContext.setAttribute(HttpClientContext.HTTP_ROUTE, route);
+        clientContext.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
+        httpProcessor.process(request, entityProducer, clientContext);
+
+        chain.proceed(request, entityProducer, scope, new AsyncExecCallback() {
+
+            @Override
+            public AsyncDataConsumer handleResponse(
+                    final HttpResponse response, final EntityDetails entityDetails) throws HttpException, IOException {
+                clientContext.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
+                httpProcessor.process(response, entityDetails, clientContext);
+
+                return asyncExecCallback.handleResponse(response, entityDetails);
+            }
+
+            @Override
+            public void completed() {
+                asyncExecCallback.completed();
+            }
+
+            @Override
+            public void failed(final Exception cause) {
+                asyncExecCallback.failed(cause);
+            }
+
+        });
+    }
+
+}

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

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

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

Added: httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java?rev=1793320&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java (added)
+++ httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java Mon May  1 12:39:16 2017
@@ -0,0 +1,213 @@
+/*
+ * ====================================================================
+ * 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.async;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+
+import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.StandardMethods;
+import org.apache.hc.client5.http.async.AsyncExecCallback;
+import org.apache.hc.client5.http.async.AsyncExecChain;
+import org.apache.hc.client5.http.async.AsyncExecChainHandler;
+import org.apache.hc.client5.http.auth.AuthExchange;
+import org.apache.hc.client5.http.auth.AuthScheme;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.protocol.RedirectException;
+import org.apache.hc.client5.http.protocol.RedirectStrategy;
+import org.apache.hc.client5.http.routing.HttpRoutePlanner;
+import org.apache.hc.client5.http.utils.URIUtils;
+import org.apache.hc.core5.http.EntityDetails;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.http.nio.AsyncDataConsumer;
+import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+class AsyncRedirectExec implements AsyncExecChainHandler {
+
+    private final Logger log = LogManager.getLogger(getClass());
+
+    private final HttpRoutePlanner routePlanner;
+    private final RedirectStrategy redirectStrategy;
+
+    AsyncRedirectExec(final HttpRoutePlanner routePlanner, final RedirectStrategy redirectStrategy) {
+        this.routePlanner = routePlanner;
+        this.redirectStrategy = redirectStrategy;
+    }
+
+    private static class State {
+
+        volatile URI redirectURI;
+        volatile int maxRedirects;
+        volatile int redirectCount;
+        volatile HttpRequest currentRequest;
+        volatile AsyncEntityProducer currentEntityProducer;
+        volatile AsyncExecChain.Scope currentScope;
+        volatile boolean reroute;
+
+    }
+
+    private void internalExecute(
+            final State state,
+            final AsyncExecChain chain,
+            final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
+
+        final HttpRequest request = state.currentRequest;
+        final AsyncEntityProducer entityProducer = state.currentEntityProducer;
+        final AsyncExecChain.Scope scope = state.currentScope;
+        final HttpClientContext clientContext = scope.clientContext;
+        final HttpRoute currentRoute = scope.route;
+        chain.proceed(request, entityProducer, scope, new AsyncExecCallback() {
+
+            @Override
+            public AsyncDataConsumer handleResponse(
+                    final HttpResponse response,
+                    final EntityDetails entityDetails) throws HttpException, IOException {
+
+                state.redirectURI = null;
+                final RequestConfig config = clientContext.getRequestConfig();
+                if (config.isRedirectsEnabled() && redirectStrategy.isRedirected(request, response, clientContext)) {
+                    if (state.redirectCount >= state.maxRedirects) {
+                        throw new RedirectException("Maximum redirects (" + state.maxRedirects + ") exceeded");
+                    }
+
+                    state.redirectCount++;
+
+                    final URI redirectUri = redirectStrategy.getLocationURI(request, response, clientContext);
+                    final int statusCode = response.getCode();
+
+                    switch (statusCode) {
+                        case HttpStatus.SC_MOVED_PERMANENTLY:
+                        case HttpStatus.SC_MOVED_TEMPORARILY:
+                        case HttpStatus.SC_SEE_OTHER:
+                            if (!StandardMethods.isSafe(request.getMethod())) {
+                                final HttpRequest httpGet = new BasicHttpRequest(StandardMethods.GET.name(), redirectUri);
+                                httpGet.setHeaders(scope.originalRequest.getAllHeaders());
+                                state.currentRequest = httpGet;
+                                state.currentEntityProducer = null;
+                                break;
+                            }
+                        default:
+                            state.currentRequest = new BasicHttpRequest(request.getMethod(), redirectUri);
+                    }
+                    final HttpHost newTarget = URIUtils.extractHost(redirectUri);
+                    if (newTarget == null) {
+                        throw new ProtocolException("Redirect URI does not specify a valid host name: " + redirectUri);
+                    }
+
+                    if (!currentRoute.getTargetHost().equals(newTarget)) {
+                        log.debug("New route required");
+                        state.reroute = true;
+                        final AuthExchange targetAuthExchange = clientContext.getAuthExchange(currentRoute.getTargetHost());
+                        log.debug("Resetting target auth state");
+                        targetAuthExchange.reset();
+                        if (currentRoute.getProxyHost() != null) {
+                            final AuthExchange proxyAuthExchange = clientContext.getAuthExchange(currentRoute.getProxyHost());
+                            final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
+                            if (authScheme != null && authScheme.isConnectionBased()) {
+                                log.debug("Resetting proxy auth state");
+                                proxyAuthExchange.reset();
+                            }
+                        }
+                        final HttpRoute newRoute = routePlanner.determineRoute(newTarget, clientContext);
+                        state.currentScope = new AsyncExecChain.Scope(
+                                scope.exchangeId, newRoute, scope.originalRequest, clientContext, scope.execRuntime);
+                        state.redirectURI = redirectUri;
+                    } else {
+                        state.reroute = false;
+                        state.redirectURI = redirectUri;
+                    }
+                }
+                if (state.redirectURI != null) {
+                    if (log.isDebugEnabled()) {
+                        log.debug(scope.exchangeId + ": redirecting to '" + state.redirectURI + "' via " + currentRoute);
+                    }
+                    return null;
+                } else {
+                    return asyncExecCallback.handleResponse(response, entityDetails);
+                }
+            }
+
+            @Override
+            public void completed() {
+                if (state.redirectURI == null) {
+                    asyncExecCallback.completed();
+                } else {
+                    try {
+                        if (state.reroute) {
+                            scope.execRuntime.releaseConnection();
+                        }
+                        internalExecute(state, chain, asyncExecCallback);
+                    } catch (IOException | HttpException ex) {
+                        asyncExecCallback.failed(ex);
+                    }
+                }
+            }
+
+            @Override
+            public void failed(final Exception cause) {
+                asyncExecCallback.failed(cause);
+            }
+
+        });
+
+    }
+
+    @Override
+    public void execute(
+            final HttpRequest request,
+            final AsyncEntityProducer entityProducer,
+            final AsyncExecChain.Scope scope,
+            final AsyncExecChain chain,
+            final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
+        final HttpClientContext clientContext = scope.clientContext;
+        final List<URI> redirectLocations = clientContext.getRedirectLocations();
+        if (redirectLocations != null) {
+            redirectLocations.clear();
+        }
+        final RequestConfig config = clientContext.getRequestConfig();
+
+        final State state = new State();
+        state.maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
+        state.redirectCount = 0;
+        state.currentRequest = request;
+        state.currentEntityProducer = entityProducer;
+        state.currentScope = scope;
+
+        internalExecute(state, chain, asyncExecCallback);
+    }
+
+}

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

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

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



Mime
View raw message