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 2019/12/23 19:33:33 UTC

[httpcomponents-core] branch development updated (04531ef -> dcb1ecd)

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

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


 discard 04531ef  Support for status code 431 (Request Header Fields Too Large)
     new dcb1ecd  Support for status code 431 (Request Header Fields Too Large)

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (04531ef)
            \
             N -- N -- N   refs/heads/development (dcb1ecd)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../testing/classic/ClassicIntegrationTest.java    | 38 +++++++-------
 .../http/RequestHeaderFieldsTooLargeException.java | 58 ----------------------
 2 files changed, 19 insertions(+), 77 deletions(-)
 delete mode 100644 httpcore5/src/main/java/org/apache/hc/core5/http/RequestHeaderFieldsTooLargeException.java


[httpcomponents-core] 01/01: Support for status code 431 (Request Header Fields Too Large)

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit dcb1ecda284d35cac9c7aeca59c2d13db7a26b2d
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Mon Dec 23 15:34:42 2019 +0100

    Support for status code 431 (Request Header Fields Too Large)
---
 .../core5/testing/classic/ClassicTestServer.java   |  9 +++--
 .../testing/classic/ClassicIntegrationTest.java    | 39 ++++++++++++++++++++--
 .../hc/core5/testing/nio/Http1IntegrationTest.java | 33 ++++++++++++++++++
 .../apache/hc/core5/http/impl/ServerSupport.java   |  3 ++
 .../http/impl/io/DefaultHttpRequestParser.java     | 14 ++++++++
 .../apache/hc/core5/http/impl/io/HttpService.java  |  6 +---
 .../http/impl/nio/DefaultHttpRequestParser.java    | 14 ++++++++
 .../hc/core5/http/impl/io/TestRequestParser.java   |  4 +--
 8 files changed, 110 insertions(+), 12 deletions(-)

diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestServer.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestServer.java
index c7d4ff4..4abe8b2 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestServer.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestServer.java
@@ -99,7 +99,10 @@ public class ClassicTestServer {
         throw new IllegalStateException("Server not running");
     }
 
