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 13:57:23 UTC
[httpcomponents-core] 03/04: Corrected handling of illegal or
invalid request heads by async server side protocol handler
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 337401f41da3bfdf10cce0975f7780fea437cdb5
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Mon Dec 23 14:27:06 2019 +0100
Corrected handling of illegal or invalid request heads by async server side protocol handler
---
.../http/impl/nio/AbstractHttp1StreamDuplexer.java | 12 +++-
.../http/impl/nio/ServerHttp1StreamDuplexer.java | 36 +++++++++++
.../http/impl/nio/ServerHttp1StreamHandler.java | 73 +++++++++++++---------
3 files changed, 88 insertions(+), 33 deletions(-)
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java
index 24aa6b8..70807f3 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java
@@ -234,6 +234,14 @@ abstract class AbstractHttp1StreamDuplexer<IncomingMessage extends HttpMessage,
processCommands();
}
+ IncomingMessage parseMessageHead(final boolean endOfStream) throws IOException, HttpException {
+ final IncomingMessage messageHead = incomingMessageParser.parse(inbuf, endOfStream);
+ if (messageHead != null) {
+ incomingMessageParser.reset();
+ }
+ return messageHead;
+ }
+
public final void onInput(final ByteBuffer src) throws HttpException, IOException {
if (src != null) {
inbuf.put(src);
@@ -256,10 +264,8 @@ abstract class AbstractHttp1StreamDuplexer<IncomingMessage extends HttpMessage,
do {
if (incomingMessage == null) {
- final IncomingMessage messageHead = incomingMessageParser.parse(inbuf, endOfStream);
+ final IncomingMessage messageHead = parseMessageHead(endOfStream);
if (messageHead != null) {
- incomingMessageParser.reset();
-
this.version = messageHead.getVersion();
updateInputMetrics(messageHead, connMetrics);
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java
index 850d645..50161f7 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamDuplexer.java
@@ -298,6 +298,42 @@ public class ServerHttp1StreamDuplexer extends AbstractHttp1StreamDuplexer<HttpR
}
@Override
+ HttpRequest parseMessageHead(final boolean endOfStream) throws IOException, HttpException {
+ try {
+ return super.parseMessageHead(endOfStream);
+ } catch (final HttpException ex) {
+ terminateExchange(ex);
+ return null;
+ }
+ }
+
+ void terminateExchange(final HttpException ex) throws HttpException, IOException {
+ final ServerHttp1StreamHandler streamHandler;
+ final HttpCoreContext context = HttpCoreContext.create();
+ context.setAttribute(HttpCoreContext.SSL_SESSION, getSSLSession());
+ context.setAttribute(HttpCoreContext.CONNECTION_ENDPOINT, getEndpointDetails());
+ if (outgoing == null) {
+ streamHandler = new ServerHttp1StreamHandler(
+ outputChannel,
+ httpProcessor,
+ connectionReuseStrategy,
+ exchangeHandlerFactory,
+ context);
+ outgoing = streamHandler;
+ } else {
+ streamHandler = new ServerHttp1StreamHandler(
+ new DelayedOutputChannel(outputChannel),
+ httpProcessor,
+ connectionReuseStrategy,
+ exchangeHandlerFactory,
+ context);
+ pipeline.add(streamHandler);
+ }
+ streamHandler.terminateExchange(ex);
+ incoming = streamHandler;
+ }
+
+ @Override
void consumeHeader(final HttpRequest request, final EntityDetails entityDetails) throws HttpException, IOException {
if (streamListener != null) {
streamListener.onRequestHead(this, request);
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
index 6c7cb1b..0515179 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/ServerHttp1StreamHandler.java
@@ -58,12 +58,12 @@ import org.apache.hc.core5.http.nio.support.ImmediateResponseExchangeHandler;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.http.protocol.HttpCoreContext;
import org.apache.hc.core5.http.protocol.HttpProcessor;
-import org.apache.hc.core5.util.Asserts;
class ServerHttp1StreamHandler implements ResourceHolder {
private final Http1StreamChannel<HttpResponse> outputChannel;
private final DataStreamChannel internalDataChannel;
+ private final ResponseChannel responseChannel;
private final HttpProcessor httpProcessor;
private final HandlerFactory<AsyncServerExchangeHandler> exchangeHandlerFactory;
private final ConnectionReuseStrategy connectionReuseStrategy;
@@ -112,6 +112,33 @@ class ServerHttp1StreamHandler implements ResourceHolder {
};
+ this.responseChannel = new ResponseChannel() {
+
+ @Override
+ public void sendInformation(final HttpResponse response, final HttpContext httpContext) throws HttpException, IOException {
+ commitInformation(response);
+ }
+
+ @Override
+ public void sendResponse(
+ final HttpResponse response, final EntityDetails responseEntityDetails, final HttpContext httpContext) throws HttpException, IOException {
+ ServerSupport.validateResponse(response, responseEntityDetails);
+ commitResponse(response, responseEntityDetails);
+ }
+
+ @Override
+ public void pushPromise(
+ final HttpRequest promise, final AsyncPushProducer pushProducer, final HttpContext httpContext) throws HttpException, IOException {
+ commitPromise();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " " + ServerHttp1StreamHandler.this.toString();
+ }
+
+ };
+
this.httpProcessor = httpProcessor;
this.connectionReuseStrategy = connectionReuseStrategy;
this.exchangeHandlerFactory = exchangeHandlerFactory;
@@ -138,12 +165,11 @@ class ServerHttp1StreamHandler implements ResourceHolder {
throw new HttpException("Invalid response: " + status);
}
- Asserts.notNull(receivedRequest, "Received request");
- final String method = receivedRequest.getMethod();
context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
httpProcessor.process(response, responseEntityDetails, context);
- final boolean endStream = responseEntityDetails == null || Method.HEAD.isSame(method);
+ final boolean endStream = responseEntityDetails == null ||
+ (receivedRequest != null && Method.HEAD.isSame(receivedRequest.getMethod()));
if (!connectionReuseStrategy.keepAlive(receivedRequest, response, context)) {
keepAlive = false;
@@ -195,6 +221,19 @@ class ServerHttp1StreamHandler implements ResourceHolder {
return requestState == MessageState.COMPLETE && responseState == MessageState.COMPLETE;
}
+ void terminateExchange(final HttpException ex) throws HttpException, IOException {
+ if (done.get() || requestState != MessageState.HEADERS) {
+ throw new ProtocolException("Unexpected message head");
+ }
+ receivedRequest = null;
+ requestState = MessageState.COMPLETE;
+ final AsyncResponseProducer responseProducer = new BasicResponseProducer(
+ ServerSupport.toStatusCode(ex),
+ ServerSupport.toErrorMessage(ex));
+ exchangeHandler = new ImmediateResponseExchangeHandler(responseProducer);
+ exchangeHandler.handleRequest(null, null, responseChannel, context);
+ }
+
void consumeHeader(final HttpRequest request, final EntityDetails requestEntityDetails) throws HttpException, IOException {
if (done.get() || requestState != MessageState.HEADERS) {
throw new ProtocolException("Unexpected message head");
@@ -223,32 +262,6 @@ class ServerHttp1StreamHandler implements ResourceHolder {
context.setProtocolVersion(transportVersion);
context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
- final ResponseChannel responseChannel = new ResponseChannel() {
-
- @Override
- public void sendInformation(final HttpResponse response, final HttpContext httpContext) throws HttpException, IOException {
- commitInformation(response);
- }
-
- @Override
- public void sendResponse(
- final HttpResponse response, final EntityDetails responseEntityDetails, final HttpContext httpContext) throws HttpException, IOException {
- ServerSupport.validateResponse(response, responseEntityDetails);
- commitResponse(response, responseEntityDetails);
- }
-
- @Override
- public void pushPromise(
- final HttpRequest promise, final AsyncPushProducer pushProducer, final HttpContext httpContext) throws HttpException, IOException {
- commitPromise();
- }
-
- @Override
- public String toString() {
- return super.toString() + " " + ServerHttp1StreamHandler.this.toString();
- }
-
- };
try {
httpProcessor.process(request, requestEntityDetails, context);
exchangeHandler.handleRequest(request, requestEntityDetails, responseChannel, context);