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 2016/12/04 13:50:00 UTC

svn commit: r1772536 [1/2] - in /httpcomponents/httpcore/trunk: httpcore5-h2/src/examples/ httpcore5-h2/src/examples/org/ httpcore5-h2/src/examples/org/apache/ httpcore5-h2/src/examples/org/apache/hc/ httpcore5-h2/src/examples/org/apache/hc/core5/ http...

Author: olegk
Date: Sun Dec  4 13:49:59 2016
New Revision: 1772536

URL: http://svn.apache.org/viewvc?rev=1772536&view=rev
Log:
Added bootstrap classes for HTTP/2 server and requester; updated examples

Added:
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2FileServerExample.java   (with props)
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2MultiStreamExecutionExample.java
      - copied, changed from r1772441, httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java
    httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2RequestExecutionExample.java
      - copied, changed from r1772441, httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java
    httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/Http2Processors.java   (contents, props changed)
      - copied, changed from r1772441, httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/bootstrap/Http2Processors.java
    httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/
    httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/AsyncPushConsumerRegistry.java   (with props)
    httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java   (with props)
    httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java   (with props)
Removed:
    httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/bootstrap/Http2Processors.java
Modified:
    httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java
    httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java
    httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http/Http1TestClient.java
    httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestClient.java
    httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestServer.java
    httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java
    httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java
    httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncRequestExecutionExample.java
    httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/ClassicGetExecutionExample.java
    httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/ClassicPostExecutionExample.java
    httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/ClassicPostWithTrailersExecutionExample.java
    httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/bootstrap/HttpRequester.java
    httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/bootstrap/HttpServer.java
    httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/bootstrap/AsyncRequester.java
    httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
    httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/BasicRequestProducer.java

Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2FileServerExample.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2FileServerExample.java?rev=1772536&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2FileServerExample.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2FileServerExample.java Sun Dec  4 13:49:59 2016
@@ -0,0 +1,240 @@
+/*
+ * ====================================================================
+ * 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.core5.http.examples;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hc.core5.http.ConnectionClosedException;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.ExceptionListener;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpConnection;
+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;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.impl.ConnectionListener;
+import org.apache.hc.core5.http.impl.nio.bootstrap.HttpAsyncServer;
+import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
+import org.apache.hc.core5.http.nio.BasicRequestConsumer;
+import org.apache.hc.core5.http.nio.BasicResponseProducer;
+import org.apache.hc.core5.http.nio.entity.FileEntityProducer;
+import org.apache.hc.core5.http.nio.entity.NoopEntityConsumer;
+import org.apache.hc.core5.http.nio.support.RequestConsumerSupplier;
+import org.apache.hc.core5.http.nio.support.ResponseHandler;
+import org.apache.hc.core5.http.nio.support.ResponseTrigger;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.http.protocol.HttpCoreContext;
+import org.apache.hc.core5.http2.frame.RawFrame;
+import org.apache.hc.core5.http2.impl.nio.Http2StreamListener;
+import org.apache.hc.core5.http2.impl.nio.bootstrap.H2ServerBootstrap;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.reactor.ListenerEndpoint;
+
+/**
+ * Example of asynchronous embedded HTTP/2 file server.
+ */
+public class Http2FileServerExample {
+
+    public static void main(String[] args) throws Exception {
+        if (args.length < 1) {
+            System.err.println("Please specify document root directory");
+            System.exit(1);
+        }
+        // Document root directory
+        final File docRoot = new File(args[0]);
+        int port = 8080;
+        if (args.length >= 2) {
+            port = Integer.parseInt(args[1]);
+        }
+
+        IOReactorConfig config = IOReactorConfig.custom()
+                .setSoTimeout(15000)
+                .setTcpNoDelay(true)
+                .build();
+
+        final HttpAsyncServer server = H2ServerBootstrap.bootstrap()
+                .setIOReactorConfig(config)
+                .setExceptionListener(new ExceptionListener() {
+
+                    @Override
+                    public void onError(final Exception ex) {
+                        if (ex instanceof ConnectionClosedException) {
+                            return;
+                        }
+                        if (ex instanceof SocketTimeoutException) {
+                            System.out.println("Timeout");
+                        } else if (ex instanceof IOException) {
+                            System.out.println("I/O error: " + ex.getMessage());
+                        } else {
+                            ex.printStackTrace();
+                        }
+                    }
+                })
+                .setConnectionListener(new ConnectionListener() {
+
+                    @Override
+                    public void onConnect(final HttpConnection connection) {
+                        System.out.println(connection + " connected");
+                    }
+
+                    @Override
+                    public void onError(final HttpConnection connection, final Exception ex) {
+                        System.err.println(connection + " error: " + ex.getMessage());
+                    }
+
+                    @Override
+                    public void onDisconnect(final HttpConnection connection) {
+                        System.out.println(connection + " disconnected");
+                    }
+
+                })
+                .setStreamListener(new Http2StreamListener() {
+
+                    @Override
+                    public void onHeaderInput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
+                        for (int i = 0; i < headers.size(); i++) {
+                            System.out.println(connection + " (" + streamId + ") << " + headers.get(i));
+                        }
+                    }
+
+                    @Override
+                    public void onHeaderOutput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
+                        for (int i = 0; i < headers.size(); i++) {
+                            System.out.println(connection + " (" + streamId + ") >> " + headers.get(i));
+                        }
+                    }
+
+                    @Override
+                    public void onFrameInput(final HttpConnection connection, final int streamId, final RawFrame frame) {
+                    }
+
+                    @Override
+                    public void onFrameOutput(final HttpConnection connection, final int streamId, final RawFrame frame) {
+                    }
+
+                    @Override
+                    public void onInputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
+                    }
+
+                    @Override
+                    public void onOutputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
+                    }
+
+                })
+                .register("*", new RequestConsumerSupplier<Message<HttpRequest, Void>>() {
+
+                    @Override
+                    public AsyncRequestConsumer<Message<HttpRequest, Void>> get(
+                            final HttpRequest request,
+                            final HttpContext context) throws HttpException {
+                        return new BasicRequestConsumer<>(new NoopEntityConsumer());
+                    }
+
+                }, new ResponseHandler<Message<HttpRequest, Void>>() {
+
+                    @Override
+                    public void handle(
+                            final Message<HttpRequest, Void> message,
+                            final ResponseTrigger responseTrigger,
+                            final HttpContext context) throws HttpException, IOException {
+                        HttpRequest request = message.getHead();
+                        URI requestUri;
+                        try {
+                            requestUri = request.getUri();
+                        } catch (URISyntaxException ex) {
+                            throw new ProtocolException(ex.getMessage(), ex);
+                        }
+                        String path = requestUri.getPath();
+                        final File file = new File(docRoot, path);
+                        if (!file.exists()) {
+
+                            System.out.println("File " + file.getPath() + " not found");
+                            responseTrigger.submitResponse(new BasicResponseProducer(
+                                    HttpStatus.SC_NOT_FOUND,
+                                    "<html><body><h1>File" + file.getPath() +
+                                            " not found</h1></body></html>",
+                                    ContentType.TEXT_HTML));
+
+                        } else if (!file.canRead() || file.isDirectory()) {
+
+                            System.out.println("Cannot read file " + file.getPath());
+                            responseTrigger.submitResponse(new BasicResponseProducer(
+                                    HttpStatus.SC_FORBIDDEN,
+                                    "<html><body><h1>Access denied</h1></body></html>",
+                                    ContentType.TEXT_HTML));
+
+                        } else {
+
+                            final ContentType contentType;
+                            final String filename = file.getName().toLowerCase(Locale.ROOT);
+                            if (filename.endsWith(".txt")) {
+                                contentType = ContentType.TEXT_PLAIN;
+                            } else if (filename.endsWith(".html") || filename.endsWith(".htm")) {
+                                contentType = ContentType.TEXT_HTML;
+                            } else if (filename.endsWith(".xml")) {
+                                contentType = ContentType.TEXT_XML;
+                            } else {
+                                contentType = ContentType.DEFAULT_BINARY;
+                            }
+
+                            final HttpConnection connection = (HttpConnection) context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
+
+                            System.out.println(connection + " serving file " + file.getPath());
+                            responseTrigger.submitResponse(new BasicResponseProducer(
+                                    HttpStatus.SC_OK, new FileEntityProducer(file, contentType)));
+                        }
+                    }
+
+                })
+                .create();
+
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override
+            public void run() {
+                System.out.println("HTTP server shutting down");
+                server.shutdown(5, TimeUnit.SECONDS);
+            }
+        });
+
+        server.start();
+        ListenerEndpoint listenerEndpoint = server.listen(new InetSocketAddress(port));
+        listenerEndpoint.waitFor();
+        System.out.print("Listening on " + listenerEndpoint.getAddress());
+        server.awaitShutdown(Long.MAX_VALUE, TimeUnit.DAYS);
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2FileServerExample.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2FileServerExample.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2FileServerExample.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2MultiStreamExecutionExample.java (from r1772441, httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2MultiStreamExecutionExample.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2MultiStreamExecutionExample.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java&r1=1772441&r2=1772536&rev=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2MultiStreamExecutionExample.java Sun Dec  4 13:49:59 2016
@@ -26,31 +26,75 @@
  */
 package org.apache.hc.core5.http.examples;
 
-import java.net.URI;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpConnection;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.impl.nio.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.impl.nio.bootstrap.PooledClientEndpoint;
-import org.apache.hc.core5.http.impl.nio.bootstrap.RequesterBootstrap;
 import org.apache.hc.core5.http.nio.BasicRequestProducer;
 import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.frame.RawFrame;
+import org.apache.hc.core5.http2.impl.nio.Http2StreamListener;
+import org.apache.hc.core5.http2.impl.nio.bootstrap.H2RequesterBootstrap;
 
 /**
- * Example of asynchronous HTTP/1.1 request execution.
+ * Example of HTTP/2 concurrent request execution using multiple streams.
  */
-public class AsyncPipelinedRequestExecutionExample {
+public class Http2MultiStreamExecutionExample {
 
     public static void main(String[] args) throws Exception {
 
         // Create and start requester
-        final HttpAsyncRequester requester = RequesterBootstrap.bootstrap().create();
+        H2Config h2Config = H2Config.custom()
+                .setPushEnabled(false)
+                .setMaxConcurrentStreams(100)
+                .build();
+        final HttpAsyncRequester requester = H2RequesterBootstrap.bootstrap()
+                .setH2Config(h2Config)
+                .setStreamListener(new Http2StreamListener() {
+
+                    @Override
+                    public void onHeaderInput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
+                        for (int i = 0; i < headers.size(); i++) {
+                            System.out.println(connection + " (" + streamId + ") << " + headers.get(i));
+                        }
+                    }
+
+                    @Override
+                    public void onHeaderOutput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
+                        for (int i = 0; i < headers.size(); i++) {
+                            System.out.println(connection + " (" + streamId + ") >> " + headers.get(i));
+                        }
+                    }
+
+                    @Override
+                    public void onFrameInput(final HttpConnection connection, final int streamId, final RawFrame frame) {
+                    }
+
+                    @Override
+                    public void onFrameOutput(final HttpConnection connection, final int streamId, final RawFrame frame) {
+                    }
+
+                    @Override
+                    public void onInputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
+                    }
+
+                    @Override
+                    public void onOutputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
+                    }
+
+                })
+                .create();
         Runtime.getRuntime().addShutdownHook(new Thread() {
             @Override
             public void run() {
@@ -60,9 +104,8 @@ public class AsyncPipelinedRequestExecut
         });
         requester.start();
 
-        HttpHost target = new HttpHost("www.apache.org");
-        String[] requestUris = new String[] {"/", "/foundation",
-                "/foundation/how-it-works.html", "/foundation/getinvolved.html"};
+        HttpHost target = new HttpHost("http2bin.org");
+        String[] requestUris = new String[] {"/", "/ip", "/user-agent", "/headers"};
 
         Future<PooledClientEndpoint> future = requester.connect(target, 5, TimeUnit.SECONDS);
         PooledClientEndpoint clientEndpoint = future.get();
@@ -70,7 +113,7 @@ public class AsyncPipelinedRequestExecut
         final CountDownLatch latch = new CountDownLatch(requestUris.length);
         for (final String requestUri: requestUris) {
             clientEndpoint.execute(
-                    new BasicRequestProducer("GET", URI.create(requestUri)),
+                    new BasicRequestProducer("GET", target, requestUri),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()),
                     new FutureCallback<Message<HttpResponse, String>>() {
 
@@ -78,7 +121,9 @@ public class AsyncPipelinedRequestExecut
                         public void completed(final Message<HttpResponse, String> message) {
                             latch.countDown();
                             HttpResponse response = message.getHead();
+                            String body = message.getBody();
                             System.out.println(requestUri + "->" + response.getCode());
+                            System.out.println(body);
                         }
 
                         @Override

Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2RequestExecutionExample.java (from r1772441, httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2RequestExecutionExample.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2RequestExecutionExample.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java&r1=1772441&r2=1772536&rev=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/examples/org/apache/hc/core5/http/examples/Http2RequestExecutionExample.java Sun Dec  4 13:49:59 2016
@@ -26,31 +26,75 @@
  */
 package org.apache.hc.core5.http.examples;
 
-import java.net.URI;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpConnection;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.Message;
 import org.apache.hc.core5.http.impl.nio.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.impl.nio.bootstrap.PooledClientEndpoint;
-import org.apache.hc.core5.http.impl.nio.bootstrap.RequesterBootstrap;
 import org.apache.hc.core5.http.nio.BasicRequestProducer;
 import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.frame.RawFrame;
+import org.apache.hc.core5.http2.impl.nio.Http2StreamListener;
+import org.apache.hc.core5.http2.impl.nio.bootstrap.H2RequesterBootstrap;
 
 /**
- * Example of asynchronous HTTP/1.1 request execution.
+ * Example of HTTP/2 request execution.
  */
-public class AsyncPipelinedRequestExecutionExample {
+public class Http2RequestExecutionExample {
 
     public static void main(String[] args) throws Exception {
 
         // Create and start requester
-        final HttpAsyncRequester requester = RequesterBootstrap.bootstrap().create();
+        H2Config h2Config = H2Config.custom()
+                .setPushEnabled(false)
+                .build();
+
+        final HttpAsyncRequester requester = H2RequesterBootstrap.bootstrap()
+                .setH2Config(h2Config)
+                .setStreamListener(new Http2StreamListener() {
+
+                    @Override
+                    public void onHeaderInput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
+                        for (int i = 0; i < headers.size(); i++) {
+                            System.out.println(connection + " (" + streamId + ") << " + headers.get(i));
+                        }
+                    }
+
+                    @Override
+                    public void onHeaderOutput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
+                        for (int i = 0; i < headers.size(); i++) {
+                            System.out.println(connection + " (" + streamId + ") >> " + headers.get(i));
+                        }
+                    }
+
+                    @Override
+                    public void onFrameInput(final HttpConnection connection, final int streamId, final RawFrame frame) {
+                    }
+
+                    @Override
+                    public void onFrameOutput(final HttpConnection connection, final int streamId, final RawFrame frame) {
+                    }
+
+                    @Override
+                    public void onInputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
+                    }
+
+                    @Override
+                    public void onOutputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
+                    }
+
+                })
+                .create();
         Runtime.getRuntime().addShutdownHook(new Thread() {
             @Override
             public void run() {
@@ -60,17 +104,15 @@ public class AsyncPipelinedRequestExecut
         });
         requester.start();
 
-        HttpHost target = new HttpHost("www.apache.org");
-        String[] requestUris = new String[] {"/", "/foundation",
-                "/foundation/how-it-works.html", "/foundation/getinvolved.html"};
-
-        Future<PooledClientEndpoint> future = requester.connect(target, 5, TimeUnit.SECONDS);
-        PooledClientEndpoint clientEndpoint = future.get();
+        HttpHost target = new HttpHost("http2bin.org");
+        String[] requestUris = new String[] {"/", "/ip", "/user-agent", "/headers"};
 
         final CountDownLatch latch = new CountDownLatch(requestUris.length);
         for (final String requestUri: requestUris) {
-            clientEndpoint.execute(
-                    new BasicRequestProducer("GET", URI.create(requestUri)),
+            final Future<PooledClientEndpoint> future = requester.connect(target, 5, TimeUnit.SECONDS);
+            final PooledClientEndpoint clientEndpoint = future.get();
+            clientEndpoint.executeAndRelease(
+                    new BasicRequestProducer("GET", target, requestUri),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()),
                     new FutureCallback<Message<HttpResponse, String>>() {
 
@@ -78,7 +120,9 @@ public class AsyncPipelinedRequestExecut
                         public void completed(final Message<HttpResponse, String> message) {
                             latch.countDown();
                             HttpResponse response = message.getHead();
+                            String body = message.getBody();
                             System.out.println(requestUri + "->" + response.getCode());
+                            System.out.println(body);
                         }
 
                         @Override
@@ -97,10 +141,6 @@ public class AsyncPipelinedRequestExecut
         }
 
         latch.await();
-
-        // Manually release client endpoint when done !!!
-        clientEndpoint.releaseResources();
-
         System.out.println("Shutting down I/O reactor");
         requester.initiateShutdown();
     }

Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/Http2Processors.java (from r1772441, httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/bootstrap/Http2Processors.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/Http2Processors.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/Http2Processors.java&p1=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/bootstrap/Http2Processors.java&r1=1772441&r2=1772536&rev=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/bootstrap/Http2Processors.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/Http2Processors.java Sun Dec  4 13:49:59 2016
@@ -24,7 +24,7 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.core5.http2.bootstrap;
+package org.apache.hc.core5.http2.impl;
 
 import org.apache.hc.core5.http.impl.HttpProcessors;
 import org.apache.hc.core5.http.protocol.HttpProcessor;

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/Http2Processors.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/Http2Processors.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/Http2Processors.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java?rev=1772536&r1=1772535&r2=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractHttp2StreamMultiplexer.java Sun Dec  4 13:49:59 2016
@@ -178,7 +178,7 @@ abstract class AbstractHttp2StreamMultip
             final int streamId, final AtomicInteger window, final int delta) throws ArithmeticException {
         final int newSize = updateWindow(window, delta);
         if (streamListener != null) {
-            streamListener.onInputFlowControl(streamId, delta, newSize);
+            streamListener.onInputFlowControl(this, streamId, delta, newSize);
         }
         return newSize;
     }
@@ -187,7 +187,7 @@ abstract class AbstractHttp2StreamMultip
             final int streamId, final AtomicInteger window, final int delta) throws ArithmeticException {
         final int newSize = updateWindow(window, delta);
         if (streamListener != null) {
-            streamListener.onOutputFlowControl(streamId, delta, newSize);
+            streamListener.onOutputFlowControl(this, streamId, delta, newSize);
         }
         return newSize;
     }
@@ -195,7 +195,7 @@ abstract class AbstractHttp2StreamMultip
     private void commitFrameInternal(final RawFrame frame) throws IOException {
         if (outputBuffer.isEmpty() && outputQueue.isEmpty()) {
             if (streamListener != null) {
-                streamListener.onFrameOutput(frame);
+                streamListener.onFrameOutput(this, frame.getStreamId(), frame);
             }
             outputBuffer.write(frame, ioSession.channel());
         } else {
@@ -217,7 +217,7 @@ abstract class AbstractHttp2StreamMultip
     private void commitHeaders(
             final int streamId, final List<? extends Header> headers, final boolean endStream) throws IOException {
         if (streamListener != null) {
-            streamListener.onHeaderOutput(headers);
+            streamListener.onHeaderOutput(this, streamId, headers);
         }
         final ByteArrayBuffer buf = new ByteArrayBuffer(512);
         hPackEncoder.encodeHeaders(buf, headers);
@@ -251,7 +251,7 @@ abstract class AbstractHttp2StreamMultip
             throw new H2ConnectionException(H2Error.INTERNAL_ERROR, "Message headers are missing");
         }
         if (streamListener != null) {
-            streamListener.onHeaderOutput(headers);
+            streamListener.onHeaderOutput(this, streamId, headers);
         }
         final ByteArrayBuffer buf = new ByteArrayBuffer(512);
         buf.append((byte)(promisedStreamId >> 24));
@@ -298,7 +298,7 @@ abstract class AbstractHttp2StreamMultip
                 chunk = payload.remaining();
                 final RawFrame dataFrame = frameFactory.createData(streamId, payload, false);
                 if (streamListener != null) {
-                    streamListener.onFrameOutput(dataFrame);
+                    streamListener.onFrameOutput(this, streamId, dataFrame);
                 }
                 outputBuffer.write(dataFrame, ioSession.channel());
             } else {
@@ -308,7 +308,7 @@ abstract class AbstractHttp2StreamMultip
                     payload.limit(payload.position() + chunk);
                     final RawFrame dataFrame = frameFactory.createData(streamId, payload, false);
                     if (streamListener != null) {
-                        streamListener.onFrameOutput(dataFrame);
+                        streamListener.onFrameOutput(this, streamId, dataFrame);
                     }
                     outputBuffer.write(dataFrame, ioSession.channel());
                 } finally {
@@ -387,7 +387,7 @@ abstract class AbstractHttp2StreamMultip
             RawFrame frame;
             while ((frame = inputBuffer.read(ioSession.channel())) != null) {
                 if (streamListener != null) {
-                    streamListener.onFrameInput(frame);
+                    streamListener.onFrameInput(this, frame.getStreamId(), frame);
                 }
                 consumeFrame(frame);
             }
@@ -404,7 +404,7 @@ abstract class AbstractHttp2StreamMultip
                 final RawFrame frame = outputQueue.poll();
                 if (frame != null) {
                     if (streamListener != null) {
-                        streamListener.onFrameOutput(frame);
+                        streamListener.onFrameOutput(this, frame.getStreamId(), frame);
                     }
                     outputBuffer.write(frame, ioSession.channel());
                 } else {
@@ -907,7 +907,7 @@ abstract class AbstractHttp2StreamMultip
                 processedRemoteStreamId = promisedStreamId;
             }
             if (streamListener != null) {
-                streamListener.onHeaderInput(headers);
+                streamListener.onHeaderInput(this, promisedStreamId, headers);
             }
             if (connState == ConnectionHandshake.GRACEFUL_SHUTDOWN) {
                 throw new H2StreamResetException(H2Error.REFUSED_STREAM, "Stream refused");
@@ -935,7 +935,7 @@ abstract class AbstractHttp2StreamMultip
                 processedRemoteStreamId = streamId;
             }
             if (streamListener != null) {
-                streamListener.onHeaderInput(headers);
+                streamListener.onHeaderInput(this, streamId, headers);
             }
             if (connState == ConnectionHandshake.GRACEFUL_SHUTDOWN) {
                 throw new H2StreamResetException(H2Error.PROTOCOL_ERROR, "Stream refused");
@@ -965,7 +965,7 @@ abstract class AbstractHttp2StreamMultip
                 processedRemoteStreamId = streamId;
             }
             if (streamListener != null) {
-                streamListener.onHeaderInput(headers);
+                streamListener.onHeaderInput(this, streamId, headers);
             }
             if (connState == ConnectionHandshake.GRACEFUL_SHUTDOWN) {
                 throw new H2StreamResetException(H2Error.PROTOCOL_ERROR, "Stream refused");

Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java?rev=1772536&r1=1772535&r2=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/Http2StreamListener.java Sun Dec  4 13:49:59 2016
@@ -31,6 +31,7 @@ import java.util.List;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpConnection;
 import org.apache.hc.core5.http2.frame.RawFrame;
 
 /**
@@ -41,16 +42,16 @@ import org.apache.hc.core5.http2.frame.R
 @Contract(threading = ThreadingBehavior.STATELESS)
 public interface Http2StreamListener {
 
-    void onHeaderInput(List<? extends Header> headers);
+    void onHeaderInput(HttpConnection connection, int streamId, List<? extends Header> headers);
 
-    void onHeaderOutput(List<? extends Header> headers);
+    void onHeaderOutput(HttpConnection connection, int streamId, List<? extends Header> headers);
 
-    void onFrameInput(RawFrame frame);
+    void onFrameInput(HttpConnection connection, int streamId, RawFrame frame);
 
-    void onFrameOutput(RawFrame frame);
+    void onFrameOutput(HttpConnection connection, int streamId, RawFrame frame);
 
-    void onInputFlowControl(int streamId, int delta, int actualSize);
+    void onInputFlowControl(HttpConnection connection, int streamId, int delta, int actualSize);
 
-    void onOutputFlowControl(int streamId, int delta, int actualSize);
+    void onOutputFlowControl(HttpConnection connection, int streamId, int delta, int actualSize);
 
 }

Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/AsyncPushConsumerRegistry.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/AsyncPushConsumerRegistry.java?rev=1772536&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/AsyncPushConsumerRegistry.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/AsyncPushConsumerRegistry.java Sun Dec  4 13:49:59 2016
@@ -0,0 +1,103 @@
+/*
+ * ====================================================================
+ * 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.core5.http2.impl.nio.bootstrap;
+
+import java.util.Locale;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.hc.core5.function.Supplier;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.nio.AsyncPushConsumer;
+import org.apache.hc.core5.http.nio.HandlerFactory;
+import org.apache.hc.core5.http.protocol.UriPatternMatcher;
+import org.apache.hc.core5.net.URIAuthority;
+import org.apache.hc.core5.util.Args;
+
+public class AsyncPushConsumerRegistry implements HandlerFactory<AsyncPushConsumer> {
+
+    private final UriPatternMatcher<Supplier<AsyncPushConsumer>> primary;
+    private final ConcurrentMap<String, UriPatternMatcher<Supplier<AsyncPushConsumer>>> hostMap;
+
+    public AsyncPushConsumerRegistry() {
+        this.primary = new UriPatternMatcher<>();
+        this.hostMap = new ConcurrentHashMap<>();
+    }
+
+    private UriPatternMatcher<Supplier<AsyncPushConsumer>> getPatternMatcher(final String hostname) {
+        if (hostname == null) {
+            return primary;
+        }
+        final UriPatternMatcher<Supplier<AsyncPushConsumer>> hostMatcher = hostMap.get(hostname);
+        if (hostMatcher != null) {
+            return hostMatcher;
+        }
+        return primary;
+    }
+
+    @Override
+    public AsyncPushConsumer create(final HttpRequest request) throws HttpException {
+        final URIAuthority authority = request.getAuthority();
+        final String key = authority != null ? authority.getHostName().toLowerCase(Locale.ROOT) : null;
+        final UriPatternMatcher<Supplier<AsyncPushConsumer>> patternMatcher = getPatternMatcher(key);
+        if (patternMatcher == null) {
+            return null;
+        }
+        String path = request.getPath();
+        final int i = path.indexOf("?");
+        if (i != -1) {
+            path = path.substring(0, i - 1);
+        }
+        final Supplier<AsyncPushConsumer> supplier = patternMatcher.lookup(path);
+        if (supplier != null) {
+            return supplier.get();
+        }
+        return null;
+    }
+
+    public void register(final String hostname, final String uriPattern, final Supplier<AsyncPushConsumer> supplier) {
+        Args.notBlank(uriPattern, "URI pattern");
+        Args.notNull(supplier, "Supplier");
+        if (hostname == null) {
+            primary.register(uriPattern, supplier);
+        } else {
+            final String key = hostname.toLowerCase(Locale.ROOT);
+            UriPatternMatcher<Supplier<AsyncPushConsumer>> matcher = hostMap.get(key);
+            if (matcher == null) {
+                final UriPatternMatcher<Supplier<AsyncPushConsumer>> newMatcher = new UriPatternMatcher<>();
+                matcher = hostMap.putIfAbsent(key, newMatcher);
+                if (matcher == null) {
+                    matcher = newMatcher;
+                }
+            }
+            matcher.register(uriPattern, supplier);
+        }
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/AsyncPushConsumerRegistry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/AsyncPushConsumerRegistry.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/AsyncPushConsumerRegistry.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java?rev=1772536&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java Sun Dec  4 13:49:59 2016
@@ -0,0 +1,210 @@
+/*
+ * ====================================================================
+ * 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.core5.http2.impl.nio.bootstrap;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hc.core5.function.Supplier;
+import org.apache.hc.core5.http.ExceptionListener;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.impl.ConnectionListener;
+import org.apache.hc.core5.http.impl.nio.bootstrap.ClientEndpoint;
+import org.apache.hc.core5.http.impl.nio.bootstrap.HttpAsyncRequester;
+import org.apache.hc.core5.http.nio.AsyncPushConsumer;
+import org.apache.hc.core5.http.protocol.HttpProcessor;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.impl.Http2Processors;
+import org.apache.hc.core5.http2.impl.nio.ClientHttpProtocolNegotiatorFactory;
+import org.apache.hc.core5.http2.impl.nio.Http2StreamListener;
+import org.apache.hc.core5.pool.ConnPoolListener;
+import org.apache.hc.core5.pool.StrictConnPool;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * @since 5.0
+ */
+public class H2RequesterBootstrap {
+
+    private final List<PushConsumerEntry> pushConsumerList;
+
+    private IOReactorConfig ioReactorConfig;
+    private HttpProcessor httpProcessor;
+    private Charset charset;
+    private H2Config h2Config;
+    private int defaultMaxPerRoute;
+    private int maxTotal;
+    private long timeToLive;
+    private TimeUnit timeUnit;
+    private ExceptionListener exceptionListener;
+    private ConnectionListener connectionListener;
+    private Http2StreamListener streamListener;
+    private ConnPoolListener<HttpHost> connPoolListener;
+
+    private H2RequesterBootstrap() {
+        this.pushConsumerList = new ArrayList<>();
+    }
+
+    public static H2RequesterBootstrap bootstrap() {
+        return new H2RequesterBootstrap();
+    }
+
+    /**
+     * Sets I/O reactor configuration.
+     */
+    public final H2RequesterBootstrap setIOReactorConfig(final IOReactorConfig ioReactorConfig) {
+        this.ioReactorConfig = ioReactorConfig;
+        return this;
+    }
+
+    /**
+     * Assigns {@link HttpProcessor} instance.
+     */
+    public final H2RequesterBootstrap setHttpProcessor(final HttpProcessor httpProcessor) {
+        this.httpProcessor = httpProcessor;
+        return this;
+    }
+
+    /**
+     * Sets HTTP/2 protocol parameters
+     */
+    public final H2RequesterBootstrap setH2Config(final H2Config h2Config) {
+        this.h2Config = h2Config;
+        return this;
+    }
+
+    /**
+     * Sets charset for HTTP/2 messages.
+     */
+    public final H2RequesterBootstrap setCharset(final Charset charset) {
+        this.charset = charset;
+        return this;
+    }
+
+    public final H2RequesterBootstrap setDefaultMaxPerRoute(final int defaultMaxPerRoute) {
+        this.defaultMaxPerRoute = defaultMaxPerRoute;
+        return this;
+    }
+
+    public final H2RequesterBootstrap setMaxTotal(final int maxTotal) {
+        this.maxTotal = maxTotal;
+        return this;
+    }
+
+    public final H2RequesterBootstrap setTimeToLive(final long timeToLive, final TimeUnit timeUnit) {
+        this.timeToLive = timeToLive;
+        this.timeUnit = timeUnit;
+        return this;
+    }
+
+    /**
+     * Assigns {@link ExceptionListener} instance.
+     */
+    public final H2RequesterBootstrap setExceptionListener(final ExceptionListener exceptionListener) {
+        this.exceptionListener = exceptionListener;
+        return this;
+    }
+
+    /**
+     * Assigns {@link ConnectionListener} instance.
+     */
+    public final H2RequesterBootstrap setConnectionListener(final ConnectionListener connectionListener) {
+        this.connectionListener = connectionListener;
+        return this;
+    }
+
+    /**
+     * Assigns {@link Http2StreamListener} instance.
+     */
+    public final H2RequesterBootstrap setStreamListener(final Http2StreamListener streamListener) {
+        this.streamListener = streamListener;
+        return this;
+    }
+
+    public final H2RequesterBootstrap setConnPoolListener(final ConnPoolListener<HttpHost> connPoolListener) {
+        this.connPoolListener = connPoolListener;
+        return this;
+    }
+
+    public final H2RequesterBootstrap register(final String uriPattern, final Supplier<AsyncPushConsumer> supplier) {
+        Args.notBlank(uriPattern, "URI pattern");
+        Args.notNull(supplier, "Supplier");
+        pushConsumerList.add(new PushConsumerEntry(null, uriPattern, supplier));
+        return this;
+    }
+
+    public final H2RequesterBootstrap register(final String hostname, final String uriPattern, final Supplier<AsyncPushConsumer> supplier) {
+        Args.notBlank(hostname, "Hostname");
+        Args.notBlank(uriPattern, "URI pattern");
+        Args.notNull(supplier, "Supplier");
+        pushConsumerList.add(new PushConsumerEntry(hostname, uriPattern, supplier));
+        return this;
+    }
+
+    public HttpAsyncRequester create() {
+        final StrictConnPool<HttpHost, ClientEndpoint> connPool = new StrictConnPool<>(
+                defaultMaxPerRoute > 0 ? defaultMaxPerRoute : 20,
+                maxTotal > 0 ? maxTotal : 50,
+                timeToLive, timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS,
+                connPoolListener);
+        final AsyncPushConsumerRegistry pushConsumerRegistry = new AsyncPushConsumerRegistry();
+        for (PushConsumerEntry entry: pushConsumerList) {
+            pushConsumerRegistry.register(entry.hostname, entry.uriPattern, entry.supplier);
+        }
+        final ClientHttpProtocolNegotiatorFactory ioEventHandlerFactory = new ClientHttpProtocolNegotiatorFactory(
+                httpProcessor != null ? httpProcessor : Http2Processors.client(),
+                pushConsumerRegistry,
+                charset != null ? charset : StandardCharsets.US_ASCII,
+                h2Config != null ? h2Config : H2Config.DEFAULT,
+                connectionListener,
+                streamListener);
+        return new HttpAsyncRequester(
+                ioReactorConfig,
+                exceptionListener,
+                ioEventHandlerFactory,
+                connPool);
+    }
+
+    private static class PushConsumerEntry {
+
+        final String hostname;
+        final String uriPattern;
+        final Supplier<AsyncPushConsumer> supplier;
+
+        public PushConsumerEntry(final String hostname, final String uriPattern, final Supplier<AsyncPushConsumer> supplier) {
+            this.hostname = hostname;
+            this.uriPattern = uriPattern;
+            this.supplier = supplier;
+        }
+
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java?rev=1772536&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java Sun Dec  4 13:49:59 2016
@@ -0,0 +1,220 @@
+/*
+ * ====================================================================
+ * 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.core5.http2.impl.nio.bootstrap;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.hc.core5.function.Supplier;
+import org.apache.hc.core5.http.ExceptionListener;
+import org.apache.hc.core5.http.impl.ConnectionListener;
+import org.apache.hc.core5.http.impl.nio.bootstrap.AsyncServerExchangeHandlerRegistry;
+import org.apache.hc.core5.http.impl.nio.bootstrap.HttpAsyncServer;
+import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
+import org.apache.hc.core5.http.nio.support.BasicServerExchangeHandler;
+import org.apache.hc.core5.http.nio.support.RequestConsumerSupplier;
+import org.apache.hc.core5.http.nio.support.ResponseHandler;
+import org.apache.hc.core5.http.protocol.HttpProcessor;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.impl.Http2Processors;
+import org.apache.hc.core5.http2.impl.nio.Http2StreamListener;
+import org.apache.hc.core5.http2.impl.nio.ServerHttpProtocolNegotiatorFactory;
+import org.apache.hc.core5.net.InetAddressUtils;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * @since 5.0
+ */
+public class H2ServerBootstrap {
+
+    private final List<HandlerEntry> handlerList;
+    private String canonicalHostName;
+    private IOReactorConfig ioReactorConfig;
+    private HttpProcessor httpProcessor;
+    private Charset charset;
+    private H2Config h2Config;
+    private ExceptionListener exceptionListener;
+    private ConnectionListener connectionListener;
+    private Http2StreamListener streamListener;
+
+    private H2ServerBootstrap() {
+        this.handlerList = new ArrayList<>();
+    }
+
+    public static H2ServerBootstrap bootstrap() {
+        return new H2ServerBootstrap();
+    }
+
+    /**
+     * Sets canonical name (fully qualified domain name) of the server.
+     *
+     * @since 5.0
+     */
+    public final H2ServerBootstrap setCanonicalHostName(final String canonicalHostName) {
+        this.canonicalHostName = canonicalHostName;
+        return this;
+    }
+
+    /**
+     * Sets I/O reactor configuration.
+     */
+    public final H2ServerBootstrap setIOReactorConfig(final IOReactorConfig ioReactorConfig) {
+        this.ioReactorConfig = ioReactorConfig;
+        return this;
+    }
+
+    /**
+     * Assigns {@link HttpProcessor} instance.
+     */
+    public final H2ServerBootstrap setHttpProcessor(final HttpProcessor httpProcessor) {
+        this.httpProcessor = httpProcessor;
+        return this;
+    }
+
+    /**
+     * Sets HTTP/2 protocol parameters
+     */
+    public final H2ServerBootstrap  setH2Config(final H2Config h2Config) {
+        this.h2Config = h2Config;
+        return this;
+    }
+
+    /**
+     * Sets charset for HTTP/2 messages.
+     */
+    public final H2ServerBootstrap  setCharset(final Charset charset) {
+        this.charset = charset;
+        return this;
+    }
+
+    /**
+     * Assigns {@link ExceptionListener} instance.
+     */
+    public final H2ServerBootstrap setExceptionListener(final ExceptionListener exceptionListener) {
+        this.exceptionListener = exceptionListener;
+        return this;
+    }
+
+    /**
+     * Assigns {@link ConnectionListener} instance.
+     */
+    public final H2ServerBootstrap setConnectionListener(final ConnectionListener connectionListener) {
+        this.connectionListener = connectionListener;
+        return this;
+    }
+
+    /**
+     * Assigns {@link Http2StreamListener} instance.
+     */
+    public final H2ServerBootstrap setStreamListener(final Http2StreamListener streamListener) {
+        this.streamListener = streamListener;
+        return this;
+    }
+
+    public final H2ServerBootstrap register(final String uriPattern, final Supplier<AsyncServerExchangeHandler> supplier) {
+        Args.notBlank(uriPattern, "URI pattern");
+        Args.notNull(supplier, "Supplier");
+        handlerList.add(new HandlerEntry(null, uriPattern, supplier));
+        return this;
+    }
+
+    public final H2ServerBootstrap registerVirtual(final String hostname, final String uriPattern, final Supplier<AsyncServerExchangeHandler> supplier) {
+        Args.notBlank(hostname, "Hostname");
+        Args.notBlank(uriPattern, "URI pattern");
+        Args.notNull(supplier, "Supplier");
+        handlerList.add(new HandlerEntry(hostname, uriPattern, supplier));
+        return this;
+    }
+
+    public final <T> H2ServerBootstrap register(
+            final String uriPattern,
+            final RequestConsumerSupplier<T> consumerSupplier,
+            final ResponseHandler<T> responseHandler) {
+        register(uriPattern, new Supplier<AsyncServerExchangeHandler>() {
+
+            @Override
+            public AsyncServerExchangeHandler get() {
+                return new BasicServerExchangeHandler<>(consumerSupplier, responseHandler);
+            }
+
+        });
+        return this;
+    }
+
+    public final <T> H2ServerBootstrap registerVirtual(
+            final String hostname,
+            final String uriPattern,
+            final RequestConsumerSupplier<T> consumerSupplier,
+            final ResponseHandler<T> responseHandler) {
+        registerVirtual(hostname, uriPattern, new Supplier<AsyncServerExchangeHandler>() {
+
+            @Override
+            public AsyncServerExchangeHandler get() {
+                return new BasicServerExchangeHandler<>(consumerSupplier, responseHandler);
+            }
+
+        });
+        return this;
+    }
+
+    public HttpAsyncServer create() {
+        final AsyncServerExchangeHandlerRegistry exchangeHandlerFactory = new AsyncServerExchangeHandlerRegistry(
+                canonicalHostName != null ? canonicalHostName : InetAddressUtils.getCanonicalLocalHostName());
+        for (HandlerEntry entry: handlerList) {
+            exchangeHandlerFactory.register(entry.hostname, entry.uriPattern, entry.supplier);
+        }
+        final ServerHttpProtocolNegotiatorFactory ioEventHandlerFactory = new ServerHttpProtocolNegotiatorFactory(
+                httpProcessor != null ? httpProcessor : Http2Processors.server(),
+                exchangeHandlerFactory,
+                charset != null ? charset : StandardCharsets.US_ASCII,
+                h2Config != null ? h2Config : H2Config.DEFAULT,
+                connectionListener,
+                streamListener);
+        return new HttpAsyncServer(
+                ioEventHandlerFactory,
+                ioReactorConfig,
+                exceptionListener);
+    }
+
+    private static class HandlerEntry {
+
+        final String hostname;
+        final String uriPattern;
+        final Supplier<AsyncServerExchangeHandler> supplier;
+
+        public HandlerEntry(final String hostname, final String uriPattern, final Supplier<AsyncServerExchangeHandler> supplier) {
+            this.hostname = hostname;
+            this.uriPattern = uriPattern;
+            this.supplier = supplier;
+        }
+
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http/Http1TestClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http/Http1TestClient.java?rev=1772536&r1=1772535&r2=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http/Http1TestClient.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http/Http1TestClient.java Sun Dec  4 13:49:59 2016
@@ -43,12 +43,11 @@ import org.apache.hc.core5.http.config.C
 import org.apache.hc.core5.http.config.H1Config;
 import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
 import org.apache.hc.core5.http.impl.HttpProcessors;
-import org.apache.hc.core5.http.impl.nio.bootstrap.ClientEndpoint;
 import org.apache.hc.core5.http.impl.nio.bootstrap.AsyncRequester;
+import org.apache.hc.core5.http.impl.nio.bootstrap.ClientEndpoint;
 import org.apache.hc.core5.http.nio.command.ShutdownCommand;
 import org.apache.hc.core5.http.nio.command.ShutdownType;
 import org.apache.hc.core5.http.protocol.HttpProcessor;
-import org.apache.hc.core5.net.NamedEndpoint;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.SessionRequest;
@@ -109,20 +108,20 @@ public class Http1TestClient extends Asy
 
     @Override
     public SessionRequest requestSession(
-            final NamedEndpoint remoteEndpoint,
+            final HttpHost host,
             final long timeout,
             final TimeUnit timeUnit,
             final SessionRequestCallback callback) {
-        return super.requestSession(remoteEndpoint, timeout, timeUnit, callback);
+        return super.requestSession(host, timeout, timeUnit, callback);
     }
 
     public Future<ClientEndpoint> connect(
-            final NamedEndpoint remoteEndpoint,
+            final HttpHost host,
             final long timeout,
             final TimeUnit timeUnit,
             final FutureCallback<ClientEndpoint> callback) throws InterruptedException {
         final BasicFuture<ClientEndpoint> future = new BasicFuture<>(callback);
-        requestSession(remoteEndpoint, timeout, timeUnit, new SessionRequestCallback() {
+        requestSession(host, timeout, timeUnit, new SessionRequestCallback() {
 
             @Override
             public void completed(final SessionRequest request) {
@@ -149,10 +148,10 @@ public class Http1TestClient extends Asy
     }
 
     public Future<ClientEndpoint> connect(
-            final NamedEndpoint remoteEndpoint,
+            final HttpHost host,
             final long timeout,
             final TimeUnit timeUnit) throws InterruptedException {
-        return connect(remoteEndpoint, timeout, timeUnit, null);
+        return connect(host, timeout, timeUnit, null);
     }
 
     public Future<ClientEndpoint> connect(

Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestClient.java?rev=1772536&r1=1772535&r2=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestClient.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestClient.java Sun Dec  4 13:49:59 2016
@@ -40,22 +40,16 @@ import org.apache.hc.core5.concurrent.Fu
 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.HttpException;
 import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpRequest;
-import org.apache.hc.core5.http.MisdirectedRequestException;
-import org.apache.hc.core5.http.impl.nio.bootstrap.ClientEndpoint;
 import org.apache.hc.core5.http.impl.nio.bootstrap.AsyncRequester;
+import org.apache.hc.core5.http.impl.nio.bootstrap.ClientEndpoint;
 import org.apache.hc.core5.http.nio.AsyncPushConsumer;
-import org.apache.hc.core5.http.nio.HandlerFactory;
 import org.apache.hc.core5.http.nio.command.ShutdownCommand;
 import org.apache.hc.core5.http.nio.command.ShutdownType;
 import org.apache.hc.core5.http.protocol.HttpProcessor;
-import org.apache.hc.core5.http.protocol.UriPatternMatcher;
-import org.apache.hc.core5.http2.bootstrap.Http2Processors;
 import org.apache.hc.core5.http2.config.H2Config;
-import org.apache.hc.core5.net.NamedEndpoint;
-import org.apache.hc.core5.net.URIAuthority;
+import org.apache.hc.core5.http2.impl.Http2Processors;
+import org.apache.hc.core5.http2.impl.nio.bootstrap.AsyncPushConsumerRegistry;
 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.reactor.IOSession;
@@ -68,7 +62,7 @@ import org.apache.logging.log4j.Logger;
 public class Http2TestClient extends AsyncRequester {
 
     private final SSLContext sslContext;
-    private final UriPatternMatcher<Supplier<AsyncPushConsumer>> pushHandlerMatcher;
+    private final AsyncPushConsumerRegistry pushConsumerRegistry;
 
     public Http2TestClient(final IOReactorConfig ioReactorConfig, final SSLContext sslContext) throws IOException {
         super(ioReactorConfig, new ExceptionListener() {
@@ -89,36 +83,17 @@ public class Http2TestClient extends Asy
 
         });
         this.sslContext = sslContext;
-        this.pushHandlerMatcher = new UriPatternMatcher<>();
+        this.pushConsumerRegistry = new AsyncPushConsumerRegistry();
     }
 
     public Http2TestClient() throws IOException {
         this(IOReactorConfig.DEFAULT, null);
     }
 
-    private AsyncPushConsumer createHandler(final HttpRequest request) throws HttpException {
-
-        final URIAuthority authority = request.getAuthority();
-        if (authority != null && !"localhost".equalsIgnoreCase(authority.getHostName())) {
-            throw new MisdirectedRequestException("Not authoritative");
-        }
-        String path = request.getPath();
-        final int i = path.indexOf("?");
-        if (i != -1) {
-            path = path.substring(0, i - 1);
-        }
-        final Supplier<AsyncPushConsumer> supplier = pushHandlerMatcher.lookup(path);
-        if (supplier != null) {
-            return supplier.get();
-        } else {
-            return null;
-        }
-    }
-
     public void register(final String uriPattern, final Supplier<AsyncPushConsumer> supplier) {
         Args.notNull(uriPattern, "URI pattern");
         Args.notNull(supplier, "Supplier");
-        pushHandlerMatcher.register(uriPattern, supplier);
+        pushConsumerRegistry.register(null, uriPattern, supplier);
     }
 
     public void start(final IOEventHandlerFactory handlerFactory) throws IOException {
@@ -128,14 +103,7 @@ public class Http2TestClient extends Asy
     public void start(final HttpProcessor httpProcessor, final H2Config h2Config) throws IOException {
         start(new InternalClientHttp2EventHandlerFactory(
                 httpProcessor,
-                new HandlerFactory<AsyncPushConsumer>() {
-
-                    @Override
-                    public AsyncPushConsumer create(final HttpRequest request) throws HttpException {
-                        return createHandler(request);
-                    }
-
-                },
+                pushConsumerRegistry,
                 StandardCharsets.US_ASCII,
                 h2Config,
                 sslContext));
@@ -150,12 +118,12 @@ public class Http2TestClient extends Asy
     }
 
     public Future<ClientEndpoint> connect(
-            final NamedEndpoint remoteEndpoint,
+            final HttpHost host,
             final long timeout,
             final TimeUnit timeUnit,
             final FutureCallback<ClientEndpoint> callback) throws InterruptedException {
         final BasicFuture<ClientEndpoint> future = new BasicFuture<>(callback);
-        requestSession(remoteEndpoint, timeout, timeUnit, new SessionRequestCallback() {
+        requestSession(host, timeout, timeUnit, new SessionRequestCallback() {
 
             @Override
             public void completed(final SessionRequest request) {
@@ -182,10 +150,10 @@ public class Http2TestClient extends Asy
     }
 
     public Future<ClientEndpoint> connect(
-            final NamedEndpoint remoteEndpoint,
+            final HttpHost host,
             final long timeout,
             final TimeUnit timeUnit) throws InterruptedException {
-        return connect(remoteEndpoint, timeout, timeUnit, null);
+        return connect(host, timeout, timeUnit, null);
     }
 
     public Future<ClientEndpoint> connect(

Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestServer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestServer.java?rev=1772536&r1=1772535&r2=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestServer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/Http2TestServer.java Sun Dec  4 13:49:59 2016
@@ -45,7 +45,7 @@ import org.apache.hc.core5.http.nio.supp
 import org.apache.hc.core5.http.nio.support.RequestConsumerSupplier;
 import org.apache.hc.core5.http.nio.support.ResponseHandler;
 import org.apache.hc.core5.http.protocol.HttpProcessor;
-import org.apache.hc.core5.http2.bootstrap.Http2Processors;
+import org.apache.hc.core5.http2.impl.Http2Processors;
 import org.apache.hc.core5.http2.config.H2Config;
 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;

Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java?rev=1772536&r1=1772535&r2=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/http2/InternalHttp2StreamListener.java Sun Dec  4 13:49:59 2016
@@ -31,6 +31,7 @@ import java.io.IOException;
 import java.util.List;
 
 import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpConnection;
 import org.apache.hc.core5.http2.frame.FramePrinter;
 import org.apache.hc.core5.http2.frame.RawFrame;
 import org.apache.hc.core5.http2.impl.nio.Http2StreamListener;
@@ -82,7 +83,7 @@ class InternalHttp2StreamListener implem
     }
 
     @Override
-    public void onHeaderInput(final List<? extends Header> headers) {
+    public void onHeaderInput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
         if (headerLog.isDebugEnabled()) {
             for (int i = 0; i < headers.size(); i++) {
                 headerLog.debug(id + " << " + headers.get(i));
@@ -91,7 +92,7 @@ class InternalHttp2StreamListener implem
     }
 
     @Override
-    public void onHeaderOutput(final List<? extends Header> headers) {
+    public void onHeaderOutput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
         if (headerLog.isDebugEnabled()) {
             for (int i = 0; i < headers.size(); i++) {
                 headerLog.debug(id + " >> " + headers.get(i));
@@ -100,7 +101,7 @@ class InternalHttp2StreamListener implem
     }
 
     @Override
-    public void onFrameInput(final RawFrame frame) {
+    public void onFrameInput(final HttpConnection connection, final int streamId, final RawFrame frame) {
         if (frameLog.isDebugEnabled()) {
             logFrameInfo(id + " <<", frame);
         }
@@ -110,7 +111,7 @@ class InternalHttp2StreamListener implem
     }
 
     @Override
-    public void onFrameOutput(final RawFrame frame) {
+    public void onFrameOutput(final HttpConnection connection, final int streamId, final RawFrame frame) {
         if (frameLog.isDebugEnabled()) {
             logFrameInfo(id + " >>", frame);
         }
@@ -120,14 +121,14 @@ class InternalHttp2StreamListener implem
     }
 
     @Override
-    public void onInputFlowControl(final int streamId, final int delta, final int actualSize) {
+    public void onInputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
         if (flowCtrlLog.isDebugEnabled()) {
             logFlowControl(id + " <<", streamId, delta, actualSize);
         }
     }
 
     @Override
-    public void onOutputFlowControl(final int streamId, final int delta, final int actualSize) {
+    public void onOutputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
         if (flowCtrlLog.isDebugEnabled()) {
             logFlowControl(id + " >>", streamId, delta, actualSize);
         }

Modified: httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java?rev=1772536&r1=1772535&r2=1772536&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/examples/org/apache/hc/core5/http/examples/AsyncPipelinedRequestExecutionExample.java Sun Dec  4 13:49:59 2016
@@ -26,21 +26,26 @@
  */
 package org.apache.hc.core5.http.examples;
 
-import java.net.URI;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpConnection;
 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.Message;
+import org.apache.hc.core5.http.impl.Http1StreamListener;
 import org.apache.hc.core5.http.impl.nio.bootstrap.HttpAsyncRequester;
 import org.apache.hc.core5.http.impl.nio.bootstrap.PooledClientEndpoint;
 import org.apache.hc.core5.http.impl.nio.bootstrap.RequesterBootstrap;
+import org.apache.hc.core5.http.message.RequestLine;
+import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.http.nio.BasicRequestProducer;
 import org.apache.hc.core5.http.nio.BasicResponseConsumer;
 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.reactor.IOReactorConfig;
 
 /**
  * Example of asynchronous HTTP/1.1 request execution.
@@ -49,8 +54,39 @@ public class AsyncPipelinedRequestExecut
 
     public static void main(String[] args) throws Exception {
 
+        IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
+                .setConnectTimeout(5000)
+                .setSoTimeout(5000)
+                .build();
+
         // Create and start requester
-        final HttpAsyncRequester requester = RequesterBootstrap.bootstrap().create();
+        final HttpAsyncRequester requester = RequesterBootstrap.bootstrap()
+                .setIOReactorConfig(ioReactorConfig)
+                .setStreamListener(new Http1StreamListener() {
+
+                    @Override
+                    public void onRequestHead(final HttpConnection connection, final HttpRequest request) {
+                        System.out.println(connection + " " + new RequestLine(request));
+
+                    }
+
+                    @Override
+                    public void onResponseHead(final HttpConnection connection, final HttpResponse response) {
+                        System.out.println(connection + " " + new StatusLine(response));
+                    }
+
+                    @Override
+                    public void onExchangeComplete(final HttpConnection connection, final boolean keepAlive) {
+                        if (keepAlive) {
+                            System.out.println(connection + " can be kept alive");
+                        } else {
+                            System.out.println(connection + " cannot be kept alive");
+                        }
+                    }
+
+                })
+                .create();
+
         Runtime.getRuntime().addShutdownHook(new Thread() {
             @Override
             public void run() {
@@ -60,9 +96,8 @@ public class AsyncPipelinedRequestExecut
         });
         requester.start();
 
-        HttpHost target = new HttpHost("www.apache.org");
-        String[] requestUris = new String[] {"/", "/foundation",
-                "/foundation/how-it-works.html", "/foundation/getinvolved.html"};
+        HttpHost target = new HttpHost("httpbin.org");
+        String[] requestUris = new String[] {"/", "/ip", "/user-agent", "/headers"};
 
         Future<PooledClientEndpoint> future = requester.connect(target, 5, TimeUnit.SECONDS);
         PooledClientEndpoint clientEndpoint = future.get();
@@ -70,7 +105,7 @@ public class AsyncPipelinedRequestExecut
         final CountDownLatch latch = new CountDownLatch(requestUris.length);
         for (final String requestUri: requestUris) {
             clientEndpoint.execute(
-                    new BasicRequestProducer("GET", URI.create(requestUri)),
+                    new BasicRequestProducer("GET", target, requestUri),
                     new BasicResponseConsumer<>(new StringAsyncEntityConsumer()),
                     new FutureCallback<Message<HttpResponse, String>>() {
 
@@ -78,7 +113,9 @@ public class AsyncPipelinedRequestExecut
                         public void completed(final Message<HttpResponse, String> message) {
                             latch.countDown();
                             HttpResponse response = message.getHead();
+                            String body = message.getBody();
                             System.out.println(requestUri + "->" + response.getCode());
+                            System.out.println(body);
                         }
 
                         @Override