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:34 UTC
[httpcomponents-core] 01/01: Support for status code 431 (Request
Header Fields Too Large)
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" +