You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2016/04/06 09:21:14 UTC
svn commit: r1737929 [1/2] - in /httpcomponents/httpcore/trunk:
httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/
httpcore5-h2/src/main/java/org/apache/hc/core5/http2/
httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/ httpcore5-h...
Author: olegk
Date: Wed Apr 6 07:21:14 2016
New Revision: 1737929
URL: http://svn.apache.org/viewvc?rev=1737929&view=rev
Log:
RFC 7540: HTTP/2 message parsers and writers
Added:
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoRequestHeaders.java
- copied, changed from r1735768, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriterFactory.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoResponseHeaders.java
- copied, changed from r1735768, httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackException.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageParser.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageWriter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestParser.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestWriter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseParser.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseWriter.java
- copied, changed from r1735768, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriter.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageParser.java
- copied, changed from r1735768, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriter.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageWriter.java
- copied, changed from r1735768, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriter.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestParser.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestWriter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2ResponseParser.java (with props)
httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2ResponseWriter.java (with props)
Modified:
httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkWorker.java
httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/HttpBenchmark.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java
httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackException.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/HttpRequest.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/MessageHead.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestWriter.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestWriter.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/HttpAsyncRequestExecutor.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/HttpAsyncService.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/UriHttpAsyncRequestHandlerMapper.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageParser.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageParserFactory.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriter.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriterFactory.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/UriHttpRequestHandlerMapper.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/message/BasicHttpRequest.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/message/HeaderGroup.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageParser.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageParserFactory.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriter.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriterFactory.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/RequestTargetHost.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/RequestValidateHost.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestDefaultBHttpServerConnection.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestRequestParser.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestDefaultNHttpServerConnection.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/impl/nio/TestHttpMessageParser.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/integration/SimpleRequestHandler.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/integration/TestHttpAsyncHandlers.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/integration/TestSyncHttp.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/message/TestBasicMessages.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestStandardInterceptors.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/testserver/io/HttpClient.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/testserver/io/LoggingBHttpClientConnection.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/testserver/io/LoggingBHttpServerConnection.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/testserver/nio/LoggingNHttpClientConnection.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/testserver/nio/LoggingNHttpServerConnection.java
Modified: httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkWorker.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkWorker.java?rev=1737929&r1=1737928&r2=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkWorker.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/BenchmarkWorker.java Wed Apr 6 07:21:14 2016
@@ -70,17 +70,20 @@ class BenchmarkWorker implements Runnabl
private final HttpProcessor httpProcessor;
private final HttpRequestExecutor httpexecutor;
private final ConnectionReuseStrategy connstrategy;
+ private final HttpHost host;
private final HttpRequest request;
private final Config config;
private final SocketFactory socketFactory;
private final Stats stats = new Stats();
public BenchmarkWorker(
+ final HttpHost host,
final HttpRequest request,
final SocketFactory socketFactory,
final Config config) {
super();
this.context = new HttpCoreContext();
+ this.host = host;
this.request = request;
this.config = config;
final HttpProcessorBuilder builder = HttpProcessorBuilder.create()
@@ -105,10 +108,9 @@ class BenchmarkWorker implements Runnabl
final HttpVersion version = config.isUseHttp1_0() ? HttpVersion.HTTP_1_0 : HttpVersion.HTTP_1_1;
final BenchmarkConnection conn = new BenchmarkConnection(8 * 1024, stats);
- final HttpHost targetHost = this.request.getHost();
- final String scheme = targetHost.getSchemeName();
- final String hostname = targetHost.getHostName();
- int port = targetHost.getPort();
+ final String scheme = this.host.getSchemeName();
+ final String hostname = this.host.getHostName();
+ int port = this.host.getPort();
if (port == -1) {
if (scheme.equalsIgnoreCase("https")) {
port = 443;
@@ -233,7 +235,7 @@ class BenchmarkWorker implements Runnabl
private void verboseOutput(final HttpResponse response) {
if (config.getVerbosity() >= 3) {
- System.out.println(">> " + request.getMethod() + " " + request.getUri());
+ System.out.println(">> " + request.getMethod() + " " + request.getPath());
final Header[] headers = request.getAllHeaders();
for (final Header header : headers) {
System.out.println(">> " + header.toString());
Modified: httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/HttpBenchmark.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/HttpBenchmark.java?rev=1737929&r1=1737928&r2=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/HttpBenchmark.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-ab/src/main/java/org/apache/hc/core5/http/benchmark/HttpBenchmark.java Wed Apr 6 07:21:14 2016
@@ -152,7 +152,8 @@ public class HttpBenchmark {
if (config.getSoapAction() != null && config.getSoapAction().length() > 0) {
request.addHeader(new DefaultHeader("SOAPAction", config.getSoapAction()));
}
- request.setHost(host);
+ request.setScheme(host.getSchemeName());
+ request.setAuthority(host.toHostString());
return request;
}
@@ -212,6 +213,7 @@ public class HttpBenchmark {
final BenchmarkWorker[] workers = new BenchmarkWorker[config.getThreads()];
for (int i = 0; i < workers.length; i++) {
workers[i] = new BenchmarkWorker(
+ host,
createRequest(host),
socketFactory,
config);
Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoRequestHeaders.java (from r1735768, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriterFactory.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoRequestHeaders.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoRequestHeaders.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriterFactory.java&r1=1735768&r2=1737929&rev=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriterFactory.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoRequestHeaders.java Wed Apr 6 07:21:14 2016
@@ -25,17 +25,16 @@
*
*/
-package org.apache.hc.core5.http.nio;
-
-import org.apache.hc.core5.http.HttpMessage;
+package org.apache.hc.core5.http2;
/**
- * Factory for {@link org.apache.hc.core5.http.nio.NHttpMessageWriter} instances.
- *
- * @since 4.3
+ * @since 5.0
*/
-public interface NHttpMessageWriterFactory<T extends HttpMessage> {
+public final class H2PseudoRequestHeaders {
- NHttpMessageWriter<T> create();
+ public static final String METHOD = ":method";
+ public static final String SCHEME = ":scheme";
+ public static final String AUTHORITY = ":authority";
+ public static final String PATH = ":path";
}
Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoResponseHeaders.java (from r1735768, httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackException.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoResponseHeaders.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoResponseHeaders.java&p1=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackException.java&r1=1735768&r2=1737929&rev=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackException.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2PseudoResponseHeaders.java Wed Apr 6 07:21:14 2016
@@ -24,14 +24,14 @@
* <http://www.apache.org/>.
*
*/
-package org.apache.hc.core5.http2.hpack;
-import java.io.IOException;
+package org.apache.hc.core5.http2;
-public class HPackException extends IOException {
+/**
+ * @since 5.0
+ */
+public final class H2PseudoResponseHeaders {
- public HPackException(final String message) {
- super(message);
- }
+ public static final String STATUS = ":status";
-};
+}
Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java?rev=1737929&r1=1737928&r2=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackDecoder.java Wed Apr 6 07:21:14 2016
@@ -250,29 +250,32 @@ public final class HPackDecoder {
return existing;
}
- public Header decodeHeader(final ByteBuffer src) throws HPackException, CharacterCodingException {
-
- while (src.hasRemaining()) {
- final int b = peekByte(src);
- if ((b & 0x80) == 0x80) {
- return decodeIndexedHeader(src);
- } else if ((b & 0xc0) == 0x40) {
- return decodeLiteralHeader(src, HPackRepresentation.WITH_INDEXING);
- } else if ((b & 0xf0) == 0x00) {
- return decodeLiteralHeader(src, HPackRepresentation.WITHOUT_INDEXING);
- } else if ((b & 0xf0) == 0x10) {
- return decodeLiteralHeader(src, HPackRepresentation.NEVER_INDEXED);
- } else if ((b & 0xe0) == 0x20) {
- final int maxSize = decodeInt(src, 5);
- this.dynamicTable.setMaxSize(Math.min(this.maxTableSize, maxSize));
- } else {
- throw new HPackException("Unexpected header first byte: 0x" + Integer.toHexString(b));
+ public Header decodeHeader(final ByteBuffer src) throws HPackException {
+ try {
+ while (src.hasRemaining()) {
+ final int b = peekByte(src);
+ if ((b & 0x80) == 0x80) {
+ return decodeIndexedHeader(src);
+ } else if ((b & 0xc0) == 0x40) {
+ return decodeLiteralHeader(src, HPackRepresentation.WITH_INDEXING);
+ } else if ((b & 0xf0) == 0x00) {
+ return decodeLiteralHeader(src, HPackRepresentation.WITHOUT_INDEXING);
+ } else if ((b & 0xf0) == 0x10) {
+ return decodeLiteralHeader(src, HPackRepresentation.NEVER_INDEXED);
+ } else if ((b & 0xe0) == 0x20) {
+ final int maxSize = decodeInt(src, 5);
+ this.dynamicTable.setMaxSize(Math.min(this.maxTableSize, maxSize));
+ } else {
+ throw new HPackException("Unexpected header first byte: 0x" + Integer.toHexString(b));
+ }
}
+ return null;
+ } catch (CharacterCodingException ex) {
+ throw new HPackException(ex.getMessage(), ex);
}
- return null;
}
- public List<Header> decodeHeaders(final ByteBuffer src) throws HPackException, CharacterCodingException {
+ public List<Header> decodeHeaders(final ByteBuffer src) throws HPackException {
final List<Header> list = new ArrayList<>();
while (src.hasRemaining()) {
Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java?rev=1737929&r1=1737928&r2=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackEncoder.java Wed Apr 6 07:21:14 2016
@@ -191,6 +191,12 @@ public final class HPackEncoder {
void encodeLiteralHeader(
final ByteArrayBuffer dst, final HPackEntry existing, final Header header,
final HPackRepresentation representation, final boolean useHuffman) throws CharacterCodingException, HPackException {
+ encodeLiteralHeader(dst, existing, header.getName(), header.getValue(), header.isSensitive(), representation, useHuffman);
+ }
+
+ void encodeLiteralHeader(
+ final ByteArrayBuffer dst, final HPackEntry existing, final String key, final String value, final boolean sensitive,
+ final HPackRepresentation representation, final boolean useHuffman) throws CharacterCodingException, HPackException {
final int n;
final int mask;
@@ -214,14 +220,14 @@ public final class HPackEncoder {
final int nameLen;
if (index <= 0) {
encodeInt(dst, n, 0, mask);
- nameLen = encodeString(dst, header.getName(), useHuffman);
+ nameLen = encodeString(dst, key, useHuffman);
} else {
encodeInt(dst, n, index, mask);
nameLen = existing.getHeader().getNameLen();
}
- final int valueLen = encodeString(dst, header.getValue(), useHuffman);
+ final int valueLen = encodeString(dst, value != null ? value : "", useHuffman);
if (representation == HPackRepresentation.WITH_INDEXING) {
- dynamicTable.add(new HPackHeader(header.getName(), nameLen, header.getValue(), valueLen, header.isSensitive()));
+ dynamicTable.add(new HPackHeader(key, nameLen, value, valueLen, sensitive));
}
}
@@ -245,9 +251,15 @@ public final class HPackEncoder {
void encodeHeader(
final ByteArrayBuffer dst, final Header header,
final boolean noIndexing, final boolean useHuffman) throws CharacterCodingException, HPackException {
+ encodeHeader(dst, header.getName(), header.getValue(), header.isSensitive(), noIndexing, useHuffman);
+ }
+
+ void encodeHeader(
+ final ByteArrayBuffer dst, final String name, final String value, final boolean sensitive,
+ final boolean noIndexing, final boolean useHuffman) throws CharacterCodingException, HPackException {
final HPackRepresentation representation;
- if (header.isSensitive()) {
+ if (sensitive) {
representation = HPackRepresentation.NEVER_INDEXED;
} else if (noIndexing) {
representation = HPackRepresentation.WITHOUT_INDEXING;
@@ -255,10 +267,7 @@ public final class HPackEncoder {
representation = HPackRepresentation.WITH_INDEXING;
}
- final String key = header.getName();
- final String value = header.getValue();
-
- final List<HPackEntry> staticEntries = StaticTable.INSTANCE.getByName(key);
+ final List<HPackEntry> staticEntries = StaticTable.INSTANCE.getByName(name);
if (representation == HPackRepresentation.WITH_INDEXING) {
// Try to find full match and encode as as index
@@ -267,7 +276,7 @@ public final class HPackEncoder {
encodeIndex(dst, staticIndex);
return;
}
- final List<HPackEntry> dynamicEntries = dynamicTable.getByName(key);
+ final List<HPackEntry> dynamicEntries = dynamicTable.getByName(name);
final int dynamicIndex = findFullMatch(dynamicEntries, value);
if (dynamicIndex > 0) {
encodeIndex(dst, dynamicIndex);
@@ -279,29 +288,48 @@ public final class HPackEncoder {
if (staticEntries != null && !staticEntries.isEmpty()) {
existing = staticEntries.get(0);
} else {
- final List<HPackEntry> dynamicEntries = dynamicTable.getByName(key);
+ final List<HPackEntry> dynamicEntries = dynamicTable.getByName(name);
if (dynamicEntries != null && !dynamicEntries.isEmpty()) {
existing = dynamicEntries.get(0);
}
}
- encodeLiteralHeader(dst, existing, header, representation, useHuffman);
+ encodeLiteralHeader(dst, existing, name, value, sensitive, representation, useHuffman);
}
void encodeHeaders(
final ByteArrayBuffer dst, final List<Header> headers,
- final boolean noIndexing, final boolean useHuffman) throws CharacterCodingException, HPackException {
+ final boolean noIndexing, final boolean useHuffman) throws HPackException {
for (int i = 0; i < headers.size(); i++) {
- encodeHeader(dst, headers.get(i), noIndexing, useHuffman);
+ try {
+ encodeHeader(dst, headers.get(i), noIndexing, useHuffman);
+ } catch (CharacterCodingException ex) {
+ throw new HPackException(ex.getMessage(), ex);
+ }
}
}
public void encodeHeader(
- final ByteArrayBuffer dst, final Header header) throws CharacterCodingException, HPackException {
- encodeHeader(dst, header, false, true);
+ final ByteArrayBuffer dst, final Header header) throws HPackException {
+ Args.notNull(dst, "ByteArrayBuffer");
+ Args.notNull(header, "Header");
+ encodeHeader(dst, header.getName(), header.getValue(), header.isSensitive());
+ }
+
+ public void encodeHeader(
+ final ByteArrayBuffer dst, final String name, final String value, final boolean sensitive) throws HPackException {
+ Args.notNull(dst, "ByteArrayBuffer");
+ Args.notEmpty(name, "Header name");
+ try {
+ encodeHeader(dst, name, value, sensitive, false, true);
+ } catch (CharacterCodingException ex) {
+ throw new HPackException(ex.getMessage(), ex);
+ }
}
public void encodeHeaders(
- final ByteArrayBuffer dst, final List<Header> headers) throws CharacterCodingException, HPackException {
+ final ByteArrayBuffer dst, final List<Header> headers) throws HPackException {
+ Args.notNull(dst, "ByteArrayBuffer");
+ Args.notEmpty(headers, "Header list");
encodeHeaders(dst, headers, false, true);
}
Modified: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackException.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackException.java?rev=1737929&r1=1737928&r2=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackException.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/hpack/HPackException.java Wed Apr 6 07:21:14 2016
@@ -26,12 +26,16 @@
*/
package org.apache.hc.core5.http2.hpack;
-import java.io.IOException;
+import org.apache.hc.core5.http.HttpException;
-public class HPackException extends IOException {
+public class HPackException extends HttpException {
public HPackException(final String message) {
super(message);
}
+ public HPackException(final String message, final Exception cause) {
+ super(message, cause);
+ }
+
};
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageParser.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageParser.java?rev=1737929&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageParser.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageParser.java Wed Apr 6 07:21:14 2016
@@ -0,0 +1,106 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.impl.io;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.hc.core5.annotation.NotThreadSafe;
+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.HttpMessage;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http2.hpack.HPackDecoder;
+import org.apache.hc.core5.http2.io.Http2MessageParser;
+
+/**
+ * Abstract base class for HTTP message parsers that read input in HPACk format from an input buffer.
+ *
+ * @since 5.0
+ */
+@NotThreadSafe
+public abstract class AbstractHttp2MessageParser<T extends HttpMessage> implements Http2MessageParser<T> {
+
+ private final HPackDecoder decoder;
+
+ public AbstractHttp2MessageParser(final Charset charset) {
+ this.decoder = new HPackDecoder(charset);
+ }
+
+ public int getMaxTableSize() {
+ return this.decoder.getMaxTableSize();
+ }
+
+ public void setMaxTableSize(final int maxTableSize) {
+ this.decoder.setMaxTableSize(maxTableSize);
+ }
+
+ @Override
+ public final T parse(final ByteBuffer src) throws HttpException {
+ final List<Header> pseudoHeaders = new ArrayList<>();
+ final List<Header> headers = new ArrayList<>();
+ boolean pseudoHeaderCompleted = false;
+ while (src.hasRemaining()) {
+ final Header header = this.decoder.decodeHeader(src);
+ if (header == null) {
+ break;
+ } else {
+ final String name = header.getName();
+ for (int i = 0; i < name.length(); i++) {
+ final char ch = name.charAt(i);
+ if (Character.isAlphabetic(ch) && !Character.isLowerCase(ch)) {
+ throw new ProtocolException("Header name '" + name + "' is invalid (header name contains uppercase characters)");
+ }
+ }
+ if (name.startsWith(":")) {
+ if (pseudoHeaderCompleted) {
+ throw new ProtocolException("Invalid sequence of headers (pseudo-headers must precede message headers)");
+ }
+ pseudoHeaders.add(header);
+ } else {
+ pseudoHeaderCompleted = true;
+ if (name.equalsIgnoreCase(HttpHeaders.CONNECTION)) {
+ throw new ProtocolException("Header '" + header.getName() + ": " + header.getValue() + "' is illegal for HTTP/2 messages");
+ }
+ headers.add(header);
+ }
+ }
+ }
+ final T message = createMessage(pseudoHeaders);
+ for (int i = 0; i < headers.size(); i++) {
+ message.addHeader(headers.get(i));
+ }
+ return message;
+ }
+
+ protected abstract T createMessage(List<Header> pseudoHeaders) throws HttpException;
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageParser.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageParser.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageWriter.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageWriter.java?rev=1737929&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageWriter.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageWriter.java Wed Apr 6 07:21:14 2016
@@ -0,0 +1,89 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.impl.io;
+
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.Locale;
+
+import org.apache.hc.core5.annotation.NotThreadSafe;
+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.HttpMessage;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http2.hpack.HPackEncoder;
+import org.apache.hc.core5.http2.io.Http2MessageWriter;
+import org.apache.hc.core5.util.ByteArrayBuffer;
+
+/**
+ * Abstract base class for HTTP message writers that serialize output in HPACK format to a output buffer.
+ *
+ * @since 5.0
+ */
+@NotThreadSafe
+public abstract class AbstractHttp2MessageWriter<T extends HttpMessage> implements Http2MessageWriter<T> {
+
+ private final HPackEncoder encoder;
+
+ public AbstractHttp2MessageWriter(final Charset charset) {
+ this.encoder = new HPackEncoder(charset);
+ }
+
+ public int getMaxTableSize() {
+ return this.encoder.getMaxTableSize();
+ }
+
+ public void setMaxTableSize(final int maxTableSize) {
+ this.encoder.setMaxTableSize(maxTableSize);
+ }
+
+ protected HPackEncoder getEncoder() {
+ return encoder;
+ }
+
+ @Override
+ public final void write(final T message, final ByteArrayBuffer dst) throws HttpException {
+
+ writePseudoHeaders(message, dst);
+ for (final Iterator<Header> it = message.headerIterator(); it.hasNext(); ) {
+ final Header header = it.next();
+ final String name = header.getName();
+ if (name.startsWith(":")) {
+ throw new ProtocolException("Header name '" + name + "' is invalid");
+ }
+ if (name.equalsIgnoreCase(HttpHeaders.CONNECTION)) {
+ throw new ProtocolException("Header '" + header.getName() + ": " + header.getValue() + "' is illegal for HTTP/2 messages");
+ }
+ this.encoder.encodeHeader(dst, header.getName().toLowerCase(Locale.ROOT), header.getValue(), header.isSensitive());
+ }
+ }
+
+ protected abstract void writePseudoHeaders(T message, ByteArrayBuffer buffer) throws HttpException;
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageWriter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageWriter.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/AbstractHttp2MessageWriter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestParser.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestParser.java?rev=1737929&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestParser.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestParser.java Wed Apr 6 07:21:14 2016
@@ -0,0 +1,124 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.impl.io;
+
+import java.nio.charset.Charset;
+import java.util.List;
+
+import org.apache.hc.core5.annotation.NotThreadSafe;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpRequestFactory;
+import org.apache.hc.core5.http.HttpVersion;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.impl.DefaultHttpRequestFactory;
+import org.apache.hc.core5.http2.H2PseudoRequestHeaders;
+
+/**
+ * HTTP/2 request parser.
+ *
+ * @since 5.0
+ */
+@NotThreadSafe
+public class Http2RequestParser extends AbstractHttp2MessageParser<HttpRequest> {
+
+ private final HttpRequestFactory requestFactory;
+
+ public Http2RequestParser(final Charset charset, final HttpRequestFactory requestFactory) {
+ super(charset);
+ this.requestFactory = requestFactory != null ? requestFactory : DefaultHttpRequestFactory.INSTANCE;
+ }
+
+ public Http2RequestParser(final Charset charset) {
+ this(charset, null);
+ }
+
+ @Override
+ protected HttpRequest createMessage(final List<Header> pseudoHeaders) throws HttpException {
+ String method = null;
+ String scheme = null;
+ String authority = null;
+ String path = null;
+
+ for (int i = 0; i < pseudoHeaders.size(); i++) {
+ final Header header = pseudoHeaders.get(i);
+ final String name = header.getName();
+ final String value = header.getValue();
+ if (name.equals(H2PseudoRequestHeaders.METHOD)) {
+ if (method != null) {
+ throw new ProtocolException("Multiple '" + name + "' request headers are illegal");
+ }
+ method = value;
+ } else if (name.equals(H2PseudoRequestHeaders.SCHEME)) {
+ if (scheme != null) {
+ throw new ProtocolException("Multiple '" + name + "' request headers are illegal");
+ }
+ scheme = value;
+ } else if (name.equals(H2PseudoRequestHeaders.PATH)) {
+ if (path != null) {
+ throw new ProtocolException("Multiple '" + name + "' request headers are illegal");
+ }
+ path = value;
+ } else if (name.equals(H2PseudoRequestHeaders.AUTHORITY)) {
+ authority = value;
+ } else {
+ throw new ProtocolException("Unsupported request header '" + name + "'");
+ }
+ }
+ if (method == null) {
+ throw new ProtocolException("Mandatory request header ':method' not found");
+ }
+ if (method.equalsIgnoreCase("CONNECT")) {
+ if (authority == null) {
+ throw new ProtocolException("Header ':authority' is mandatory for CONNECT request");
+ }
+ if (scheme != null) {
+ throw new ProtocolException("Header ':scheme' must not be set for CONNECT request");
+ }
+ if (path != null) {
+ throw new ProtocolException("Header ':path' must not be set for CONNECT request");
+ }
+ } else {
+ if (scheme == null) {
+ throw new ProtocolException("Mandatory request header ':scheme' not found");
+ }
+ if (path == null) {
+ throw new ProtocolException("Mandatory request header ':path' not found");
+ }
+ }
+
+ final HttpRequest httpRequest = this.requestFactory.newHttpRequest(HttpVersion.HTTP_2, method, path);
+ httpRequest.setScheme(scheme);
+ httpRequest.setAuthority(authority);
+ httpRequest.setPath(path);
+
+ return httpRequest;
+ }
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestParser.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestParser.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestWriter.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestWriter.java?rev=1737929&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestWriter.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestWriter.java Wed Apr 6 07:21:14 2016
@@ -0,0 +1,87 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.impl.io;
+
+import java.nio.charset.Charset;
+
+import org.apache.hc.core5.annotation.NotThreadSafe;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http2.H2PseudoRequestHeaders;
+import org.apache.hc.core5.http2.hpack.HPackEncoder;
+import org.apache.hc.core5.util.ByteArrayBuffer;
+import org.apache.hc.core5.util.TextUtils;
+
+/**
+ * HTTP/2 request writer.
+ *
+ * @since 5.0
+ */
+@NotThreadSafe
+public class Http2RequestWriter extends AbstractHttp2MessageWriter<HttpRequest> {
+
+ public Http2RequestWriter(final Charset charset) {
+ super(charset);
+ }
+
+ @Override
+ protected void writePseudoHeaders(final HttpRequest message, final ByteArrayBuffer buffer) throws HttpException {
+ if (TextUtils.isBlank(message.getMethod())) {
+ throw new ProtocolException("Request method is empty");
+ }
+ final boolean optionMethod = "CONNECT".equalsIgnoreCase(message.getMethod());
+ if (optionMethod) {
+ if (TextUtils.isBlank(message.getAuthority())) {
+ throw new ProtocolException("CONNECT request authority is not set");
+ }
+ if (message.getPath() != null) {
+ throw new ProtocolException("CONNECT request path must be null");
+ }
+ } else {
+ if (TextUtils.isBlank(message.getScheme())) {
+ throw new ProtocolException("Request scheme is not set");
+ }
+ if (TextUtils.isBlank(message.getPath())) {
+ throw new ProtocolException("Request path is not set");
+ }
+ }
+ final HPackEncoder encoder = getEncoder();
+ encoder.encodeHeader(buffer, H2PseudoRequestHeaders.METHOD, message.getMethod(), false);
+ if (optionMethod) {
+ encoder.encodeHeader(buffer, H2PseudoRequestHeaders.AUTHORITY, message.getAuthority(), false);
+ } else {
+ encoder.encodeHeader(buffer, H2PseudoRequestHeaders.SCHEME, message.getScheme(), false);
+ if (message.getAuthority() != null) {
+ encoder.encodeHeader(buffer, H2PseudoRequestHeaders.AUTHORITY, message.getAuthority(), false);
+ }
+ encoder.encodeHeader(buffer, H2PseudoRequestHeaders.PATH, message.getPath(), false);
+ }
+ }
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestWriter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestWriter.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2RequestWriter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseParser.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseParser.java?rev=1737929&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseParser.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseParser.java Wed Apr 6 07:21:14 2016
@@ -0,0 +1,89 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.impl.io;
+
+import java.nio.charset.Charset;
+import java.util.List;
+
+import org.apache.hc.core5.annotation.NotThreadSafe;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.HttpResponseFactory;
+import org.apache.hc.core5.http.HttpVersion;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.impl.DefaultHttpResponseFactory;
+import org.apache.hc.core5.http2.H2PseudoResponseHeaders;
+
+/**
+ * HTTP/2 response parser.
+ *
+ * @since 5.0
+ */
+@NotThreadSafe
+public class Http2ResponseParser extends AbstractHttp2MessageParser<HttpResponse> {
+
+ private HttpResponseFactory responseFactory;
+
+ public Http2ResponseParser(final Charset charset, final HttpResponseFactory responseFactory) {
+ super(charset);
+ this.responseFactory = responseFactory != null ? responseFactory : DefaultHttpResponseFactory.INSTANCE;
+ }
+
+ public Http2ResponseParser(final Charset charset) {
+ this(charset, null);
+ }
+
+ @Override
+ protected HttpResponse createMessage(final List<Header> pseudoHeaders) throws HttpException {
+ String statusText = null;
+
+ for (int i = 0; i < pseudoHeaders.size(); i++) {
+ final Header header = pseudoHeaders.get(i);
+ final String name = header.getName();
+ final String value = header.getValue();
+ if (name.equals(H2PseudoResponseHeaders.STATUS)) {
+ if (statusText != null) {
+ throw new ProtocolException("Multiple '" + name + "' response headers are illegal");
+ }
+ statusText = value;
+ } else {
+ throw new ProtocolException("Unsupported response header '" + name + "'");
+ }
+ }
+ if (statusText == null) {
+ throw new ProtocolException("Mandatory response header ':status' not found");
+ }
+ try {
+ return this.responseFactory.newHttpResponse(HttpVersion.HTTP_2, Integer.parseInt(statusText), null);
+ } catch (NumberFormatException ex) {
+ throw new ProtocolException("Invalid response status: " + statusText);
+ }
+ }
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseParser.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseParser.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseWriter.java (from r1735768, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriter.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseWriter.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseWriter.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriter.java&r1=1735768&r2=1737929&rev=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/nio/NHttpMessageWriter.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/io/Http2ResponseWriter.java Wed Apr 6 07:21:14 2016
@@ -25,35 +25,38 @@
*
*/
-package org.apache.hc.core5.http.nio;
+package org.apache.hc.core5.http2.impl.io;
-import java.io.IOException;
+import java.nio.charset.Charset;
+import org.apache.hc.core5.annotation.NotThreadSafe;
import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpMessage;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http2.H2PseudoResponseHeaders;
+import org.apache.hc.core5.http2.hpack.HPackEncoder;
+import org.apache.hc.core5.util.ByteArrayBuffer;
/**
- * Abstract HTTP message writer for non-blocking connections.
+ * HTTP/2 response writer.
*
- * @since 4.0
+ * @since 5.0
*/
-public interface NHttpMessageWriter<T extends HttpMessage> {
+@NotThreadSafe
+public class Http2ResponseWriter extends AbstractHttp2MessageWriter<HttpResponse> {
- /**
- * Resets the writer. The writer will be ready to start serializing another
- * HTTP message.
- */
- void reset();
-
- /**
- * Serializes out the HTTP message head.
- *
- * @param message HTTP message.
- * @param buffer session output buffer.
- * @throws IOException in case of an I/O error.
- * @throws HttpException in case the HTTP message is malformed or
- * violates the HTTP protocol.
- */
- void write(T message, SessionOutputBuffer buffer) throws IOException, HttpException;
+ public Http2ResponseWriter(final Charset charset) {
+ super(charset);
+ }
+
+ @Override
+ protected void writePseudoHeaders(final HttpResponse message, final ByteArrayBuffer buffer) throws HttpException {
+ final int code = message.getCode();
+ if (code < 100 || code >= 600) {
+ throw new ProtocolException("Response status " + code + " is invalid");
+ }
+ final HPackEncoder encoder = getEncoder();
+ encoder.encodeHeader(buffer, H2PseudoResponseHeaders.STATUS, Integer.toString(code), false);
+ }
}
Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageParser.java (from r1735768, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriter.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageParser.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageParser.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriter.java&r1=1735768&r2=1737929&rev=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriter.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageParser.java Wed Apr 6 07:21:14 2016
@@ -25,30 +25,30 @@
*
*/
-package org.apache.hc.core5.http.io;
+package org.apache.hc.core5.http2.io;
-import java.io.IOException;
-import java.io.OutputStream;
+import java.nio.ByteBuffer;
import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpMessage;
+import org.apache.hc.core5.http.MessageHead;
/**
- * Abstract message writer intended to serialize HTTP messages to an arbitrary
- * data sink.
+ * Abstract message parser intended to build HTTP message head from an arbitrary data source.
*
- * @since 4.0
+ * @param <T>
+ * {@link MessageHead} or a subclass
+ *
+ * @since 5.0
*/
-public interface HttpMessageWriter<T extends HttpMessage> {
+public interface Http2MessageParser<T extends MessageHead> {
/**
- * Serializes an instance of {@link HttpMessage} to an output buffer.
+ * Generates an instance of {@link MessageHead} from the given input buffer.
*
- * @param message HTTP message
- * @param buffer session output buffer
- * @throws IOException in case of an I/O error
+ * @param buffer input buffer
+ * @return HTTP message head
* @throws HttpException in case of HTTP protocol violation
*/
- void write(T message, SessionOutputBuffer buffer, OutputStream outputStream) throws IOException, HttpException;
+ T parse(ByteBuffer buffer) throws HttpException;
}
Copied: httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageWriter.java (from r1735768, httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriter.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageWriter.java?p2=httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageWriter.java&p1=httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriter.java&r1=1735768&r2=1737929&rev=1737929&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/io/HttpMessageWriter.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/io/Http2MessageWriter.java Wed Apr 6 07:21:14 2016
@@ -25,30 +25,27 @@
*
*/
-package org.apache.hc.core5.http.io;
-
-import java.io.IOException;
-import java.io.OutputStream;
+package org.apache.hc.core5.http2.io;
import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpMessage;
+import org.apache.hc.core5.http.MessageHead;
+import org.apache.hc.core5.util.ByteArrayBuffer;
/**
- * Abstract message writer intended to serialize HTTP messages to an arbitrary
+ * Abstract message writer intended to serialize HTTP message head to an arbitrary
* data sink.
*
* @since 4.0
*/
-public interface HttpMessageWriter<T extends HttpMessage> {
+public interface Http2MessageWriter<T extends MessageHead> {
/**
- * Serializes an instance of {@link HttpMessage} to an output buffer.
+ * Serializes an instance of {@link MessageHead} to the given output buffer.
*
- * @param message HTTP message
- * @param buffer session output buffer
- * @throws IOException in case of an I/O error
+ * @param message HTTP message head
+ * @param buffer output buffer
* @throws HttpException in case of HTTP protocol violation
*/
- void write(T message, SessionOutputBuffer buffer, OutputStream outputStream) throws IOException, HttpException;
+ void write(T message, ByteArrayBuffer buffer) throws HttpException;
}
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestParser.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestParser.java?rev=1737929&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestParser.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestParser.java Wed Apr 6 07:21:14 2016
@@ -0,0 +1,347 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.impl.io;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http2.hpack.HPackEncoder;
+import org.apache.hc.core5.util.ByteArrayBuffer;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class TestHttp2RequestParser {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testBasicParse() throws Exception {
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader("custom123", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ final HttpRequest request = parser.parse(src);
+ Assert.assertNotNull(request);
+ Assert.assertEquals("GET", request.getMethod());
+ Assert.assertEquals("http", request.getScheme());
+ Assert.assertEquals("www.example.com", request.getAuthority());
+ Assert.assertEquals("/", request.getPath());
+ final Header[] allHeaders = request.getAllHeaders();
+ Assert.assertEquals(1, allHeaders.length);
+ Assert.assertEquals("custom123", allHeaders[0].getName());
+ Assert.assertEquals("value", allHeaders[0].getValue());
+ }
+
+ @Test
+ public void testParseUpperCaseHeaderName() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Header name ':Path' is invalid (header name contains uppercase characters)");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":Path", "/"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseConnectionHeader() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Header 'connection: keep-alive' is illegal for HTTP/2 messages");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader("connection", "keep-alive")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParsePseudoHeaderSequence() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Invalid sequence of headers (pseudo-headers must precede message headers)");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader("custom", "value"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseMissingMethod() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Mandatory request header ':method' not found");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseMissingScheme() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Mandatory request header ':scheme' not found");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseMissingPath() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Mandatory request header ':path' not found");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseUnknownPseudoHeader() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Unsupported request header ':custom'");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader(":custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseMultipleMethod() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Multiple ':method' request headers are illegal");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseMultipleScheme() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Multiple ':scheme' request headers are illegal");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader(":scheme", "https"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseMultiplePath() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Multiple ':path' request headers are illegal");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "GET"),
+ new BasicHeader(":scheme", "https"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseConnect() throws Exception {
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "CONNECT"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseConnectMissingAuthority() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Header ':authority' is mandatory for CONNECT request");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "CONNECT"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseConnectPresentScheme() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Header ':scheme' must not be set for CONNECT request");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "CONNECT"),
+ new BasicHeader(":scheme", "http"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+ @Test
+ public void testParseConnectPresentPath() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Header ':path' must not be set for CONNECT request");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+ final HPackEncoder encoder = new HPackEncoder(StandardCharsets.US_ASCII);
+ encoder.encodeHeaders(buf, Arrays.<Header>asList(
+ new BasicHeader(":method", "CONNECT"),
+ new BasicHeader(":authority", "www.example.com"),
+ new BasicHeader(":path", "/"),
+ new BasicHeader("custom", "value")));
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+
+ final Http2RequestParser parser = new Http2RequestParser(StandardCharsets.US_ASCII);
+ parser.parse(src);
+ }
+
+}
+
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestParser.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestParser.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestWriter.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestWriter.java?rev=1737929&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestWriter.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestWriter.java Wed Apr 6 07:21:14 2016
@@ -0,0 +1,207 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http2.impl.io;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.apache.hc.core5.http.Header;
+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.message.BasicHttpRequest;
+import org.apache.hc.core5.http2.hpack.HPackDecoder;
+import org.apache.hc.core5.util.ByteArrayBuffer;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class TestHttp2RequestWriter {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testBasicWrite() throws Exception {
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+
+ final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+ request.addHeader("Custom123", "Value");
+
+ final Http2RequestWriter writer = new Http2RequestWriter(StandardCharsets.US_ASCII);
+ writer.write(request, buf);
+
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+ final HPackDecoder decoder = new HPackDecoder(StandardCharsets.US_ASCII);
+ final List<Header> headers = decoder.decodeHeaders(src);
+
+ Assert.assertNotNull(headers);
+ Assert.assertEquals(5, headers.size());
+ final Header header1 = headers.get(0);
+ Assert.assertEquals(":method", header1.getName());
+ Assert.assertEquals("GET", header1.getValue());
+ final Header header2 = headers.get(1);
+ Assert.assertEquals(":scheme", header2.getName());
+ Assert.assertEquals("http", header2.getValue());
+ final Header header3 = headers.get(2);
+ Assert.assertEquals(":authority", header3.getName());
+ Assert.assertEquals("host", header3.getValue());
+ final Header header4 = headers.get(3);
+ Assert.assertEquals(":path", header4.getName());
+ Assert.assertEquals("/", header4.getValue());
+ final Header header5 = headers.get(4);
+ Assert.assertEquals("custom123", header5.getName());
+ Assert.assertEquals("Value", header5.getValue());
+ }
+
+ @Test
+ public void testWriteMissingScheme() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Request scheme is not set");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+
+ final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+ request.addHeader("Custom123", "Value");
+ request.setScheme(null);
+
+ final Http2RequestWriter writer = new Http2RequestWriter(StandardCharsets.US_ASCII);
+ writer.write(request, buf);
+ }
+
+ @Test
+ public void testWriteMissingPath() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Request path is not set");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+
+ final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+ request.addHeader("Custom123", "Value");
+ request.setPath(null);
+
+ final Http2RequestWriter writer = new Http2RequestWriter(StandardCharsets.US_ASCII);
+ writer.write(request, buf);
+ }
+
+ @Test
+ public void testWriteConnect() throws Exception {
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+
+ final HttpRequest request = new BasicHttpRequest("CONNECT", new HttpHost("host:80"), null);
+ request.addHeader("Custom123", "Value");
+
+ final Http2RequestWriter writer = new Http2RequestWriter(StandardCharsets.US_ASCII);
+ writer.write(request, buf);
+
+ final ByteBuffer src = ByteBuffer.wrap(buf.buffer(), 0, buf.length());
+ final HPackDecoder decoder = new HPackDecoder(StandardCharsets.US_ASCII);
+ final List<Header> headers = decoder.decodeHeaders(src);
+
+ Assert.assertNotNull(headers);
+ Assert.assertEquals(3, headers.size());
+ final Header header1 = headers.get(0);
+ Assert.assertEquals(":method", header1.getName());
+ Assert.assertEquals("CONNECT", header1.getValue());
+ final Header header2 = headers.get(1);
+ Assert.assertEquals(":authority", header2.getName());
+ Assert.assertEquals("host:80", header2.getValue());
+ final Header header3 = headers.get(2);
+ Assert.assertEquals("custom123", header3.getName());
+ Assert.assertEquals("Value", header3.getValue());
+ }
+
+ @Test
+ public void testWriteConnectMissingAuthority() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("CONNECT request authority is not set");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+
+ final HttpRequest request = new BasicHttpRequest("CONNECT", null, null);
+ request.addHeader("Custom123", "Value");
+
+ final Http2RequestWriter writer = new Http2RequestWriter(StandardCharsets.US_ASCII);
+ writer.write(request, buf);
+ }
+
+ @Test
+ public void testWriteConnectWithPath() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("CONNECT request path must be null");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+
+ final HttpRequest request = new BasicHttpRequest("CONNECT", "/");
+ request.setAuthority("host");
+ request.addHeader("Custom123", "Value");
+
+ final Http2RequestWriter writer = new Http2RequestWriter(StandardCharsets.US_ASCII);
+ writer.write(request, buf);
+ }
+
+ @Test
+ public void testWriteConnectionHeader() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Header 'Connection: Keep-Alive' is illegal for HTTP/2 messages");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+
+ final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+ request.addHeader("Connection", "Keep-Alive");
+
+ final Http2RequestWriter writer = new Http2RequestWriter(StandardCharsets.US_ASCII);
+ writer.write(request, buf);
+ }
+
+ @Test
+ public void testWriteInvalidHeader() throws Exception {
+
+ thrown.expect(HttpException.class);
+ thrown.expectMessage("Header name ':custom' is invalid");
+
+ final ByteArrayBuffer buf = new ByteArrayBuffer(128);
+
+ final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+ request.addHeader(":custom", "stuff");
+
+ final Http2RequestWriter writer = new Http2RequestWriter(StandardCharsets.US_ASCII);
+ writer.write(request, buf);
+ }
+
+}
+
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestWriter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestWriter.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/io/TestHttp2RequestWriter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain