[prev in list] [next in list] [prev in thread] [next in thread] 

List:       httpcomponents-commits
Subject:    svn commit: r1761318 [6/8] - in /httpcomponents/httpcore/trunk: httpcore5-h2/src/main/java/org/apach
From:       olegk () apache ! org
Date:       2016-09-18 11:29:33
Message-ID: 20160918112935.1E04E3A1FA8 () svn01-us-west ! apache ! org
[Download RAW message or body]

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=httpcompo \
nents/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=httpcomponen \
ts/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/Int \
ernalServerTestBase.java&p1=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/o \
rg/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/httpco \
re/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LogAppendabl \
e.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/htt \
pcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/integration/LoggingIO \
Session.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/co \
re5/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();
-        }
-
-    }
-
 }


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic