From fd7fe9e8747763d077b1ba5886071d09bba7b761 Mon Sep 17 00:00:00 2001 From: Yizhou Feng Date: Thu, 12 Dec 2024 05:22:11 +0000 Subject: [PATCH] flags --- .../com/linecorp/armeria/common/Flags.java | 7 ++++++ .../armeria/common/FlagsProvider.java | 5 ++++ .../armeria/server/Http1RequestDecoder.java | 25 ++++++------------- .../armeria/server/Http2RequestDecoder.java | 21 ++++++---------- 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/com/linecorp/armeria/common/Flags.java b/core/src/main/java/com/linecorp/armeria/common/Flags.java index 3fc9c0acbcd..529f78cfe2e 100644 --- a/core/src/main/java/com/linecorp/armeria/common/Flags.java +++ b/core/src/main/java/com/linecorp/armeria/common/Flags.java @@ -421,6 +421,9 @@ private static boolean validateTransportType(TransportType transportType, String private static final boolean ALLOW_SEMICOLON_IN_PATH_COMPONENT = getValue(FlagsProvider::allowSemicolonInPathComponent, "allowSemicolonInPathComponent"); + private static final boolean ALLOW_LARGE_REQUEST_EARLY_REJECTION = + getValue(FlagsProvider::allowLargeRequestEarlyRejection, "allowLargeRequestEarlyRejection"); + private static final Path DEFAULT_MULTIPART_UPLOADS_LOCATION = getValue(FlagsProvider::defaultMultipartUploadsLocation, "defaultMultipartUploadsLocation"); @@ -1554,6 +1557,10 @@ public static boolean allowSemicolonInPathComponent() { return ALLOW_SEMICOLON_IN_PATH_COMPONENT; } + public static boolean allowLargeRequestEarlyRejection() { + return ALLOW_LARGE_REQUEST_EARLY_REJECTION; + } + /** * Returns the {@link Sampler} that determines whether to trace the stack trace of request contexts leaks * and how frequently to keeps stack trace. A sampled exception will have the stack trace while the others diff --git a/core/src/main/java/com/linecorp/armeria/common/FlagsProvider.java b/core/src/main/java/com/linecorp/armeria/common/FlagsProvider.java index 3503737bb93..c3ccc157be9 100644 --- a/core/src/main/java/com/linecorp/armeria/common/FlagsProvider.java +++ b/core/src/main/java/com/linecorp/armeria/common/FlagsProvider.java @@ -1097,6 +1097,11 @@ default Boolean allowDoubleDotsInQueryString() { return null; } + @Nullable + default Boolean allowLargeRequestEarlyRejection() { + return null; + } + /** * Returns whether to allow a semicolon ({@code ;}) in a request path component on the server-side. * If disabled, the substring from the semicolon to before the next slash, commonly referred to as diff --git a/core/src/main/java/com/linecorp/armeria/server/Http1RequestDecoder.java b/core/src/main/java/com/linecorp/armeria/server/Http1RequestDecoder.java index b862a5cbfb5..f97a8fcffa0 100644 --- a/core/src/main/java/com/linecorp/armeria/server/Http1RequestDecoder.java +++ b/core/src/main/java/com/linecorp/armeria/server/Http1RequestDecoder.java @@ -22,23 +22,12 @@ import java.net.URISyntaxException; +import com.linecorp.armeria.common.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Ascii; -import com.linecorp.armeria.common.ClosedSessionException; -import com.linecorp.armeria.common.ContentTooLargeException; -import com.linecorp.armeria.common.ExchangeType; -import com.linecorp.armeria.common.HttpData; -import com.linecorp.armeria.common.HttpMethod; -import com.linecorp.armeria.common.HttpRequestWriter; -import com.linecorp.armeria.common.HttpStatus; -import com.linecorp.armeria.common.ProtocolViolationException; -import com.linecorp.armeria.common.RequestHeaders; -import com.linecorp.armeria.common.RequestTarget; -import com.linecorp.armeria.common.ResponseHeaders; -import com.linecorp.armeria.common.SessionProtocol; import com.linecorp.armeria.common.annotation.Nullable; import com.linecorp.armeria.common.util.SystemInfo; import com.linecorp.armeria.internal.common.ArmeriaHttpUtil; @@ -208,7 +197,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception // Validate the 'content-length' header. final String contentLengthStr = headers.get(HttpHeaderNames.CONTENT_LENGTH); final boolean contentEmpty; - long contentLength = -1; + long contentLength = 0; if (contentLengthStr != null) { try { contentLength = Long.parseLong(contentLengthStr); @@ -280,10 +269,12 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception final boolean endOfStream = contentEmpty && !transferEncodingChunked; this.req = req = DecodedHttpRequest.of(endOfStream, eventLoop, id, 1, headers, keepAlive, inboundTrafficController, routingCtx); - final DecodedHttpRequestWriter decodedReq = - (req instanceof DecodedHttpRequestWriter) ? (DecodedHttpRequestWriter) req : null; - if (decodedReq != null && contentLength > decodedReq.maxRequestLength()) { - abortLargeRequest(ctx, decodedReq, id, endOfStream, true, keepAliveHandler); + if (Flags.allowLargeRequestEarlyRejection()) { + final DecodedHttpRequestWriter decodedReq = + (req instanceof DecodedHttpRequestWriter) ? (DecodedHttpRequestWriter) req : null; + if (decodedReq != null && contentLength > decodedReq.maxRequestLength()) { + abortLargeRequest(ctx, decodedReq, id, endOfStream, true, keepAliveHandler); + } } cfg.serverMetrics().increasePendingHttp1Requests(); ctx.fireChannelRead(req); diff --git a/core/src/main/java/com/linecorp/armeria/server/Http2RequestDecoder.java b/core/src/main/java/com/linecorp/armeria/server/Http2RequestDecoder.java index 48a28348595..2e3b1b07685 100644 --- a/core/src/main/java/com/linecorp/armeria/server/Http2RequestDecoder.java +++ b/core/src/main/java/com/linecorp/armeria/server/Http2RequestDecoder.java @@ -22,19 +22,10 @@ import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR; import static io.netty.handler.codec.http2.Http2Exception.connectionError; +import com.linecorp.armeria.common.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.linecorp.armeria.common.ContentTooLargeException; -import com.linecorp.armeria.common.HttpData; -import com.linecorp.armeria.common.HttpHeaderNames; -import com.linecorp.armeria.common.HttpHeaders; -import com.linecorp.armeria.common.HttpMethod; -import com.linecorp.armeria.common.HttpStatus; -import com.linecorp.armeria.common.RequestHeaders; -import com.linecorp.armeria.common.RequestTarget; -import com.linecorp.armeria.common.ResponseHeaders; -import com.linecorp.armeria.common.SessionProtocol; import com.linecorp.armeria.common.annotation.Nullable; import com.linecorp.armeria.common.stream.ClosedStreamException; import com.linecorp.armeria.internal.common.ArmeriaHttpUtil; @@ -206,10 +197,12 @@ public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers final EventLoop eventLoop = ctx.channel().eventLoop(); req = DecodedHttpRequest.of(endOfStream, eventLoop, id, streamId, headers, true, inboundTrafficController, routingCtx); - final DecodedHttpRequestWriter decodedReq = - (req instanceof DecodedHttpRequestWriter) ? (DecodedHttpRequestWriter) req : null; - if (decodedReq != null && contentLength > decodedReq.maxRequestLength()) { - abortLargeRequest(decodedReq, endOfStream, true); + if (Flags.allowLargeRequestEarlyRejection()) { + final DecodedHttpRequestWriter decodedReq = + (req instanceof DecodedHttpRequestWriter) ? (DecodedHttpRequestWriter) req : null; + if (decodedReq != null && contentLength > decodedReq.maxRequestLength()) { + abortLargeRequest(decodedReq, endOfStream, true); + } } requests.put(streamId, req); cfg.serverMetrics().increasePendingHttp2Requests();