-
Notifications
You must be signed in to change notification settings - Fork 925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Early Rejection of Large Requests Based on Content-Length Header #6032
Conversation
fd7fe9e
to
0a25899
Compare
@@ -600,8 +600,8 @@ void testTimeoutAfterPartialContentWithPooling(WebClient client) throws Exceptio | |||
void testTooLargeContentToNonExistentService(WebClient client) { | |||
final byte[] content = new byte[(int) MAX_CONTENT_LENGTH + 1]; | |||
final AggregatedHttpResponse res = client.post("/non-existent", content).aggregate().join(); | |||
assertThat(res.status()).isSameAs(HttpStatus.NOT_FOUND); | |||
assertThat(res.contentUtf8()).startsWith("Status: 404\n"); | |||
assertThat(res.status()).isSameAs(HttpStatus.REQUEST_ENTITY_TOO_LARGE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i had to change this test as it's rejected earlier now, is there a way to fix it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To simulate a client request with no content-length
header, we can probably make a transfer-encoding request.
e.g.
val req = HttpRequest.streaming(POST, "/non-existent);
client.execute(req)...
req.write(content)
req.close();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make sense, updated!
core/src/main/java/com/linecorp/armeria/common/ContentTooLargeException.java
Outdated
Show resolved
Hide resolved
@@ -472,6 +472,11 @@ public Boolean allowSemicolonInPathComponent() { | |||
return false; | |||
} | |||
|
|||
@Override | |||
public Boolean allowLargeRequestEarlyRejection() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to guard this feature under a flag..
core/src/main/java/com/linecorp/armeria/server/Http1RequestDecoder.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall, left some minor comments
core/src/main/java/com/linecorp/armeria/common/ContentTooLargeExceptionBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/Http1RequestDecoder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/Http1RequestDecoder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/Http2RequestDecoder.java
Outdated
Show resolved
Hide resolved
36bb54d
to
c114764
Compare
core/src/main/java/com/linecorp/armeria/common/ContentTooLargeExceptionBuilder.java
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/ContentTooLargeExceptionBuilder.java
Outdated
Show resolved
Hide resolved
06f9c52
to
990f4cb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 👍 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yzfeng2020 Happy new year! 😆
core/src/main/java/com/linecorp/armeria/server/Http1RequestDecoder.java
Outdated
Show resolved
Hide resolved
hey @ikhoon gentle ping if you can take a look! :) |
core/src/main/java/com/linecorp/armeria/common/ContentTooLargeExceptionBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/common/ContentTooLargeExceptionBuilder.java
Outdated
Show resolved
Hide resolved
if (maxRequestLength > 0 && contentLength > maxRequestLength) { | ||
abortLargeRequest(ctx, req, id, endOfStream, keepAliveHandler, true); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am unsure if it is necessary to pass the content-length exceeding request to the service chains. Should we fail()
the request instead? What do you think @minwoox?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, it was implemented this way to meet a demand for logging content-length-exceeding requests via LoggingService
.
This feature could still be useful for identifying such requests on the server side, provided it doesn't cause a performance issue. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't worried about performance, but I was considering the race condition between the response sent by the user and the aborted response.
That case would be rare, so I think it can be ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, let's revisit this if we encounter any issue with this. 😉
…ExceptionBuilder.java
…ExceptionBuilder.java
@yzfeng2020 Thanks! 👍 👍 👍 |
Motivation: Currently, large requests are rejected only after the transferred bytes exceed the configured limit. This behavior is sub-optimal for requests that include a valid Content-Length header indicating the request is already too large. By rejecting such requests earlier—when the header is read—we can improve resource utilization and reduce unnecessary processing. Modifications: - Added a field to ContentTooLargeException to indicate when the exception is raised during header processing. - Implemented content-length-based early rejection in Http1ObjectDecoder and Http2ObjectDecoder. Result: Result: - Closes #5880 - Requests with a Content-Length header exceeding the allowed limit can now be rejected early in the request flow, reducing wasted resources and improving efficiency. <!-- Visit this URL to learn more about how to write a pull request description: https://armeria.dev/community/developer-guide#how-to-write-pull-request-description -->
Motivation:
Currently, large requests are rejected only after the transferred bytes exceed the configured limit. This behavior is sub-optimal for requests that include a valid Content-Length header indicating the request is already too large. By rejecting such requests earlier—when the header is read—we can improve resource utilization and reduce unnecessary processing.
Modifications:
Result:
Result: