Skip to content

feat(http): add SizeLimitHandler to enforce request body size limit#6658

Open
bladehan1 wants to merge 6 commits intotronprotocol:developfrom
bladehan1:feat/request_size
Open

feat(http): add SizeLimitHandler to enforce request body size limit#6658
bladehan1 wants to merge 6 commits intotronprotocol:developfrom
bladehan1:feat/request_size

Conversation

@bladehan1
Copy link
Copy Markdown
Collaborator

What does this PR do?

Add Jetty SizeLimitHandler at the server handler level to enforce request body size limits for all HTTP and JSON-RPC endpoints. Oversized requests are rejected with HTTP 413 before the body is fully buffered into memory.

  • Introduce node.http.maxMessageSize and node.jsonrpc.maxMessageSize as independent, configurable size limits
  • Default: GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE (4 MB), consistent with gRPC defaults
  • Wire SizeLimitHandler into HttpService.initContextHandler() as the outermost handler
  • Each HttpService subclass (4 HTTP + 3 JSON-RPC) sets maxRequestSize from the corresponding config getter
  • Deprecate Util.checkBodySize() — retained as fallback for backward compatibility

Why are these changes required?

Previously, HTTP request body size was only validated at the application layer (Util.checkBodySize()), which reads the entire body into memory before checking. The JSON-RPC interface had no size validation at all. This allows an attacker to send arbitrarily large payloads, causing OOM and denial of service.

Moving the limit to the Jetty handler chain provides:

  1. Early rejection — oversized requests are stopped before reaching servlet code
  2. Streaming enforcement — limits are enforced during read, not after full buffering
  3. Unified coverage — all HTTP and JSON-RPC endpoints are protected by a single mechanism
  4. Independent tuning — operators can configure HTTP and JSON-RPC limits separately

Closes #6604

This PR has been tested by:

  • Unit Tests (SizeLimitHandlerTest: boundary, independent limits, UTF-8 byte counting)
  • Unit Tests (ArgsTest: default value alignment)

Follow up

  • Remove Util.checkBodySize() callers in a follow-up PR once this is stable
  • Compression bomb (gzip decompression) protection is a separate concern, tracked independently

Extra details

Files changed: 14 (+253 / -2)

Component Changes
HttpService Add maxRequestSize field, wire SizeLimitHandler in initContextHandler()
Args / ConfigKey / CommonParameter Parse node.http.maxMessageSize and node.jsonrpc.maxMessageSize
7 service subclasses Set maxRequestSize from protocol-specific getter in constructor
Util.checkBodySize() Mark @Deprecated
SizeLimitHandlerTest New: 8 tests covering HTTP/JSON-RPC limits, boundary, UTF-8, independence
ArgsTest Align assertions with 4 MB defaults

…imit

Add SizeLimitHandler at the Jetty server level to reject oversized
request bodies before they are fully buffered into memory. This prevents
OOM attacks via arbitrarily large HTTP payloads that bypass the existing
application-level Util.checkBodySize() check (which reads the entire
body first) and the JSON-RPC interface (which had no size validation).
Introduce node.http.maxMessageSize and node.jsonrpc.maxMessageSize to
allow HTTP and JSON-RPC services to enforce separate request body size
limits via Jetty SizeLimitHandler, decoupled from gRPC config.

- Default: 4 * GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE (16 MB)
- Validation: reject <= 0 with TronError(PARAMETER_INIT) at startup
- Each HttpService subclass sets its own maxRequestSize in constructor
- SizeLimitHandlerTest covers independent limits, boundary, UTF-8 bytes
@xxo1shine
Copy link
Copy Markdown
Collaborator

@bladehan1 One observation on the config validation in Args.java: the guard currently rejects <= 0 values with TronError, but there is no upper-bound check. An operator who accidentally sets node.http.maxMessageSize = 2147483647 would silently run with a 2 GB limit. Adding a reasonable maximum (e.g. 128 MB) with an explicit warn-or-throw would make misconfiguration more visible.

@bladehan1
Copy link
Copy Markdown
Collaborator Author

@xxo1shine
Thanks for the review. I think that when users manually configure values, it's unnecessary to set all boundaries except for error-prone values. Especially for values ​​that are obviously likely to have problems, setting boundaries is unnecessary.

}
}

@Deprecated
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking this helper as deprecated does not make the new HTTP limit effective yet. PostParams.getPostParams() and many servlets still call Util.checkBodySize(), and that method is still enforcing parameter.getMaxMessageSize() (the gRPC limit), not httpMaxMessageSize. So any request whose body is > node.rpc.maxMessageSize but <= node.http.maxMessageSize will pass Jetty and then still be rejected in the servlet layer, which means the new independent HTTP setting is not actually honored for a large part of the API surface.

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath(this.contextPath);
this.apiServer.setHandler(context);
SizeLimitHandler sizeLimitHandler = new SizeLimitHandler(this.maxRequestSize, -1);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This moves oversized-request handling in front of every servlet, so those requests never reach RateLimiterServlet.service() / Util.processError(). Today the HTTP APIs consistently set application/json and serialize failures through Util.printErrorMsg(...); after this change an over-limit body gets Jetty's default 413 response instead. That is a client-visible behavior change for existing callers, and the new test only checks status codes so it would not catch the response-format regression.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Unified HTTP Request Body Size Limit

3 participants