Skip to content

fix: restore missing max_body_size guard for chunked body in 1.29.2.4 patch (client_max_body_size 0 wrongly 413s chunked)#115

Open
pubyun wants to merge 1 commit into
api7:mainfrom
pubyun:fix-chunked-max-body-size-zero
Open

fix: restore missing max_body_size guard for chunked body in 1.29.2.4 patch (client_max_body_size 0 wrongly 413s chunked)#115
pubyun wants to merge 1 commit into
api7:mainfrom
pubyun:fix-chunked-max-body-size-zero

Conversation

@pubyun

@pubyun pubyun commented Jun 29, 2026

Copy link
Copy Markdown

What this fixes

patch/1.29.2.4/nginx-client_max_body_size.patch dropped the && max_body_size guard in the
chunked-body check that patch/1.27.1.1/nginx-client_max_body_size.patch has.

After C preprocessing, the NGX_HTTP_APISIX branch of ngx_http_request_body_chunked_filter()
becomes:

if (max_body_size - r->headers_in.content_length_n < rb->chunked->size)

So with client_max_body_size 0 (unlimited) and a chunked request (content_length_n == 0),
0 - 0 < chunk_size is true for any non-empty chunk → spurious 413
client intended to send too large chunked body.

The content-length check and the rb->received check in the same patch kept their
&& max_body_size guard, so only chunked requests are affected.

Impact

APISIX renders client_max_body_size 0 by default. Once APISIX bundles this runtime
(APISIX 3.17.0 → apisix-runtime 1.3.6 → OpenResty 1.29.2.4 + apisix-nginx-module 1.19.5),
any chunked upload through APISIX returns 413: docker push blob upload (chunked PATCH),
large file/attachment uploads, etc.

Confirmed in production on APISIX 3.17.0 (docker push to a registry behind APISIX failed with
413), reproduced with a standalone OpenResty 1.29.2.4 build; OpenResty 1.27.1.2 (this module's
1.27.1.1 patch) is unaffected.

Fix

Restore the missing && max_body_size line so max_body_size == 0 short-circuits the chunked
check, matching patch/1.27.1.1/... and stock nginx semantics.

 #if (NGX_HTTP_APISIX)
                 (void) clcf; /* unused */

                 if (max_body_size
+                    && max_body_size
 #else
                 if (clcf->client_max_body_size
                     && clcf->client_max_body_size
 #endif
                        - r->headers_in.content_length_n < rb->chunked->size)

Tests

Added regression cases to t/client_max_body_size.t:

  • TEST 12: set_client_max_body_size(0) + Transfer-Encoding: chunked (HTTP/1.1),
    non-empty body → must pass, not 413.
  • TEST 13: same over HTTP/2.

(TEST 11 already covered max-body-size 0 for Content-Length; chunked was the gap.)

Related

This was originally reported (mistakenly) against OpenResty core in openresty/openresty#1139;
the actual root cause is this module's 1.29.2.4 patch, not nginx/OpenResty core.

Summary by CodeRabbit

  • Bug Fixes
    • Improved request body size handling so configured limits are applied more consistently across normal, chunked, and HTTP/2 requests.
    • Requests with no body size limit set now correctly allow larger request bodies without returning a 413 response.
  • Tests
    • Added coverage for unlimited body size handling with chunked requests and HTTP/2 chunked requests.

The 1.29.2.4 client_max_body_size patch dropped the `&& max_body_size` guard in the
chunked body check that 1.27.1.1 has. After preprocessing, the NGX_HTTP_APISIX branch became:

    if (max_body_size - r->headers_in.content_length_n < rb->chunked->size)

So with client_max_body_size 0 (unlimited) and a chunked request (content_length_n == 0),
`0 - 0 < chunk_size` is always true for any non-empty chunk, producing a spurious 413
"client intended to send too large chunked body".

This breaks chunked uploads through APISIX (which renders client_max_body_size 0 by default):
docker push blob upload (chunked PATCH), large file/attachment uploads, etc. Only chunked is
affected; the content-length and rb->received checks in the same patch kept their guard.

Restore `&& max_body_size` so 0 short-circuits, matching patch/1.27.1.1 and stock nginx.
Add regression tests: client_max_body_size 0 + Transfer-Encoding: chunked (http1 + http2)
with non-empty body must pass, not 413.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Peng Yong <ppyy@netegn.com>
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ef23eb18-be0c-42c9-a8b5-53bd49e2e82e

📥 Commits

Reviewing files that changed from the base of the PR and between 996fd95 and 4a3deff.

📒 Files selected for processing (2)
  • patch/1.29.2.4/nginx-client_max_body_size.patch
  • t/client_max_body_size.t

📝 Walkthrough

Walkthrough

A patch to ngx_http_request_body.c (chunked body filter) is updated to use ngx_http_apisix_client_max_body_size(r) instead of clcf->client_max_body_size under NGX_HTTP_APISIX. Two new tests verify that setting client_max_body_size to 0 disables body size limits for chunked and HTTP/2 chunked requests.

Changes

client_max_body_size=0 bypass for chunked and HTTP/2

Layer / File(s) Summary
Patch: chunked body size check via APISIX API
patch/1.29.2.4/nginx-client_max_body_size.patch
Chunked request-body filter switches from clcf->client_max_body_size to ngx_http_apisix_client_max_body_size(r) under NGX_HTTP_APISIX; non-APISIX path is unchanged via #if/#else.
Tests: zero limit for chunked and HTTP/2
t/client_max_body_size.t
TEST 12 and TEST 13 verify that client.set_client_max_body_size(0) disables the 413 limit for chunked and HTTP/2 chunked POST requests respectively.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the chunked-body max_body_size regression and the 1.29.2.4 patch fix.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
E2e Test Quality Review ✅ Passed PASS: The new Test::Nginx cases exercise the real APISIX/Nginx request path for chunked HTTP/1.1 and HTTP/2, cover the 0-limit boundary, and are readable/independent.
Security Check ✅ Passed Touched files only fix client_max_body_size chunked-body logic and add regression tests; no secret, auth, DB, TLS, or ownership code paths were introduced.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

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.

2 participants