Skip to content

Limit ingress HTTP request body size#4751

Merged
muhamadazmy merged 1 commit into
mainfrom
pr4751
May 19, 2026
Merged

Limit ingress HTTP request body size#4751
muhamadazmy merged 1 commit into
mainfrom
pr4751

Conversation

@muhamadazmy
Copy link
Copy Markdown
Contributor

Limit ingress HTTP request body size

Adds a RequestBodyLimitLayer to the ingress HTTP server so oversized
request bodies are rejected with 413 Payload Too Large rather than being
streamed in full.

Introduces a new ingress.request-size-limit config option. It defaults
to (and is clamped at) networking.message-size-limit, since requests
larger than that cap cannot be transmitted over the cluster-internal
network.

Fixes #4153

@muhamadazmy muhamadazmy marked this pull request as ready for review May 18, 2026 14:03
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d190507bde

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

),
)
.layer(NormalizePathLayer::trim_trailing_slash())
.layer(RequestBodyLimitLayer::new(request_size_limit))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Move the body-limit layer inside CORS

When browser clients send an oversized request with a Content-Length header, RequestBodyLimitLayer returns the 413 immediately without calling its inner service. Because CorsLayer::very_permissive() is added after this line (server.rs:180), it is inside the limit layer and never gets a chance to add CORS headers to those early 413 responses, so browser callers cannot observe the intended Payload Too Large response. Place the limit layer inside the CORS layer (or otherwise apply CORS to the early response).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This unfortunately requires this change to be accepted and merged to mainstream tower-http tower-rs/tower-http#679

We can also switch to using my fork for now. But since the chances of sending such a large payload from the browser are minimal, we can just keep using this mainstream tower-http until the PR is approved and merged.

I will leave a todo in code so we keep track of this

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 18, 2026

Test Results

  8 files  ±0    8 suites  ±0   5m 11s ⏱️ +22s
 60 tests ±0   59 ✅  - 1  0 💤 ±0  0 ❌ ±0  1 🔥 +1 
267 runs  ±0  266 ✅  - 1  0 💤 ±0  0 ❌ ±0  1 🔥 +1 

For more details on these errors, see this check.

Results for commit 83484da. ± Comparison against base commit dcdd8ac.

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown
Contributor

@tillrohrmann tillrohrmann left a comment

Choose a reason for hiding this comment

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

Thanks for enforcing request limits at the ingress @muhamadazmy. The changes look really nice :-) +1 for merging after checking why the e2e tests are failing with this PR.

Comment thread crates/ingress-http/src/lib.rs Outdated
use restate_types::journal_v2::Signal;
use restate_types::net::address::SocketAddress;

pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you use GenericError, instead?

Comment on lines +1230 to +1232
req.extensions_mut()
.insert(ConnectInfo::new(SocketAddress::Anonymous));
req.extensions_mut().insert(opentelemetry::Context::new());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Out of curiosity: Why are those extensions needed?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I assume the RequestBodyLimitLayer needs those?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This function is a based on the original handle_with_schemas_and_dispatcher. The extensions are accessed by the service handler function, and are injected automatically by the connection handler. So we need to inject those extensions here for the tests to pass.

Copy link
Copy Markdown
Contributor

@tillrohrmann tillrohrmann May 19, 2026

Choose a reason for hiding this comment

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

I thought the handler should never be called in these tests? Removing those extensions lets the tests still to pass.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There are 2 test scenarios. One of them sends a full body with content-length header. This one short circuits and fails immediately.

The other test doesn't have content-length header which is normally the case with streaming. In this scenario the handler is called, and fails only if the read body hit the size limit. This scenario of course still calls the handler and fails during body collection.

Removing the extension injection here, causes the second scenario to panic of course.

Adds a `RequestBodyLimitLayer` to the ingress HTTP server so oversized
request bodies are rejected with 413 Payload Too Large rather than being
streamed in full.

Introduces a new `ingress.request-size-limit` config option. It defaults
to (and is clamped at) `networking.message-size-limit`, since requests
larger than that cap cannot be transmitted over the cluster-internal
network.

Fixes #4153
@muhamadazmy muhamadazmy merged commit 1eaf0e0 into main May 19, 2026
63 of 65 checks passed
@muhamadazmy muhamadazmy deleted the pr4751 branch May 19, 2026 07:52
@github-actions github-actions Bot locked and limited conversation to collaborators May 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reject ingress messages that are exceeding the message size limit

2 participants