diff options
Diffstat (limited to 'container-core/src/main/java/com/yahoo/jdisc/http/server/jetty')
-rw-r--r-- | container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java index 2f2c48e0b48..75ef655c60c 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java @@ -1,16 +1,19 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.jdisc.http.server.jetty; +import com.yahoo.jdisc.Response; import com.yahoo.jdisc.handler.CompletionHandler; import com.yahoo.jdisc.handler.ContentChannel; import jakarta.servlet.ReadListener; import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServletRequest; +import org.eclipse.jetty.server.Request; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Objects; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; @@ -33,6 +36,7 @@ import java.util.logging.Logger; */ class ServletRequestReader { + private enum State { NOT_STARTED, READING, ALL_DATA_READ, REQUEST_CONTENT_CLOSED } @@ -96,12 +100,15 @@ class ServletRequestReader { private final CompletableFuture<Void> finishedFuture = new CompletableFuture<>(); ServletRequestReader( - HttpServletRequest req, + Request req, ContentChannel requestContentChannel, Janitor janitor, RequestMetricReporter metricReporter) { this.req = Objects.requireNonNull(req); - this.requestContentChannel = Objects.requireNonNull(requestContentChannel); + long maxContentSize = RequestUtils.getConnector(req).connectorConfig().maxContentSize(); + this.requestContentChannel = maxContentSize >= 0 + ? new ByteLimitedContentChannel(Objects.requireNonNull(requestContentChannel), maxContentSize) + : Objects.requireNonNull(requestContentChannel); this.janitor = Objects.requireNonNull(janitor); this.metricReporter = Objects.requireNonNull(metricReporter); } @@ -259,4 +266,30 @@ class ServletRequestReader { } } + private static class ByteLimitedContentChannel implements ContentChannel { + private final long maxContentSize; + private final AtomicLong bytesWritten = new AtomicLong(); + private final ContentChannel delegate; + + ByteLimitedContentChannel(ContentChannel delegate, long maxContentSize) { + this.delegate = delegate; + this.maxContentSize = maxContentSize; + } + + @Override + public void write(ByteBuffer buf, CompletionHandler handler) { + long written = bytesWritten.addAndGet(buf.remaining()); + if (written > maxContentSize) { + handler.failed(new RequestException( + Response.Status.REQUEST_TOO_LONG, + "Request content length %d exceeds limit of %d bytes".formatted(written, maxContentSize))); + return; + } + delegate.write(buf, handler); + } + + @Override public void close(CompletionHandler h) { delegate.close(h); } + @Override public void onError(Throwable t) { delegate.onError(t); } + } + } |