-    public void start(final HttpProcessor httpProcessor, final Decorator<HttpServerRequestHandler> handlerDecorator) throws IOException {
+    public void start(
+            final Http1Config http1Config,
+            final HttpProcessor httpProcessor,
+            final Decorator<HttpServerRequestHandler> handlerDecorator) throws IOException {
         if (serverRef.get() == null) {
             final HttpServerRequestHandler handler = new BasicHttpServerRequestHandler(registry);
             final HttpService httpService = new HttpService(
@@ -115,7 +118,7 @@ public class ClassicTestServer {
                     sslContext != null ? sslContext.getServerSocketFactory() : ServerSocketFactory.getDefault(),
                     new LoggingBHttpServerConnectionFactory(
                             sslContext != null ? URIScheme.HTTPS.id : URIScheme.HTTP.id,
-                            Http1Config.DEFAULT,
+                            http1Config != null ? http1Config : Http1Config.DEFAULT,
                             CharCodingConfig.DEFAULT),
                     null,
                     LoggingExceptionListener.INSTANCE);
@@ -128,7 +131,7 @@ public class ClassicTestServer {
     }
 
     public void start() throws IOException {
-        start(null, null);
+        start(null, null, null);
     }
 
     public void shutdown(final CloseMode closeMode) {
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicIntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicIntegrationTest.java
index 6971c4e..3c787db 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicIntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/classic/ClassicIntegrationTest.java
@@ -57,6 +57,7 @@ import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.HttpVersion;
 import org.apache.hc.core5.http.Method;
 import org.apache.hc.core5.http.URIScheme;
+import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.io.HttpRequestHandler;
 import org.apache.hc.core5.http.io.HttpServerRequestHandler;
 import org.apache.hc.core5.http.io.SocketConfig;
@@ -108,7 +109,7 @@ public class ClassicIntegrationTest {
         @Override
         protected void before() throws Throwable {
             server = new ClassicTestServer(
-                    scheme == URIScheme.HTTPS  ? SSLTestContexts.createServerSSLContext() : null,
+                    scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null,
                     SocketConfig.custom()
                             .setSoTimeout(5, TimeUnit.SECONDS)
                             .build());
@@ -489,7 +490,7 @@ public class ClassicIntegrationTest {
 
         });
 
-        this.server.start(null, new Decorator<HttpServerRequestHandler>() {
+        this.server.start(null, null, new Decorator<HttpServerRequestHandler>() {
 
             @Override
             public HttpServerRequestHandler decorate(final HttpServerRequestHandler handler) {
@@ -885,4 +886,38 @@ public class ClassicIntegrationTest {
         }
     }
 
+    @Test
+    public void testHeaderTooLarge() throws Exception {
+        this.server.registerHandler("*", new HttpRequestHandler() {
+
+            @Override
+            public void handle(
+                    final ClassicHttpRequest request,
+                    final ClassicHttpResponse response,
+                    final HttpContext context) throws HttpException, IOException {
+                response.setEntity(new StringEntity("All is well", StandardCharsets.US_ASCII));
+            }
+
+        });
+
+        this.server.start(
+                Http1Config.custom()
+                        .setMaxLineLength(100)
+                        .build(),
+                null,
+                null);
+        this.client.start();
+
+        final HttpCoreContext context = HttpCoreContext.create();
+        final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
+
+        final BasicClassicHttpRequest get1 = new BasicClassicHttpRequest(Method.GET, "/");
+        get1.setHeader("big-f-header", "1234567890123456789012345678901234567890123456789012345678901234567890" +
+                "1234567890123456789012345678901234567890");
+        try (final ClassicHttpResponse response1 = this.client.execute(host, get1, context)) {
+            Assert.assertEquals(431, response1.getCode());
+            EntityUtils.consume(response1.getEntity());
+        }
+    }
+
 }
diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
index 6132f15..79c1dc0 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/Http1IntegrationTest.java
@@ -1789,4 +1789,37 @@ public class Http1IntegrationTest extends InternalHttp1ServerTestBase {
         Assert.assertEquals("Boom!!!", entity1);
     }
 
+    @Test
+    public void testHeaderTooLarge() throws Exception {
+        server.register("/hello", new Supplier<AsyncServerExchangeHandler>() {
+
+            @Override
+            public AsyncServerExchangeHandler get() {
+                return new SingleLineResponseHandler("Hi there");
+            }
+
+        });
+        final InetSocketAddress serverEndpoint = server.start(null, Http1Config.custom()
+                .setMaxLineLength(100)
+                .build());
+        client.start();
+
+        final Future<ClientSessionEndpoint> connectFuture = client.connect(
+                "localhost", serverEndpoint.getPort(), TIMEOUT);
+        final ClientSessionEndpoint streamEndpoint = connectFuture.get();
+
+        final HttpRequest request1 = new BasicHttpRequest(Method.GET, createRequestURI(serverEndpoint, "/hello"));
+        request1.setHeader("big-f-header", "1234567890123456789012345678901234567890123456789012345678901234567890" +
+                "1234567890123456789012345678901234567890");
+        final Future<Message<HttpResponse, String>> future1 = streamEndpoint.execute(
+                new BasicRequestProducer(request1, null),
+                new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), null);
+        final Message<HttpResponse, String> result1 = future1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
+        Assert.assertNotNull(result1);
+        final HttpResponse response1 = result1.getHead();
+        Assert.assertNotNull(response1);
+        Assert.assertEquals(431, response1.getCode());
+        Assert.assertEquals("Maximum line length limit exceeded", result1.getBody());
+    }
+
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/ServerSupport.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/ServerSupport.java
index 29cca6b..df6bc12 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/ServerSupport.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/ServerSupport.java
@@ -34,6 +34,7 @@ import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.MethodNotSupportedException;
 import org.apache.hc.core5.http.NotImplementedException;
 import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.RequestHeaderFieldsTooLargeException;
 import org.apache.hc.core5.http.UnsupportedHttpVersionException;
 
 /**
@@ -70,6 +71,8 @@ public class ServerSupport {
             code = HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED;
         } else if (ex instanceof NotImplementedException) {
             code = HttpStatus.SC_NOT_IMPLEMENTED;
+        } else if (ex instanceof RequestHeaderFieldsTooLargeException) {
+            code = HttpStatus.SC_REQUEST_HEADER_FIELDS_TOO_LARGE;
         } else if (ex instanceof ProtocolException) {
             code = HttpStatus.SC_BAD_REQUEST;
         } else {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParser.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParser.java
index a1e8e59..55e6caf 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParser.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/DefaultHttpRequestParser.java
@@ -28,12 +28,16 @@
 package org.apache.hc.core5.http.impl.io;
 
 import java.io.IOException;
+import java.io.InputStream;
 
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ConnectionClosedException;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.HttpRequestFactory;
+import org.apache.hc.core5.http.MessageConstraintException;
+import org.apache.hc.core5.http.RequestHeaderFieldsTooLargeException;
 import org.apache.hc.core5.http.config.Http1Config;
+import org.apache.hc.core5.http.io.SessionInputBuffer;
 import org.apache.hc.core5.http.message.LineParser;
 import org.apache.hc.core5.http.message.RequestLine;
 import org.apache.hc.core5.util.CharArrayBuffer;
@@ -88,6 +92,16 @@ public class DefaultHttpRequestParser extends AbstractMessageParser<ClassicHttpR
     }
 
     @Override
+    public ClassicHttpRequest parse(
+            final SessionInputBuffer buffer, final InputStream inputStream) throws IOException, HttpException {
+        try {
+            return super.parse(buffer, inputStream);
+        } catch (final MessageConstraintException ex) {
+            throw new RequestHeaderFieldsTooLargeException(ex.getMessage(), ex);
+        }
+    }
+
+    @Override
     protected ClassicHttpRequest createMessage(final CharArrayBuffer buffer) throws IOException, HttpException {
         final RequestLine requestLine = getLineParser().parseRequestLine(buffer);
         final ClassicHttpRequest request = this.requestFactory.newHttpRequest(requestLine.getMethod(), requestLine.getUri());
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpService.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpService.java
index 31dd3a1..72ef10d 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpService.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/io/HttpService.java
@@ -266,11 +266,7 @@ public class HttpService {
      */
     protected void handleException(final HttpException ex, final ClassicHttpResponse response) {
         response.setCode(toStatusCode(ex));
-        String message = ex.getMessage();
-        if (message == null) {
-            message = ex.toString();
-        }
-        response.setEntity(new StringEntity(message, ContentType.TEXT_PLAIN));
+        response.setEntity(new StringEntity(ServerSupport.toErrorMessage(ex), ContentType.TEXT_PLAIN));
     }
 
     protected int toStatusCode(final Exception ex) {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParser.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParser.java
index 0f61845..67724df 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParser.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/DefaultHttpRequestParser.java
@@ -27,12 +27,17 @@
 
 package org.apache.hc.core5.http.impl.nio;
 
+import java.io.IOException;
+
 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.MessageConstraintException;
+import org.apache.hc.core5.http.RequestHeaderFieldsTooLargeException;
 import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.message.LineParser;
 import org.apache.hc.core5.http.message.RequestLine;
+import org.apache.hc.core5.http.nio.SessionInputBuffer;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.CharArrayBuffer;
 
@@ -79,6 +84,15 @@ public class DefaultHttpRequestParser<T extends HttpRequest> extends AbstractMes
     }
 
     @Override
+    public T parse(final SessionInputBuffer sessionBuffer, final boolean endOfStream) throws IOException, HttpException {
+        try {
+            return super.parse(sessionBuffer, endOfStream);
+        } catch (final MessageConstraintException ex) {
+            throw new RequestHeaderFieldsTooLargeException(ex.getMessage(), ex);
+        }
+    }
+
+    @Override
     protected T createMessage(final CharArrayBuffer buffer) throws HttpException {
         final RequestLine requestLine = getLineParser().parseRequestLine(buffer);
         final T request = this.requestFactory.newHttpRequest(requestLine.getMethod(), requestLine.getUri());
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestRequestParser.java b/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestRequestParser.java
index 918f7dd..0fe8a20 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestRequestParser.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/http/impl/io/TestRequestParser.java
@@ -33,8 +33,8 @@ import java.nio.charset.StandardCharsets;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ConnectionClosedException;
 import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.MessageConstraintException;
 import org.apache.hc.core5.http.Method;
+import org.apache.hc.core5.http.RequestHeaderFieldsTooLargeException;
 import org.apache.hc.core5.http.config.Http1Config;
 import org.apache.hc.core5.http.io.SessionInputBuffer;
 import org.junit.Assert;
@@ -95,7 +95,7 @@ public class TestRequestParser {
         Assert.assertEquals(1, headers.length);
     }
 
-    @Test(expected = MessageConstraintException.class)
+    @Test(expected = RequestHeaderFieldsTooLargeException.class)
     public void testBasicMessageParsingTooManyLeadingEmptyLines() throws Exception {
         final String s =
                 "\r\n" +