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";