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