hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r1761318 [6/8] - in /httpcomponents/httpcore/trunk: httpcore5-h2/src/main/java/org/apache/hc/core5/http2/ httpcore5-h2/src/main/java/org/apache/hc/core5/http2/config/ httpcore5-h2/src/main/java/org/apache/hc/core5/http2/frame/ httpcore5-h2/...
Date Sun, 18 Sep 2016 11:29:33 GMT
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2IntegrationTest.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2IntegrationTest.java?rev=1761318&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2IntegrationTest.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2IntegrationTest.java Sun Sep 18 11:29:30 2016
@@ -0,0 +1,854 @@
+/*
+ * ====================================================================
+ * 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.integration;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.StringTokenizer;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHeaders;
+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.Message;
+import org.apache.hc.core5.http.entity.ContentType;
+import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.http.message.BasicHttpResponse;
+import org.apache.hc.core5.http2.H2Error;
+import org.apache.hc.core5.http2.H2StreamResetException;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.nio.AbstractAsyncExchangeHandler;
+import org.apache.hc.core5.http2.nio.AbstractAsyncPushHandler;
+import org.apache.hc.core5.http2.nio.AbstractClassicExchangeHandler;
+import org.apache.hc.core5.http2.nio.AsyncExchangeHandler;
+import org.apache.hc.core5.http2.nio.AsyncPushConsumer;
+import org.apache.hc.core5.http2.nio.AsyncResponseTrigger;
+import org.apache.hc.core5.http2.nio.BasicPushProducer;
+import org.apache.hc.core5.http2.nio.BasicRequestProducer;
+import org.apache.hc.core5.http2.nio.BasicResponseConsumer;
+import org.apache.hc.core5.http2.nio.BasicResponseProducer;
+import org.apache.hc.core5.http2.nio.CapacityChannel;
+import org.apache.hc.core5.http2.nio.DataStreamChannel;
+import org.apache.hc.core5.http2.nio.ResponseChannel;
+import org.apache.hc.core5.http2.nio.StreamChannel;
+import org.apache.hc.core5.http2.nio.Supplier;
+import org.apache.hc.core5.http2.nio.command.ClientCommandEndpoint;
+import org.apache.hc.core5.http2.nio.entity.AbstractCharAsyncEntityProducer;
+import org.apache.hc.core5.http2.nio.entity.AbstractClassicEntityConsumer;
+import org.apache.hc.core5.http2.nio.entity.AbstractClassicEntityProducer;
+import org.apache.hc.core5.http2.nio.entity.NoopEntityConsumer;
+import org.apache.hc.core5.http2.nio.entity.StringAsyncEntityConsumer;
+import org.apache.hc.core5.http2.nio.entity.StringAsyncEntityProducer;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class Http2IntegrationTest extends InternalServerTestBase {
+
+    private Http2TestClient client;
+
+    @Before
+    public void setup() throws Exception {
+        client = new Http2TestClient();
+    }
+
+    @After
+    public void cleanup() throws Exception {
+        if (client != null) {
+            client.shutdown(3, TimeUnit.SECONDS);
+        }
+    }
+
+    private URI createRequestURI(final InetSocketAddress serverEndpoint, final String path) {
+        try {
+            return new URI("http", null, "localhost", serverEndpoint.getPort(), path, null, null);
+        } catch (URISyntaxException e) {
+            throw new IllegalStateException();
+        }
+    }
+
+    static class SingleLineEntityProducer extends StringAsyncEntityProducer {
+
+        SingleLineEntityProducer(final String message) {
+            super(message, ContentType.TEXT_PLAIN);
+        }
+
+    }
+
+    static class SingleLineResponseHandler extends AbstractAsyncExchangeHandler<String> {
+
+        private final String message;
+
+        SingleLineResponseHandler(final String message) {
+            super(new StringAsyncEntityConsumer());
+            this.message = message;
+        }
+
+        @Override
+        protected void handle(
+                final Message<HttpRequest, String> request,
+                final AsyncResponseTrigger responseTrigger) throws IOException, HttpException {
+            responseTrigger.submitResponse(new BasicResponseProducer(
+                    HttpStatus.SC_OK, new SingleLineEntityProducer(message)));
+        }
+
+    }
+
+    @Test
+    public void testSimpleGet() throws Exception {
+        server.registerHandler("/hello", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new SingleLineResponseHandler("Hi there");
+            }
+
+        });
+        final InetSocketAddress serverEndpoint = server.start();
+
+        client.start();
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        final HttpRequest request1 = new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/hello"));
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer(request1, null),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final Message<HttpResponse, String> result1 = future1.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        final String entity1 = result1.getBody();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getCode());
+        Assert.assertEquals("Hi there", entity1);
+    }
+
+    static class MultiLineEntityProducer extends AbstractCharAsyncEntityProducer {
+
+        private final String text;
+        private final int total;
+        private final CharBuffer charbuf;
+
+        private int count;
+
+        MultiLineEntityProducer(final String text, final int total) {
+            super(1024, ContentType.TEXT_PLAIN);
+            this.text = text;
+            this.total = total;
+            this.charbuf = CharBuffer.allocate(4096);
+            this.count = 0;
+        }
+
+        @Override
+        protected void dataStart(final StreamChannel<CharBuffer> channel) throws IOException {
+            produceData(channel);
+        }
+
+        @Override
+        public int available() {
+            return Integer.MAX_VALUE;
+        }
+
+        @Override
+        protected void produceData(final StreamChannel<CharBuffer> channel) throws IOException {
+            while (charbuf.remaining() > text.length() + 2 && count < total) {
+                charbuf.put(text + "\r\n");
+                count++;
+            }
+            if (charbuf.position() > 0) {
+                charbuf.flip();
+                channel.write(charbuf);
+                charbuf.compact();
+            }
+            if (count >= total && charbuf.position() == 0) {
+                channel.endStream();
+            }
+        }
+
+        @Override
+        public void releaseResources() {
+        }
+
+    }
+
+    static class MultiLineResponseHandler extends AbstractAsyncExchangeHandler<String> {
+
+        private final String message;
+        private final int count;
+
+        MultiLineResponseHandler(final String message, final int count) {
+            super(new StringAsyncEntityConsumer());
+            this.message = message;
+            this.count = count;
+        }
+
+        @Override
+        protected void handle(
+                final Message<HttpRequest, String> request,
+                final AsyncResponseTrigger responseTrigger) throws IOException, HttpException {
+            final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
+            responseTrigger.submitResponse(new BasicResponseProducer(
+                    response,
+                    new MultiLineEntityProducer(message, count)));
+        }
+
+    }
+
+    @Test
+    public void testLargeGet() throws Exception {
+        server.registerHandler("/", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new MultiLineResponseHandler("0123456789abcdef", 5000);
+            }
+
+        });
+        final InetSocketAddress serverEndpoint = server.start();
+
+        client.start();
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        final HttpRequest request1 = new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/"));
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer(request1, null),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+
+        final HttpRequest request2 = new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/"));
+        final Future<Message<HttpResponse, String>> future2 = streamEndpoint.execute(
+                new BasicRequestProducer(request2, null),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer(512)), null);
+
+        final Message<HttpResponse, String> result1 = future1.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getCode());
+        final String s1 = result1.getBody();
+        Assert.assertNotNull(s1);
+        final StringTokenizer t1 = new StringTokenizer(s1, "\r\n");
+        while (t1.hasMoreTokens()) {
+            Assert.assertEquals("0123456789abcdef", t1.nextToken());
+        }
+
+        final Message<HttpResponse, String> result2 = future2.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result2);
+        final HttpResponse response2 = result2.getHead();
+        Assert.assertNotNull(response2);
+        Assert.assertEquals(200, response2.getCode());
+        final String s2 = result2.getBody();
+        Assert.assertNotNull(s2);
+        final StringTokenizer t2 = new StringTokenizer(s2, "\r\n");
+        while (t2.hasMoreTokens()) {
+            Assert.assertEquals("0123456789abcdef", t2.nextToken());
+        }
+    }
+
+    @Test
+    public void testBasicPost() throws Exception {
+        server.registerHandler("/hello", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new SingleLineResponseHandler("Hi back");
+            }
+
+        });
+        final InetSocketAddress serverEndpoint = server.start();
+
+        client.start();
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        final HttpRequest request1 = new BasicHttpRequest("POST", createRequestURI(serverEndpoint, "/hello"));
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer(request1, new SingleLineEntityProducer("Hi there")),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final Message<HttpResponse, String> result1 = future1.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        final String entity1 = result1.getBody();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getCode());
+        Assert.assertEquals("Hi back", entity1);
+    }
+
+    static class EchoHandler implements AsyncExchangeHandler {
+
+        private volatile ByteBuffer buffer;
+        private volatile CapacityChannel inputCapacityChannel;
+        private volatile DataStreamChannel outputDataChannel;
+        private volatile boolean endStream;
+
+        EchoHandler(final int bufferSize) {
+            this.buffer = ByteBuffer.allocate(bufferSize);
+        }
+
+        private void ensureCapacity(final int chunk) {
+            if (buffer.remaining() < chunk) {
+                final ByteBuffer oldBuffer = buffer;
+                oldBuffer.flip();
+                buffer = ByteBuffer.allocate(oldBuffer.remaining() + (chunk > 2048 ? chunk : 2048));
+                buffer.put(oldBuffer);
+            }
+        }
+
+        @Override
+        public void handleRequest(
+                final HttpRequest request,
+                final boolean enclosedBody,
+                final ResponseChannel responseChannel) throws HttpException, IOException {
+            final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_OK);
+            final Header h1 = request.getFirstHeader(HttpHeaders.CONTENT_TYPE);
+            if (h1 != null) {
+                response.addHeader(h1);
+            }
+            final Header h2 = request.getFirstHeader(HttpHeaders.CONTENT_ENCODING);
+            if (h2 != null) {
+                response.addHeader(h2);
+            }
+            responseChannel.sendResponse(response, enclosedBody);
+        }
+
+        @Override
+        public void consume(final ByteBuffer src) throws IOException {
+            if (buffer.position() == 0) {
+                if (outputDataChannel != null) {
+                    outputDataChannel.write(src);
+                }
+            }
+            if (src.hasRemaining()) {
+                ensureCapacity(src.remaining());
+                buffer.put(src);
+                if (outputDataChannel != null) {
+                    outputDataChannel.requestOutput();
+                }
+            }
+        }
+
+        @Override
+        public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
+            if (buffer.hasRemaining()) {
+                capacityChannel.update(buffer.remaining());
+                inputCapacityChannel = null;
+            } else {
+                inputCapacityChannel = capacityChannel;
+            }
+        }
+
+        @Override
+        public void streamEnd(final List<Header> trailers) throws HttpException, IOException {
+            endStream = true;
+            if (buffer.position() == 0) {
+                if (outputDataChannel != null) {
+                    outputDataChannel.endStream();
+                }
+            } else {
+                if (outputDataChannel != null) {
+                    outputDataChannel.requestOutput();
+                }
+            }
+        }
+
+        @Override
+        public int available() {
+            return buffer.position();
+        }
+
+        @Override
+        public void produce(final DataStreamChannel channel) throws IOException {
+            outputDataChannel = channel;
+            buffer.flip();
+            if (buffer.hasRemaining()) {
+                channel.write(buffer);
+            }
+            buffer.compact();
+            if (buffer.position() == 0 && endStream) {
+                channel.endStream();
+            }
+            final CapacityChannel capacityChannel = inputCapacityChannel;
+            if (capacityChannel != null && buffer.hasRemaining()) {
+                capacityChannel.update(buffer.remaining());
+            }
+        }
+
+        @Override
+        public void failed(final Exception cause) {
+        }
+
+        @Override
+        public void releaseResources() {
+        }
+
+    }
+
+    @Test
+    public void testLargePost() throws Exception {
+        server.registerHandler("*", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new EchoHandler(2048);
+            }
+
+        });
+        final InetSocketAddress serverEndpoint = server.start();
+
+        client.start();
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        client.start();
+
+        final HttpRequest request1 = new BasicHttpRequest("POST", createRequestURI(serverEndpoint, "/echo"));
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer(request1, new MultiLineEntityProducer("0123456789abcdef", 5000)),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final Message<HttpResponse, String> result1 = future1.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getCode());
+        final String s1 = result1.getBody();
+        Assert.assertNotNull(s1);
+        final StringTokenizer t1 = new StringTokenizer(s1, "\r\n");
+        while (t1.hasMoreTokens()) {
+            Assert.assertEquals("0123456789abcdef", t1.nextToken());
+        }
+    }
+
+    @Test
+    public void testSlowResponseConsumer() throws Exception {
+        server.registerHandler("/", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new MultiLineResponseHandler("0123456789abcd", 3);
+            }
+
+        });
+        final InetSocketAddress serverEndpoint = server.start();
+
+        client.start(H2Config.custom().setInitialWindowSize(16).build());
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        final HttpRequest request1 = new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/"));
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer(request1, null),
+                new BasicResponseConsumer<>(new AbstractClassicEntityConsumer<String>(16, Executors.newSingleThreadExecutor()) {
+
+                    @Override
+                    protected String consumeData(
+                            final ContentType contentType, final InputStream inputStream) throws IOException {
+                        Charset charset = contentType != null ? contentType.getCharset() : null;
+                        if (charset == null) {
+                            charset = StandardCharsets.US_ASCII;
+                        }
+
+                        final StringBuffer buffer = new StringBuffer();
+                        try {
+                            final byte[] tmp = new byte[16];
+                            int l;
+                            while ((l = inputStream.read(tmp)) != -1) {
+                                buffer.append(charset.decode(ByteBuffer.wrap(tmp, 0, l)));
+                                Thread.sleep(500);
+                            }
+                        } catch (InterruptedException ex) {
+                            Thread.currentThread().interrupt();
+                            throw new InterruptedIOException(ex.getMessage());
+                        }
+                        return buffer.toString();
+                    }
+                }),
+                null);
+
+        final Message<HttpResponse, String> result1 = future1.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getCode());
+        final String s1 = result1.getBody();
+        Assert.assertNotNull(s1);
+        final StringTokenizer t1 = new StringTokenizer(s1, "\r\n");
+        while (t1.hasMoreTokens()) {
+            Assert.assertEquals("0123456789abcd", t1.nextToken());
+        }
+    }
+
+    @Test
+    public void testSlowRequestProducer() throws Exception {
+        server.registerHandler("*", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new EchoHandler(2048);
+            }
+
+        });
+        final InetSocketAddress serverEndpoint = server.start();
+
+        client.start();
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        final HttpRequest request1 = new BasicHttpRequest("POST", createRequestURI(serverEndpoint, "/echo"));
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer(request1, new AbstractClassicEntityProducer(4096, ContentType.TEXT_PLAIN, Executors.newSingleThreadExecutor()) {
+
+                    @Override
+                    protected void produceData(final ContentType contentType, final OutputStream outputStream) throws IOException {
+                        Charset charset = contentType.getCharset();
+                        if (charset == null) {
+                            charset = StandardCharsets.US_ASCII;
+                        }
+                        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, charset))) {
+                            for (int i = 0; i < 500; i++) {
+                                if (i % 100 == 0) {
+                                    writer.flush();
+                                    Thread.sleep(500);
+                                }
+                                writer.write("0123456789abcdef\r\n");
+                            }
+                        } catch (InterruptedException ex) {
+                            Thread.currentThread().interrupt();
+                            throw new InterruptedIOException(ex.getMessage());
+                        }
+                    }
+
+                }),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final Message<HttpResponse, String> result1 = future1.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getCode());
+        final String s1 = result1.getBody();
+        Assert.assertNotNull(s1);
+        final StringTokenizer t1 = new StringTokenizer(s1, "\r\n");
+        while (t1.hasMoreTokens()) {
+            Assert.assertEquals("0123456789abcdef", t1.nextToken());
+        }
+    }
+
+    @Test
+    public void testSlowResponseProducer() throws Exception {
+        server.registerHandler("*", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new AbstractClassicExchangeHandler(2048, Executors.newSingleThreadExecutor()) {
+
+                    @Override
+                    protected void handle(
+                            final HttpRequest request,
+                            final InputStream requestStream,
+                            final HttpResponse response,
+                            final OutputStream responseStream) throws IOException, HttpException {
+
+                        if (!"/hello".equals(request.getPath())) {
+                            response.setCode(HttpStatus.SC_NOT_FOUND);
+                            return;
+                        }
+                        if (!"POST".equalsIgnoreCase(request.getMethod())) {
+                            response.setCode(HttpStatus.SC_NOT_IMPLEMENTED);
+                            return;
+                        }
+                        if (requestStream == null) {
+                            return;
+                        }
+                        final Header h1 = request.getFirstHeader(HttpHeaders.CONTENT_TYPE);
+                        final ContentType contentType = h1 != null ? ContentType.parse(h1.getValue()) : null;
+                        Charset charset = contentType != null ? contentType.getCharset() : null;
+                        if (charset == null) {
+                            charset = StandardCharsets.US_ASCII;
+                        }
+                        response.setCode(HttpStatus.SC_OK);
+                        response.setHeader(h1);
+                        try (final BufferedReader reader = new BufferedReader(new InputStreamReader(requestStream, charset));
+                            final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(responseStream, charset))) {
+                            try {
+                                String l;
+                                int count = 0;
+                                while ((l = reader.readLine()) != null) {
+                                    writer.write(l);
+                                    writer.write("\r\n");
+                                    count++;
+                                    if (count % 500 == 0) {
+                                        Thread.sleep(500);
+                                    }
+                                }
+                                writer.flush();
+                            } catch (InterruptedException ex) {
+                                Thread.currentThread().interrupt();
+                                throw new InterruptedIOException(ex.getMessage());
+                            }
+                        }
+                    }
+                };
+            }
+
+        });
+        final InetSocketAddress serverEndpoint = server.start();
+
+        client.start(H2Config.custom()
+                .setInitialWindowSize(512)
+                .build());
+
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        final HttpRequest request1 = new BasicHttpRequest("POST", createRequestURI(serverEndpoint, "/hello"));
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer(request1, new MultiLineEntityProducer("0123456789abcd", 2000)),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final Message<HttpResponse, String> result1 = future1.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getCode());
+        final String s1 = result1.getBody();
+        Assert.assertNotNull(s1);
+        final StringTokenizer t1 = new StringTokenizer(s1, "\r\n");
+        while (t1.hasMoreTokens()) {
+            Assert.assertEquals("0123456789abcd", t1.nextToken());
+        }
+    }
+
+    @Test
+    public void testPush() throws Exception {
+        final InetSocketAddress serverEndpoint = server.start();
+        server.registerHandler("/hello", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new AbstractAsyncExchangeHandler<Void>(new NoopEntityConsumer()) {
+
+                    @Override
+                    protected void handle(
+                            final Message<HttpRequest, Void> request,
+                            final AsyncResponseTrigger responseTrigger) throws IOException, HttpException {
+
+                        responseTrigger.pushPromise(
+                                new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/stuff")),
+                                new BasicPushProducer(new MultiLineEntityProducer("Pushing lots of stuff", 500)));
+                        responseTrigger.submitResponse(new BasicResponseProducer(
+                                HttpStatus.SC_OK,
+                                new SingleLineEntityProducer("Hi there")));
+                    }
+                };
+            }
+
+        });
+
+        client.start(H2Config.custom().setPushEnabled(true).build());
+
+        final BlockingQueue<Message<HttpResponse, String>> pushMessageQueue = new LinkedBlockingDeque<>();
+        client.registerHandler("*", new Supplier<AsyncPushConsumer>() {
+
+            @Override
+            public AsyncPushConsumer get() {
+                return new AbstractAsyncPushHandler<String>(new BasicResponseConsumer<>(new StringAsyncEntityConsumer())) {
+
+                    @Override
+                    protected void handleResponse(
+                            final HttpRequest promise,
+                            final Message<HttpResponse, String> responseMessage) throws IOException, HttpException {
+                        try {
+                            pushMessageQueue.put(responseMessage);
+                        } catch (InterruptedException ex) {
+                            Thread.currentThread().interrupt();
+                            throw new InterruptedIOException(ex.getMessage());
+                        }
+                    }
+
+                };
+            }
+
+        });
+
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer("GET", createRequestURI(serverEndpoint, "/hello")),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final Message<HttpResponse, String> result1 = future1.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        final String entity1 = result1.getBody();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getCode());
+        Assert.assertEquals("Hi there", entity1);
+
+        final Message<HttpResponse, String> result2 = pushMessageQueue.poll(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result2);
+        final HttpResponse response2 = result2.getHead();
+        final String entity2 = result2.getBody();
+        Assert.assertEquals(200, response2.getCode());
+        Assert.assertNotNull(entity2);
+        final StringTokenizer t1 = new StringTokenizer(entity2, "\r\n");
+        while (t1.hasMoreTokens()) {
+            Assert.assertEquals("Pushing lots of stuff", t1.nextToken());
+        }
+    }
+
+    @Test
+    public void testPushRefused() throws Exception {
+        final BlockingQueue<Exception> pushResultQueue = new LinkedBlockingDeque<>();
+        final InetSocketAddress serverEndpoint = server.start();
+        server.registerHandler("/hello", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new AbstractAsyncExchangeHandler<Void>(new NoopEntityConsumer()) {
+
+                    @Override
+                    protected void handle(
+                            final Message<HttpRequest, Void> request,
+                            final AsyncResponseTrigger responseTrigger) throws IOException, HttpException {
+
+                        responseTrigger.pushPromise(
+                                new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/stuff")),
+                                new BasicPushProducer(new SingleLineEntityProducer("Pushing all sorts of stuff")) {
+
+                            @Override
+                            public void failed(final Exception cause) {
+                                pushResultQueue.add(cause);
+                                super.failed(cause);
+                            }
+
+                        });
+                        responseTrigger.pushPromise(
+                                new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/more-stuff")),
+                                new BasicPushProducer(new MultiLineEntityProducer("Pushing lots of stuff", 500)) {
+
+                            @Override
+                            public void failed(final Exception cause) {
+                                pushResultQueue.add(cause);
+                                super.failed(cause);
+                            }
+
+                        });
+                        responseTrigger.submitResponse(new BasicResponseProducer(
+                                HttpStatus.SC_OK,
+                                new SingleLineEntityProducer("Hi there")));
+                    }
+                };
+            }
+
+        });
+
+        client.start(H2Config.custom().setPushEnabled(true).build());
+
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer("GET", createRequestURI(serverEndpoint, "/hello")),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final Message<HttpResponse, String> result1 = future1.get(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        final String entity1 = result1.getBody();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(200, response1.getCode());
+        Assert.assertEquals("Hi there", entity1);
+
+        final Object result2 = pushResultQueue.poll(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result2);
+        Assert.assertTrue(result2 instanceof H2StreamResetException);
+        Assert.assertEquals(H2Error.REFUSED_STREAM.getCode(), ((H2StreamResetException) result2).getCode());
+
+        final Object result3 = pushResultQueue.poll(5, TimeUnit.SECONDS);
+        Assert.assertNotNull(result3);
+        Assert.assertTrue(result3 instanceof H2StreamResetException);
+        Assert.assertEquals(H2Error.REFUSED_STREAM.getCode(), ((H2StreamResetException) result3).getCode());
+    }
+
+    @Test
+    public void testExcessOfConcurrentStreams() throws Exception {
+        server.registerHandler("/", new Supplier<AsyncExchangeHandler>() {
+
+            @Override
+            public AsyncExchangeHandler get() {
+                return new MultiLineResponseHandler("0123456789abcdef", 2000);
+            }
+
+        });
+        final InetSocketAddress serverEndpoint = server.start(H2Config.custom().setMaxConcurrentStreams(20).build());
+
+        client.start(H2Config.custom().setMaxConcurrentStreams(20).build());
+        final Future<ClientCommandEndpoint> connectFuture = client.connect(serverEndpoint, 5000);
+        final ClientCommandEndpoint streamEndpoint = connectFuture.get();
+
+        final Queue<Future<Message<HttpResponse, Void>>> queue = new LinkedList<>();
+        for (int i = 0; i < 2000; i++) {
+            final HttpRequest request1 = new BasicHttpRequest("GET", createRequestURI(serverEndpoint, "/"));
+            final Future<Message<HttpResponse, Void>> future = streamEndpoint.execute(
+                    new BasicRequestProducer(request1, null),
+                    new BasicResponseConsumer<>(new NoopEntityConsumer()), null);
+            queue.add(future);
+        }
+
+        while (!queue.isEmpty()) {
+            final Future<Message<HttpResponse, Void>> future = queue.remove();
+            final Message<HttpResponse, Void> result = future.get(50000, TimeUnit.SECONDS);
+            Assert.assertNotNull(result);
+            final HttpResponse response = result.getHead();
+            Assert.assertNotNull(response);
+            Assert.assertEquals(200, response.getCode());
+        }
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2IntegrationTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2IntegrationTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2IntegrationTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestClient.java?rev=1761318&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestClient.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestClient.java Sun Sep 18 11:29:30 2016
@@ -0,0 +1,229 @@
+/*
+ * ====================================================================
+ * 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.integration;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketTimeoutException;
+import java.nio.channels.SelectionKey;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hc.core5.concurrent.BasicFuture;
+import org.apache.hc.core5.concurrent.FutureCallback;
+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.protocol.HttpContext;
+import org.apache.hc.core5.http.protocol.UriPatternMatcher;
+import org.apache.hc.core5.http2.H2ConnectionException;
+import org.apache.hc.core5.http2.H2Error;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.nio.AsyncPushConsumer;
+import org.apache.hc.core5.http2.nio.HandlerFactory;
+import org.apache.hc.core5.http2.nio.Supplier;
+import org.apache.hc.core5.http2.nio.command.ClientCommandEndpoint;
+import org.apache.hc.core5.http2.nio.command.ShutdownCommand;
+import org.apache.hc.core5.http2.nio.command.ShutdownType;
+import org.apache.hc.core5.reactor.DefaultConnectingIOReactor;
+import org.apache.hc.core5.reactor.ExceptionEvent;
+import org.apache.hc.core5.reactor.IOReactorExceptionHandler;
+import org.apache.hc.core5.reactor.IOReactorStatus;
+import org.apache.hc.core5.reactor.IOSession;
+import org.apache.hc.core5.reactor.IOSessionCallback;
+import org.apache.hc.core5.reactor.SessionRequest;
+import org.apache.hc.core5.reactor.SessionRequestCallback;
+import org.apache.hc.core5.util.Args;
+
+public class Http2TestClient {
+
+    private final ExecutorService executorService;
+    private final UriPatternMatcher<Supplier<AsyncPushConsumer>> pushHandlerMatcher;
+
+    private volatile DefaultConnectingIOReactor ioReactor;
+    private volatile Exception exception;
+
+    public Http2TestClient() throws IOException {
+        super();
+        this.executorService = Executors.newSingleThreadExecutor();
+        this.pushHandlerMatcher = new UriPatternMatcher<>();
+    }
+
+    public Future<ClientCommandEndpoint> connect(
+            final InetSocketAddress address,
+            final int connectTimeout,
+            final Object attachment,
+            final FutureCallback<ClientCommandEndpoint> callback) throws InterruptedException {
+        final BasicFuture<ClientCommandEndpoint> future = new BasicFuture<>(callback);
+        final SessionRequest sessionRequest = this.ioReactor.connect(address, null, attachment, new SessionRequestCallback() {
+
+            @Override
+            public void completed(final SessionRequest request) {
+                final IOSession session = request.getSession();
+                future.completed(new ClientCommandEndpoint(session));
+            }
+
+            @Override
+            public void failed(final SessionRequest request) {
+                future.failed(request.getException());
+            }
+
+            @Override
+            public void timeout(final SessionRequest request) {
+                future.failed(new SocketTimeoutException("Connect timeout"));
+            }
+
+            @Override
+            public void cancelled(final SessionRequest request) {
+                future.cancel();
+            }
+        });
+        sessionRequest.setConnectTimeout(connectTimeout);
+        return future;
+    }
+
+    public Future<ClientCommandEndpoint> connect(
+            final InetSocketAddress address,
+            final int connectTimeout) throws InterruptedException {
+        return connect(address, connectTimeout, null, null);
+    }
+
+    private AsyncPushConsumer createHandler(final HttpRequest request) throws HttpException, IOException {
+
+        final HttpHost authority;
+        try {
+            authority = HttpHost.create(request.getAuthority());
+        } catch (IllegalArgumentException ex) {
+            throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, ex.getMessage());
+        }
+        if (!"localhost".equalsIgnoreCase(authority.getHostName())) {
+            throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, "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 registerHandler(final String uriPattern, final Supplier<AsyncPushConsumer> supplier) {
+        Args.notNull(uriPattern, "URI pattern");
+        Args.notNull(supplier, "Supplier");
+        pushHandlerMatcher.register(uriPattern, supplier);
+    }
+
+    public void start() throws Exception {
+        start(H2Config.DEFAULT);
+    }
+
+    public void start(final H2Config h2Config) throws Exception {
+        this.ioReactor = new DefaultConnectingIOReactor(new InternalClientHttp2EventHandlerFactory(
+                new HandlerFactory<AsyncPushConsumer>() {
+
+                    @Override
+                    public AsyncPushConsumer create(
+                            final HttpRequest request, final HttpContext context) throws HttpException, IOException {
+                        return createHandler(request);
+                    }
+
+                },
+                StandardCharsets.US_ASCII,
+                h2Config));
+        ioReactor.setExceptionHandler(new IOReactorExceptionHandler() {
+
+            @Override
+            public boolean handle(final IOException ex) {
+                ex.printStackTrace();
+                return false;
+            }
+
+            @Override
+            public boolean handle(final RuntimeException ex) {
+                ex.printStackTrace();
+                return false;
+            }
+
+        });
+        this.executorService.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    ioReactor.execute();
+                } catch (Exception ex) {
+                    exception = ex;
+                }
+            }
+        });
+    }
+
+    public IOReactorStatus getStatus() {
+        return this.ioReactor.getStatus();
+    }
+
+    public List<ExceptionEvent> getAuditLog() {
+        return this.ioReactor.getAuditLog();
+    }
+
+    public Exception getException() {
+        return this.exception;
+    }
+
+    public void awaitShutdown(final long deadline, final TimeUnit timeUnit) throws InterruptedException {
+        ioReactor.awaitShutdown(deadline, timeUnit);
+    }
+
+    public void initiateShutdown() throws IOException {
+        ioReactor.initiateShutdown();
+        ioReactor.enumSessions(new IOSessionCallback() {
+
+            @Override
+            public void execute(final IOSession session) throws IOException {
+                session.getCommandQueue().addFirst(new ShutdownCommand(ShutdownType.GRACEFUL));
+                session.setEvent(SelectionKey.OP_WRITE);
+            }
+
+        });
+    }
+
+    public void shutdown(final long graceTime, final TimeUnit timeUnit) throws IOException {
+        initiateShutdown();
+        ioReactor.shutdown(graceTime, timeUnit);
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestClient.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestClient.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestServer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestServer.java?rev=1761318&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestServer.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestServer.java Sun Sep 18 11:29:30 2016
@@ -0,0 +1,187 @@
+/*
+ * ====================================================================
+ * 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.integration;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.SelectionKey;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+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.HttpStatus;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.http.protocol.UriPatternMatcher;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.nio.AsyncExchangeHandler;
+import org.apache.hc.core5.http2.nio.FixedResponseExchangeHandler;
+import org.apache.hc.core5.http2.nio.HandlerFactory;
+import org.apache.hc.core5.http2.nio.Supplier;
+import org.apache.hc.core5.http2.nio.command.ShutdownCommand;
+import org.apache.hc.core5.http2.nio.command.ShutdownType;
+import org.apache.hc.core5.reactor.DefaultListeningIOReactor;
+import org.apache.hc.core5.reactor.ExceptionEvent;
+import org.apache.hc.core5.reactor.IOReactorExceptionHandler;
+import org.apache.hc.core5.reactor.IOReactorStatus;
+import org.apache.hc.core5.reactor.IOSession;
+import org.apache.hc.core5.reactor.IOSessionCallback;
+import org.apache.hc.core5.reactor.ListenerEndpoint;
+import org.apache.hc.core5.util.Args;
+
+public class Http2TestServer {
+
+    private final ExecutorService executorService;
+    private final UriPatternMatcher<Supplier<AsyncExchangeHandler>> responseHandlerMatcher;
+
+    private volatile DefaultListeningIOReactor ioReactor;
+    private volatile Exception exception;
+
+    public Http2TestServer() throws IOException {
+        super();
+        this.executorService = Executors.newSingleThreadExecutor();
+        this.responseHandlerMatcher = new UriPatternMatcher<>();
+    }
+
+    public InetSocketAddress start() throws Exception {
+        return start(H2Config.DEFAULT);
+    }
+
+    private AsyncExchangeHandler createHandler(final HttpRequest request) throws HttpException {
+
+        final HttpHost authority;
+        try {
+            authority = HttpHost.create(request.getAuthority());
+        } catch (IllegalArgumentException ex) {
+            return new FixedResponseExchangeHandler(HttpStatus.SC_BAD_REQUEST, "Invalid authority");
+        }
+        if (!"localhost".equalsIgnoreCase(authority.getHostName())) {
+            return new FixedResponseExchangeHandler(HttpStatus.SC_MISDIRECTED_REQUEST, "Not authoritative");
+        }
+        String path = request.getPath();
+        final int i = path.indexOf("?");
+        if (i != -1) {
+            path = path.substring(0, i - 1);
+        }
+        final Supplier<AsyncExchangeHandler> supplier = responseHandlerMatcher.lookup(path);
+        if (supplier != null) {
+            return supplier.get();
+        }
+        return new FixedResponseExchangeHandler(HttpStatus.SC_NOT_FOUND, "Resource not found");
+    }
+
+    public void registerHandler(final String uriPattern, final Supplier<AsyncExchangeHandler> supplier) {
+        Args.notNull(uriPattern, "URI pattern");
+        Args.notNull(supplier, "Supplier");
+        responseHandlerMatcher.register(uriPattern, supplier);
+    }
+
+    public InetSocketAddress start(final H2Config h2Config) throws Exception {
+        ioReactor = new DefaultListeningIOReactor(new InternalServerHttp2EventHandlerFactory(
+                new HandlerFactory<AsyncExchangeHandler>() {
+
+                    @Override
+                    public AsyncExchangeHandler create(
+                            final HttpRequest request,
+                            final HttpContext context) throws HttpException {
+                        return createHandler(request);
+                    }
+
+                },
+                StandardCharsets.US_ASCII,
+                h2Config));
+        ioReactor.setExceptionHandler(new IOReactorExceptionHandler() {
+
+            @Override
+            public boolean handle(final IOException ex) {
+                ex.printStackTrace();
+                return false;
+            }
+
+            @Override
+            public boolean handle(final RuntimeException ex) {
+                ex.printStackTrace();
+                return false;
+            }
+
+        });
+        executorService.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    ioReactor.execute();
+                } catch (Exception ex) {
+                    exception = ex;
+                }
+            }
+        });
+        final ListenerEndpoint listener = ioReactor.listen(new InetSocketAddress(0));
+        listener.waitFor();
+        return (InetSocketAddress) listener.getAddress();
+    }
+
+    public IOReactorStatus getStatus() {
+        return this.ioReactor.getStatus();
+    }
+
+    public List<ExceptionEvent> getAuditLog() {
+        return this.ioReactor.getAuditLog();
+    }
+
+    public Exception getException() {
+        return this.exception;
+    }
+
+    public void awaitShutdown(final long deadline, final TimeUnit timeUnit) throws InterruptedException {
+        ioReactor.awaitShutdown(deadline, timeUnit);
+    }
+
+    public void initiateShutdown() throws IOException {
+        ioReactor.initiateShutdown();
+        ioReactor.enumSessions(new IOSessionCallback() {
+
+            @Override
+            public void execute(final IOSession session) throws IOException {
+                session.getCommandQueue().addFirst(new ShutdownCommand(ShutdownType.GRACEFUL));
+                session.setEvent(SelectionKey.OP_WRITE);
+            }
+
+        });
+    }
+
+    public void shutdown(final long graceTime, final TimeUnit timeUnit) throws IOException {
+        initiateShutdown();
+        ioReactor.shutdown(graceTime, timeUnit);
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestServer.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Http2TestServer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalClientHttp2EventHandlerFactory.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalClientHttp2EventHandlerFactory.java?rev=1761318&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalClientHttp2EventHandlerFactory.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalClientHttp2EventHandlerFactory.java Sun Sep 18 11:29:30 2016
@@ -0,0 +1,78 @@
+/*
+ * ====================================================================
+ * 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.integration;
+
+import java.nio.charset.Charset;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.impl.nio.ClientHttp2StreamMultiplexer;
+import org.apache.hc.core5.http2.impl.nio.ClientHttpProtocolNegotiator;
+import org.apache.hc.core5.http2.impl.nio.HttpErrorListener;
+import org.apache.hc.core5.http2.nio.AsyncPushConsumer;
+import org.apache.hc.core5.http2.nio.HandlerFactory;
+import org.apache.hc.core5.reactor.IOEventHandler;
+import org.apache.hc.core5.reactor.IOEventHandlerFactory;
+import org.apache.hc.core5.reactor.IOSession;
+
+public class InternalClientHttp2EventHandlerFactory implements IOEventHandlerFactory {
+
+    private static final AtomicLong COUNT = new AtomicLong();
+
+    private final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory;
+    private final Charset charset;
+    private final H2Config h2Config;
+
+    public InternalClientHttp2EventHandlerFactory(
+            final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory,
+            final Charset charset,
+            final H2Config h2Config) {
+        this.exchangeHandlerFactory = exchangeHandlerFactory;
+        this.charset = charset;
+        this.h2Config = h2Config;
+    }
+
+    @Override
+    public IOEventHandler createHandler(final IOSession ioSession) {
+        final String id = "http2-outgoing-" + COUNT.incrementAndGet();
+        final Log sessionLog = LogFactory.getLog(ioSession.getClass());
+        final InternalHttp2StreamListener streamListener = new InternalHttp2StreamListener(id);
+        final HttpErrorListener errorListener = new InternalHttpErrorListener(sessionLog);
+        return new ClientHttpProtocolNegotiator(exchangeHandlerFactory, charset, h2Config, streamListener, errorListener) {
+
+            @Override
+            protected ClientHttp2StreamMultiplexer createStreamMultiplexer(final IOSession ioSession) {
+                return super.createStreamMultiplexer(new LoggingIOSession(ioSession, id, sessionLog));
+            }
+        };
+
+   }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalClientHttp2EventHandlerFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalClientHttp2EventHandlerFactory.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalClientHttp2EventHandlerFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttp2StreamListener.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttp2StreamListener.java?rev=1761318&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttp2StreamListener.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttp2StreamListener.java Sun Sep 18 11:29:30 2016
@@ -0,0 +1,136 @@
+/*
+ * ====================================================================
+ * 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.integration;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hc.core5.http.Header;
+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;
+
+class InternalHttp2StreamListener implements Http2StreamListener {
+
+    private final String id;
+    private final Log headerLog;
+    private final Log frameLog;
+    private final Log framePayloadLog;
+    private final Log flowCtrlLog;
+    private final FramePrinter framePrinter;
+
+    public InternalHttp2StreamListener(final String id) {
+        this.id = id;
+        this.framePrinter = new FramePrinter();
+        this.headerLog = LogFactory.getLog("org.apache.hc.core5.http.headers");
+        this.frameLog = LogFactory.getLog("org.apache.hc.core5.http.frame");
+        this.framePayloadLog = LogFactory.getLog("org.apache.hc.core5.http.frame.payload");
+        this.flowCtrlLog = LogFactory.getLog("org.apache.hc.core5.http.flow");
+    }
+
+    private void logFrameInfo(final String prefix, final RawFrame frame) {
+        try {
+            final LogAppendable logAppendable = new LogAppendable(frameLog, prefix);
+            framePrinter.printFrameInfo(frame, logAppendable);
+            logAppendable.flush();
+        } catch (IOException ignore) {
+        }
+    }
+
+    private void logFramePayload(final String prefix, final RawFrame frame) {
+        try {
+            final LogAppendable logAppendable = new LogAppendable(framePayloadLog, prefix);
+            framePrinter.printPayload(frame, logAppendable);
+            logAppendable.flush();
+        } catch (IOException ignore) {
+        }
+    }
+
+    private void logFlowControl(final String prefix, final int streamId, final int delta, final int actualSize) {
+        final StringBuilder buffer = new StringBuilder();
+        buffer.append(prefix).append(" stream ").append(streamId).append(" flow control " )
+                .append(delta).append(" -> ")
+                .append(actualSize);
+        flowCtrlLog.debug(buffer.toString());
+    }
+
+    @Override
+    public void onHeaderInput(final List<Header> headers) {
+        if (headerLog.isDebugEnabled()) {
+            for (int i = 0; i < headers.size(); i++) {
+                headerLog.debug(id + " << " + headers.get(i));
+            }
+        }
+    }
+
+    @Override
+    public void onHeaderOutput(final List<Header> headers) {
+        if (headerLog.isDebugEnabled()) {
+            for (int i = 0; i < headers.size(); i++) {
+                headerLog.debug(id + " >> " + headers.get(i));
+            }
+        }
+    }
+
+    @Override
+    public void onFrameInput(final RawFrame frame) {
+        if (frameLog.isDebugEnabled()) {
+            logFrameInfo(id + " <<", frame);
+        }
+        if (framePayloadLog.isDebugEnabled()) {
+            logFramePayload(id + " <<", frame);
+        }
+    }
+
+    @Override
+    public void onFrameOutput(final RawFrame frame) {
+        if (frameLog.isDebugEnabled()) {
+            logFrameInfo(id + " >>", frame);
+        }
+        if (framePayloadLog.isDebugEnabled()) {
+            logFramePayload(id + " >>", frame);
+        }
+    }
+
+    @Override
+    public void onInputFlowControl(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) {
+        if (flowCtrlLog.isDebugEnabled()) {
+            logFlowControl(id + " >>", streamId, delta, actualSize);
+        }
+    }
+
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttp2StreamListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttp2StreamListener.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttp2StreamListener.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttpErrorListener.java (from r1761317, httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/frame/FrameConsts.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttpErrorListener.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttpErrorListener.java&p1=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/frame/FrameConsts.java&r1=1761317&r2=1761318&rev=1761318&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/frame/FrameConsts.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalHttpErrorListener.java Sun Sep 18 11:29:30 2016
@@ -24,17 +24,26 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.core5.http2.frame;
 
-public final class FrameConsts {
+package org.apache.hc.core5.http2.integration;
 
-    private FrameConsts() {
-        // Do not allow utility class to be instantiated.
+import org.apache.commons.logging.Log;
+import org.apache.hc.core5.http.ConnectionClosedException;
+import org.apache.hc.core5.http2.impl.nio.HttpErrorListener;
+
+class InternalHttpErrorListener implements HttpErrorListener {
+
+    private final Log log;
+
+    public InternalHttpErrorListener(final Log log) {
+        this.log = log;
     }
 
-    public final static int HEAD_LEN = 9;
-    public final static int MAX_PADDING = 255;
-    public final static int MIN_FRAME_SIZE = 2 ^ 14;
-    public final static int MAX_FRAME_SIZE = 2 ^ 24 - 1;
+    @Override
+    public void onError(final Exception cause) {
+        if (log != null && !(cause instanceof ConnectionClosedException)) {
+            log.error(cause.getMessage(), cause);
+        }
+    }
 
-};
+}

Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerHttp2EventHandlerFactory.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerHttp2EventHandlerFactory.java?rev=1761318&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerHttp2EventHandlerFactory.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerHttp2EventHandlerFactory.java Sun Sep 18 11:29:30 2016
@@ -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.core5.http2.integration;
+
+import java.nio.charset.Charset;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.http2.impl.nio.HttpErrorListener;
+import org.apache.hc.core5.http2.impl.nio.ServerHttp2StreamMultiplexer;
+import org.apache.hc.core5.http2.impl.nio.ServerHttpProtocolNegotiator;
+import org.apache.hc.core5.http2.nio.AsyncExchangeHandler;
+import org.apache.hc.core5.http2.nio.HandlerFactory;
+import org.apache.hc.core5.reactor.IOEventHandler;
+import org.apache.hc.core5.reactor.IOEventHandlerFactory;
+import org.apache.hc.core5.reactor.IOSession;
+
+public class InternalServerHttp2EventHandlerFactory implements IOEventHandlerFactory {
+
+    private static final AtomicLong COUNT = new AtomicLong();
+
+    private final HandlerFactory<AsyncExchangeHandler> exchangeHandlerFactory;
+    private final Charset charset;
+    private final H2Config h2Config;
+
+    public InternalServerHttp2EventHandlerFactory(
+            final HandlerFactory<AsyncExchangeHandler> exchangeHandlerFactory,
+            final Charset charset,
+            final H2Config h2Config) {
+        this.exchangeHandlerFactory = exchangeHandlerFactory;
+        this.charset = charset;
+        this.h2Config = h2Config;
+    }
+
+    @Override
+    public IOEventHandler createHandler(final IOSession ioSession) {
+        final String id = "http2-incoming-" + COUNT.incrementAndGet();
+        final Log sessionLog = LogFactory.getLog(ioSession.getClass());
+        final InternalHttp2StreamListener streamListener = new InternalHttp2StreamListener(id);
+        final HttpErrorListener errorListener = new InternalHttpErrorListener(sessionLog);
+        return new ServerHttpProtocolNegotiator(exchangeHandlerFactory, charset, h2Config, streamListener, errorListener) {
+
+            @Override
+            protected ServerHttp2StreamMultiplexer createStreamMultiplexer(final IOSession ioSession) {
+                return super.createStreamMultiplexer(new LoggingIOSession(ioSession, id, sessionLog));
+            }
+        };
+
+    }
+}

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerHttp2EventHandlerFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerHttp2EventHandlerFactory.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerHttp2EventHandlerFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerTestBase.java (from r1761317, httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/frame/FrameConsts.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerTestBase.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerTestBase.java&p1=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/frame/FrameConsts.java&r1=1761317&r2=1761318&rev=1761318&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/frame/FrameConsts.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/InternalServerTestBase.java Sun Sep 18 11:29:30 2016
@@ -24,17 +24,37 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.hc.core5.http2.frame;
 
-public final class FrameConsts {
+package org.apache.hc.core5.http2.integration;
 
-    private FrameConsts() {
-        // Do not allow utility class to be instantiated.
-    }
+import java.util.concurrent.TimeUnit;
 
-    public final static int HEAD_LEN = 9;
-    public final static int MAX_PADDING = 255;
-    public final static int MIN_FRAME_SIZE = 2 ^ 14;
-    public final static int MAX_FRAME_SIZE = 2 ^ 24 - 1;
+import org.junit.Rule;
+import org.junit.rules.ExternalResource;
 
-};
+public abstract class InternalServerTestBase {
+
+    protected Http2TestServer server;
+
+    @Rule
+    public ExternalResource serverResource = new ExternalResource() {
+
+        @Override
+        protected void before() throws Throwable {
+            server = new Http2TestServer();
+        }
+
+        @Override
+        protected void after() {
+            if (server != null) {
+                try {
+                    server.shutdown(3, TimeUnit.SECONDS);
+                    server = null;
+                } catch (Exception ignore) {
+                }
+            }
+        }
+
+    };
+
+}

Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LogAppendable.java (from r1761317, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/RequestUserAgent.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LogAppendable.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LogAppendable.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/RequestUserAgent.java&r1=1761317&r2=1761318&rev=1761318&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/RequestUserAgent.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LogAppendable.java Sun Sep 18 11:29:30 2016
@@ -25,44 +25,52 @@
  *
  */
 
