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 2021/11/03 09:00:19 UTC

[httpcomponents-core] branch master updated: HTTPCORE-692 add new rules for H2 header check as rfc7540 section 8.1.2.2 and 8.1.2.3 defined

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git


The following commit(s) were added to refs/heads/master by this push:
     new 6741e3c  HTTPCORE-692 add new rules for H2 header check as rfc7540 section 8.1.2.2 and 8.1.2.3 defined
6741e3c is described below

commit 6741e3c555b96c4a64358adcb69aa0fddeb735b1
Author: 风起 <ch...@alibaba-inc.com>
AuthorDate: Wed Nov 3 11:13:24 2021 +0800

    HTTPCORE-692 add new rules for H2 header check as rfc7540 section 8.1.2.2 and 8.1.2.3 defined
---
 .../http2/impl/DefaultH2RequestConverter.java      | 16 ++++-
 .../http2/impl/DefaultH2ResponseConverter.java     |  8 ++-
 .../http2/impl/TestDefaultH2RequestConverter.java  | 83 ++++++++++++++++++++++
 .../http2/impl/TestDefaultH2ResponseConverter.java | 36 ++++++++++
 .../java/org/apache/hc/core5/http/HttpHeaders.java |  2 +
 5 files changed, 139 insertions(+), 6 deletions(-)

diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/DefaultH2RequestConverter.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/DefaultH2RequestConverter.java
index ad94312..d8f2611 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/DefaultH2RequestConverter.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/DefaultH2RequestConverter.java
@@ -106,7 +106,12 @@ public final class DefaultH2RequestConverter implements H2MessageConverter<HttpR
                         throw new ProtocolException("Unsupported request header '%s'", name);
                 }
             } else {
-                if (name.equalsIgnoreCase(HttpHeaders.CONNECTION)) {
+                if (name.equalsIgnoreCase(HttpHeaders.CONNECTION) || name.equalsIgnoreCase(HttpHeaders.KEEP_ALIVE)
+                    || name.equalsIgnoreCase(HttpHeaders.PROXY_CONNECTION) || name.equalsIgnoreCase(HttpHeaders.TRANSFER_ENCODING)
+                    || name.equalsIgnoreCase(HttpHeaders.HOST) || name.equalsIgnoreCase(HttpHeaders.UPGRADE)) {
+                    throw new ProtocolException("Header '%s: %s' is illegal for HTTP/2 messages", header.getName(), header.getValue());
+                }
+                if (name.equalsIgnoreCase(HttpHeaders.TE) && !value.equalsIgnoreCase("trailers")) {
                     throw new ProtocolException("Header '%s: %s' is illegal for HTTP/2 messages", header.getName(), header.getValue());
                 }
                 messageHeaders.add(header);
@@ -189,8 +194,13 @@ public final class DefaultH2RequestConverter implements H2MessageConverter<HttpR
             if (name.startsWith(":")) {
                 throw new ProtocolException("Header name '%s' is invalid", name);
             }
-            if (name.equalsIgnoreCase(HttpHeaders.CONNECTION)) {
-                throw new ProtocolException("Header '%s: %s' is illegal for HTTP/2 messages", name, value);
+            if (name.equalsIgnoreCase(HttpHeaders.CONNECTION) || name.equalsIgnoreCase(HttpHeaders.KEEP_ALIVE)
+                || name.equalsIgnoreCase(HttpHeaders.PROXY_CONNECTION) || name.equalsIgnoreCase(HttpHeaders.TRANSFER_ENCODING)
+                || name.equalsIgnoreCase(HttpHeaders.HOST) || name.equalsIgnoreCase(HttpHeaders.UPGRADE)) {
+                throw new ProtocolException("Header '%s: %s' is illegal for HTTP/2 messages", header.getName(), header.getValue());
+            }
+            if (name.equalsIgnoreCase(HttpHeaders.TE) && !value.equalsIgnoreCase("trailers")) {
+                throw new ProtocolException("Header '%s: %s' is illegal for HTTP/2 messages", header.getName(), header.getValue());
             }
             headers.add(new BasicHeader(TextUtils.toLowerCase(name), value));
         }
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/DefaultH2ResponseConverter.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/DefaultH2ResponseConverter.java
index db71166..0b860be 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/DefaultH2ResponseConverter.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/DefaultH2ResponseConverter.java
@@ -82,7 +82,8 @@ public class DefaultH2ResponseConverter implements H2MessageConverter<HttpRespon
                     throw new ProtocolException("Unsupported response header '%s'", name);
                 }
             } else {
-                if (name.equalsIgnoreCase(HttpHeaders.CONNECTION)) {
+                if (name.equalsIgnoreCase(HttpHeaders.CONNECTION) || name.equalsIgnoreCase(HttpHeaders.KEEP_ALIVE)
+                    || name.equalsIgnoreCase(HttpHeaders.TRANSFER_ENCODING) || name.equalsIgnoreCase(HttpHeaders.UPGRADE)) {
                     throw new ProtocolException("Header '%s: %s' is illegal for HTTP/2 messages", header.getName(), header.getValue());
                 }
                 messageHeaders.add(header);
@@ -123,8 +124,9 @@ public class DefaultH2ResponseConverter implements H2MessageConverter<HttpRespon
             if (name.startsWith(":")) {
                 throw new ProtocolException("Header name '%s' is invalid", name);
             }
-            if (name.equalsIgnoreCase(HttpHeaders.CONNECTION)) {
-                throw new ProtocolException("Header '%s: %s' is illegal for HTTP/2 messages", name, value);
+            if (name.equalsIgnoreCase(HttpHeaders.CONNECTION) || name.equalsIgnoreCase(HttpHeaders.KEEP_ALIVE)
+                || name.equalsIgnoreCase(HttpHeaders.TRANSFER_ENCODING) || name.equalsIgnoreCase(HttpHeaders.UPGRADE)) {
+                throw new ProtocolException("Header '%s: %s' is illegal for HTTP/2 messages", header.getName(), header.getValue());
             }
             headers.add(new BasicHeader(TextUtils.toLowerCase(name), value));
         }
diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/TestDefaultH2RequestConverter.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/TestDefaultH2RequestConverter.java
index 9be504e..1f8998c 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/TestDefaultH2RequestConverter.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/TestDefaultH2RequestConverter.java
@@ -359,6 +359,89 @@ public class TestDefaultH2RequestConverter {
     }
 
     @Test
+    public void testConvertFromFieldsKeepAliveHeader() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+        request.addHeader("Keep-Alive", "timeout=5, max=1000");
+
+        final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
+        Assert.assertThrows("Header 'Keep-Alive: timeout=5, max=1000' is illegal for HTTP/2 messages",
+                            HttpException.class, () -> converter.convert(request));
+    }
+
+    @Test
+    public void testConvertFromFieldsProxyConnectionHeader() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+        request.addHeader("Proxy-Connection", "keep-alive");
+
+        final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
+        Assert.assertThrows("Header 'Proxy-Connection: Keep-Alive' is illegal for HTTP/2 messages",
+                            HttpException.class, () -> converter.convert(request));
+    }
+
+    @Test
+    public void testConvertFromFieldsTransferEncodingHeader() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+        request.addHeader("Transfer-Encoding", "gzip");
+
+        final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
+        Assert.assertThrows("Header 'Transfer-Encoding: gzip' is illegal for HTTP/2 messages",
+                            HttpException.class, () -> converter.convert(request));
+    }
+
+    @Test
+    public void testConvertFromFieldsHostHeader() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+        request.addHeader("Host", "host");
+
+        final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
+        Assert.assertThrows("Header 'Host: host' is illegal for HTTP/2 messages",
+                            HttpException.class, () -> converter.convert(request));
+    }
+
+    @Test
+    public void testConvertFromFieldsUpgradeHeader() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+        request.addHeader("Upgrade", "example/1, foo/2");
+
+        final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
+        Assert.assertThrows("Header 'Upgrade: example/1, foo/2' is illegal for HTTP/2 messages",
+                            HttpException.class, () -> converter.convert(request));
+    }
+
+    @Test
+    public void testConvertFromFieldsTEHeader() throws Exception {
+        final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
+        request.addHeader("TE", "gzip");
+
+        final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
+        Assert.assertThrows("Header 'TE: gzip' is illegal for HTTP/2 messages",
+                            HttpException.class, () -> converter.convert(request));
+    }
+
+    @Test
+    public void testConvertFromFieldsTETrailerHeader() throws Exception {
+
+        final List<Header> headers = Arrays.asList(
+            new BasicHeader(":method", "GET"),
+            new BasicHeader(":scheme", "http"),
+            new BasicHeader(":authority", "www.example.com"),
+            new BasicHeader(":path", "/"),
+            new BasicHeader("te", "trailers"));
+
+        final DefaultH2RequestConverter converter = new DefaultH2RequestConverter();
+        final HttpRequest request = converter.convert(headers);
+        Assert.assertNotNull(request);
+        Assert.assertEquals("GET", request.getMethod());
+        Assert.assertEquals("http", request.getScheme());
+        Assert.assertEquals(new URIAuthority("www.example.com"), request.getAuthority());
+        Assert.assertEquals("/", request.getPath());
+        final Header[] allHeaders = request.getHeaders();
+        Assert.assertEquals(1, allHeaders.length);
+        Assert.assertEquals("te", allHeaders[0].getName());
+        Assert.assertEquals("trailers", allHeaders[0].getValue());
+    }
+
+    @Test
     public void testConvertFromMessageInvalidHeader() throws Exception {
         final HttpRequest request = new BasicHttpRequest("GET", new HttpHost("host"), "/");
         request.addHeader(":custom", "stuff");
diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/TestDefaultH2ResponseConverter.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/TestDefaultH2ResponseConverter.java
index 6253f55..90f3801 100644
--- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/TestDefaultH2ResponseConverter.java
+++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/TestDefaultH2ResponseConverter.java
@@ -96,6 +96,42 @@ public class TestDefaultH2ResponseConverter {
     }
 
     @Test
+    public void testConvertFromFieldsKeepAliveHeader() throws Exception {
+        final List<Header> headers = Arrays.asList(
+            new BasicHeader(":status", "200"),
+            new BasicHeader("location", "http://www.example.com/"),
+            new BasicHeader("keep-alive", "timeout=5, max=1000"));
+
+        final DefaultH2ResponseConverter converter = new DefaultH2ResponseConverter();
+        Assert.assertThrows("Header 'keep-alive: timeout=5, max=1000' is illegal for HTTP/2 messages",
+                            HttpException.class, () -> converter.convert(headers));
+    }
+
+    @Test
+    public void testConvertFromFieldsTransferEncodingHeader() throws Exception {
+        final List<Header> headers = Arrays.asList(
+            new BasicHeader(":status", "200"),
+            new BasicHeader("location", "http://www.example.com/"),
+            new BasicHeader("transfer-encoding", "gzip"));
+
+        final DefaultH2ResponseConverter converter = new DefaultH2ResponseConverter();
+        Assert.assertThrows("Header 'transfer-encoding: gzip' is illegal for HTTP/2 messages",
+                            HttpException.class, () -> converter.convert(headers));
+    }
+
+    @Test
+    public void testConvertFromFieldsUpgradeHeader() throws Exception {
+        final List<Header> headers = Arrays.asList(
+            new BasicHeader(":status", "200"),
+            new BasicHeader("location", "http://www.example.com/"),
+            new BasicHeader("upgrade", "example/1, foo/2"));
+
+        final DefaultH2ResponseConverter converter = new DefaultH2ResponseConverter();
+        Assert.assertThrows("Header 'upgrade: example/1, foo/2' is illegal for HTTP/2 messages",
+                            HttpException.class, () -> converter.convert(headers));
+    }
+
+    @Test
     public void testConvertFromFieldsMissingStatus() throws Exception {
         final List<Header> headers = Arrays.asList(
                 new BasicHeader("location", "http://www.example.com/"),
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/HttpHeaders.java b/httpcore5/src/main/java/org/apache/hc/core5/http/HttpHeaders.java
index ce6dced..c8a966a 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/HttpHeaders.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/HttpHeaders.java
@@ -167,6 +167,8 @@ public final class HttpHeaders {
 
     public static final String PROXY_AUTHORIZATION = "Proxy-Authorization";
 
+    public static final String PROXY_CONNECTION = "Proxy-Connection";
+
     public static final String RANGE = "Range";
 
     public static final String REFERER = "Referer";