[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