-package org.apache.hc.core5.http.protocol;
+package org.apache.hc.core5.http2.integration;
 
 import java.io.IOException;
 
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpHeaders;
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.HttpRequestInterceptor;
-import org.apache.hc.core5.util.Args;
-
-/**
- * RequestUserAgent is responsible for adding {@code User-Agent} header.
- * This interceptor is recommended for client side protocol processors.
- *
- * @since 4.0
- */
-@Contract(threading = ThreadingBehavior.IMMUTABLE)
-public class RequestUserAgent implements HttpRequestInterceptor {
+import org.apache.commons.logging.Log;
 
-    private final String userAgent;
+class LogAppendable implements Appendable {
 
-    public RequestUserAgent(final String userAgent) {
-        super();
-        this.userAgent = userAgent;
+    private final Log log;
+    private final String prefix;
+    private final StringBuilder buffer;
+
+    LogAppendable(final Log log, final String prefix) {
+        this.log = log;
+        this.prefix = prefix;
+        this.buffer = new StringBuilder();
+    }
+
+    @Override
+    public Appendable append(final CharSequence text) throws IOException {
+        return append(text, 0, text.length());
     }
 
-    public RequestUserAgent() {
-        this(null);
+    @Override
+    public Appendable append(final CharSequence text, final int start, final int end) throws IOException {
+        for (int i = start; i < end; i++) {
+            append(text.charAt(i));
+        }
+        return this;
     }
 
     @Override
-    public void process(final ClassicHttpRequest request, final HttpContext context)
-        throws HttpException, IOException {
-        Args.notNull(request, "HTTP request");
-        if (!request.containsHeader(HttpHeaders.USER_AGENT) && this.userAgent != null) {
-            request.addHeader(HttpHeaders.USER_AGENT, this.userAgent);
+    public Appendable append(final char ch) throws IOException {
+        if (ch == '\n') {
+            log.debug(prefix + " " + buffer.toString());
+            buffer.setLength(0);
+        } else if (ch != '\r') {
+            buffer.append(ch);
+        }
+        return this;
+    }
+
+    public void flush() {
+        if (buffer.length() > 0) {
+            log.debug(prefix + " " + buffer.toString());
+            buffer.setLength(0);
         }
     }
 

Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LoggingIOSession.java (from r1761317, httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/testserver/nio/LoggingIOSession.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LoggingIOSession.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LoggingIOSession.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/testserver/nio/LoggingIOSession.java&r1=1761317&r2=1761318&rev=1761318&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/testserver/nio/LoggingIOSession.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LoggingIOSession.java Sun Sep 18 11:29:30 2016
@@ -25,15 +25,15 @@
  *
  */
 
-package org.apache.hc.core5.http.testserver.nio;
+package org.apache.hc.core5.http2.integration;
 
-import java.io.IOException;
 import java.net.SocketAddress;
-import java.nio.ByteBuffer;
 import java.nio.channels.ByteChannel;
 import java.nio.channels.SelectionKey;
+import java.util.Deque;
 
 import org.apache.commons.logging.Log;
+import org.apache.hc.core5.reactor.Command;
 import org.apache.hc.core5.reactor.IOEventHandler;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.SessionBufferStatus;
@@ -41,28 +41,28 @@ import org.apache.hc.core5.reactor.Sessi
 /**
  * Decorator class intended to transparently extend an {@link IOSession}
  * with basic event logging capabilities using Commons Logging.
- *
  */
-public class LoggingIOSession implements IOSession {
+class LoggingIOSession implements IOSession {
 
     private final Log log;
-    private final Wire wirelog;
     private final String id;
     private final IOSession session;
-    private final ByteChannel channel;
 
-    public LoggingIOSession(final IOSession session, final String id, final Log log, final Log wirelog) {
+    LoggingIOSession(final IOSession session, final String id, final Log log) {
         super();
         this.session = session;
-        this.channel = new LoggingByteChannel();
         this.id = id;
         this.log = log;
-        this.wirelog = new Wire(wirelog, this.id);
+    }
+
+    @Override
+    public Deque<Command> getCommandQueue() {
+        return this.session.getCommandQueue();
     }
 
     @Override
     public ByteChannel channel() {
-        return this.channel;
+        return this.session.channel();
     }
 
     @Override
@@ -213,53 +213,4 @@ public class LoggingIOSession implements
         return this.id + " " + this.session.toString();
     }
 
-    class LoggingByteChannel implements ByteChannel {
-
-        @Override
-        public int read(final ByteBuffer dst) throws IOException {
-            final int bytesRead = session.channel().read(dst);
-            if (log.isDebugEnabled()) {
-                log.debug(id + " " + session + ": " + bytesRead + " bytes read");
-            }
-            if (bytesRead > 0 && wirelog.isEnabled()) {
-                final ByteBuffer b = dst.duplicate();
-                final int p = b.position();
-                b.limit(p);
-                b.position(p - bytesRead);
-                wirelog.input(b);
-            }
-            return bytesRead;
-        }
-
-        @Override
-        public int write(final ByteBuffer src) throws IOException {
-            final int byteWritten = session.channel().write(src);
-            if (log.isDebugEnabled()) {
-                log.debug(id + " " + session + ": " + byteWritten + " bytes written");
-            }
-            if (byteWritten > 0 && wirelog.isEnabled()) {
-                final ByteBuffer b = src.duplicate();
-                final int p = b.position();
-                b.limit(p);
-                b.position(p - byteWritten);
-                wirelog.output(b);
-            }
-            return byteWritten;
-        }
-
-        @Override
-        public void close() throws IOException {
-            if (log.isDebugEnabled()) {
-                log.debug(id + " " + session + ": Channel close");
-            }
-            session.channel().close();
-        }
-
-        @Override
-        public boolean isOpen() {
-            return session.channel().isOpen();
-        }
-
-    }
-
 }



Mime
View raw message