Skip to content

🐛 fix: Enforce BodyLimit on request decompression and multipart form parsing#4213

Merged
ReneWerner87 merged 6 commits into
mainfrom
update-fasthttp-compression-to-use-withlimit
Apr 15, 2026
Merged

🐛 fix: Enforce BodyLimit on request decompression and multipart form parsing#4213
ReneWerner87 merged 6 commits into
mainfrom
update-fasthttp-compression-to-use-withlimit

Conversation

@gaby
Copy link
Copy Markdown
Member

@gaby gaby commented Apr 14, 2026

Motivation

  • Ensure request-side decompression and multipart parsing respect the application BodyLimit to avoid unbounded memory usage and DoS vectors.
  • Propagate the app BodyLimit into form binders and request decoding paths so all entry points use the same limit.

Description

  • Use fasthttp limit-aware helpers by switching decompression calls to BodyGunzipWithLimit, BodyUnbrotliWithLimit, BodyInflateWithLimit, and BodyUnzstdWithLimit and passing r.c.app.config.BodyLimit from tryDecodeBodyInOrder.
  • Enforce body limits for multipart parsing by replacing MultipartForm() with MultipartFormWithLimit(r.c.app.config.BodyLimit) in MultipartForm() and in FormBinding.bindMultipart call req.MultipartFormWithLimit(b.MaxBodySize).
  • Add MaxBodySize int to FormBinding, wire it from Bind.Form() via bind.MaxBodySize = b.ctx.App().config.BodyLimit, and reset it in FormBinding.Reset().
  • Update docs to state that BodyLimit bounds Ctx.Body() decompression and Ctx.MultipartForm() parsing, and update middleware docs and changelog to reflect the change.
  • Applies changes introduced in Add WithLimit methods for uncompression valyala/fasthttp#2147

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 14, 2026

Walkthrough

The changes implement body size limiting for decompressed request bodies and multipart form parsing. The app's BodyLimit configuration now constrains request body decompression via Content-Encoding headers and multipart form parsing, enforced through fasthttp's *WithLimit helpers. Documentation updated to reflect these behaviors.

Changes

Cohort / File(s) Summary
Core Implementation
bind.go, binder/form.go, req.go
Added body size limit enforcement to form binding and request body parsing. FormBinding struct now includes MaxBodySize field; multipart and decompression operations use fasthttp *WithLimit variants constrained by app BodyLimit configuration.
Form Binding Tests
binder/form_test.go, ctx_test.go
Added test coverage for body limit enforcement with compressed and multipart request bodies. Tests verify that fasthttp.ErrBodyTooLarge is returned when payloads exceed configured limits.
Compression Tests
middleware/compress/compress_test.go
Added test verifying compressed request bodies respect app BodyLimit configuration when processed through compression middleware.
Documentation
docs/api/ctx.md, docs/api/fiber.md, docs/middleware/compress.md, docs/whats_new.md
Updated API and middleware documentation to clarify that BodyLimit enforcement now applies to decompressed request bodies and multipart form parsing, with release notes added for v3 compression behavior changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • gofiber/fiber#3206: Updates documentation for Ctx.Body() and Ctx.MultipartForm() methods in docs/api/ctx.md.
  • gofiber/fiber#3309: Modifies multipart form binding in binder/form.go with related file handling changes.

Suggested labels

📒 Documentation

Suggested reviewers

  • efectn
  • ReneWerner87

Poem

🐰 Body limits now apply with care,
From gzip streams to forms in air,
No oversized requests get through,
The BodyLimit config knows what to do! 📦✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description covers motivation, implementation details, and documentation updates, but the author-provided description does not follow the repository's template structure with required checklist items. Consider filling out the template sections (Changes introduced, Type of change, Checklist) to ensure consistency with repository standards and validate that all requirements have been addressed.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main changes: enforcing BodyLimit on request decompression and multipart form parsing, which is the primary purpose of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch update-fasthttp-compression-to-use-withlimit

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 and usage tips.

@ReneWerner87 ReneWerner87 added this to v3 Apr 14, 2026
@ReneWerner87 ReneWerner87 added this to the v3 milestone Apr 14, 2026
@gaby gaby changed the title Enforce BodyLimit on request decompression and multipart form parsing 🔥 feat: Enforce BodyLimit on request decompression and multipart form parsing Apr 14, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.19%. Comparing base (df0eca4) to head (1b232b5).
⚠️ Report is 13 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4213      +/-   ##
==========================================
- Coverage   91.22%   91.19%   -0.04%     
==========================================
  Files         123      123              
  Lines       11892    11910      +18     
==========================================
+ Hits        10849    10861      +12     
- Misses        655      660       +5     
- Partials      388      389       +1     
Flag Coverage Δ
unittests 91.19% <100.00%> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gaby gaby changed the title 🔥 feat: Enforce BodyLimit on request decompression and multipart form parsing 🐛 fix: Enforce BodyLimit on request decompression and multipart form parsing Apr 14, 2026
@gaby gaby moved this to In Progress in v3 Apr 14, 2026
@gaby gaby marked this pull request as ready for review April 14, 2026 11:55
@gaby gaby requested a review from a team as a code owner April 14, 2026 11:55
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request ensures that the configured BodyLimit is enforced during request body decompression and multipart form parsing by utilizing fasthttp's limit-aware helper methods. Documentation and tests have been updated to reflect these changes. Feedback suggests extending this enforcement to other multipart-related methods like FormFile() and FormValue(), and improving error handling in Ctx.Body() to return a 413 Request Entity Too Large status code instead of a 200 OK when the limit is exceeded.

Comment thread req.go
Comment thread req.go
Comment thread ctx_test.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
ctx_test.go (1)

1027-1051: Consider extending BodyLimit decode tests to non-gzip encodings.

This new test covers gzip well, but the changed implementation also added limit-aware paths for br, deflate, and zstd. A small table-driven extension here would better protect against regressions in those branches.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ctx_test.go` around lines 1027 - 1051, Extend
Test_Ctx_Body_With_Compression_BodyLimitExceeded into a table-driven test that
iterates over content-encoding values ("gzip", "br", "deflate", "zstd") and for
each case sets c.Request().Header.Set(HeaderContentEncoding, enc) and supplies a
compressed payload exceeding the configured BodyLimit so you exercise the
limit-aware branches added for brotli/deflate/zstd; reuse the existing setup
(New(Config{BodyLimit: 8}), AcquireCtx -> (*DefaultCtx), set Request body) and
assertions (expect fasthttp.ErrBodyTooLarge in c.Body(), original compressedBody
remains in c.Request().Body(), and StatusOK) while generating the compressed
payload using the appropriate compressor for each encoding in the table entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ctx_test.go`:
- Around line 1027-1051: Extend Test_Ctx_Body_With_Compression_BodyLimitExceeded
into a table-driven test that iterates over content-encoding values ("gzip",
"br", "deflate", "zstd") and for each case sets
c.Request().Header.Set(HeaderContentEncoding, enc) and supplies a compressed
payload exceeding the configured BodyLimit so you exercise the limit-aware
branches added for brotli/deflate/zstd; reuse the existing setup
(New(Config{BodyLimit: 8}), AcquireCtx -> (*DefaultCtx), set Request body) and
assertions (expect fasthttp.ErrBodyTooLarge in c.Body(), original compressedBody
remains in c.Request().Body(), and StatusOK) while generating the compressed
payload using the appropriate compressor for each encoding in the table entries.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 579e01c5-c7bf-46c9-827d-97953256b677

📥 Commits

Reviewing files that changed from the base of the PR and between df0eca4 and cf1af54.

📒 Files selected for processing (10)
  • bind.go
  • binder/form.go
  • binder/form_test.go
  • ctx_test.go
  • docs/api/ctx.md
  • docs/api/fiber.md
  • docs/middleware/compress.md
  • docs/whats_new.md
  • middleware/compress/compress_test.go
  • req.go

@gaby
Copy link
Copy Markdown
Member Author

gaby commented Apr 14, 2026

@copilot review this pull request.

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 14, 2026

@copilot review this pull request.

Reviewed the PR. Here's a summary of what was checked:

Code correctness:

  • tryDecodeBodyInOrder in req.go correctly switches to BodyGunzipWithLimit, BodyUnbrotliWithLimit, BodyInflateWithLimit, and BodyUnzstdWithLimit, all passing r.c.app.config.BodyLimit. Since BodyLimit is always ≥ DefaultBodyLimit (4 MB) after New() normalizes the value, the limit is always meaningful.
  • DefaultReq.MultipartForm() now calls r.c.fasthttp.MultipartFormWithLimit(r.c.app.config.BodyLimit) — correctly delegates to the Request level so the Content-Encoding header (e.g., gzip-compressed multipart) is also honoured by fasthttp's implementation.
  • FormBinding.bindMultipart uses req.MultipartFormWithLimit(b.MaxBodySize). When MaxBodySize is 0 (standalone use, not through Bind.Form()), fasthttp applies no limit — same as the pre-existing MultipartForm() behaviour, so no regression.
  • Bind.Form() wires bind.MaxBodySize = b.ctx.App().config.BodyLimit after acquiring from the pool, and FormBinding.Reset() zeroes it back — pool lifecycle is correct.

Tests:

  • Test_Ctx_Body_With_Compression_BodyLimitExceeded: gzip payload larger than BodyLimit (8 bytes) returns ErrBodyTooLarge as the body and leaves the raw compressed bytes intact. ✅
  • Test_Ctx_MultipartForm_BodyLimitExceeded: gzip-compressed multipart field > BodyLimit (64 bytes) returns ErrBodyTooLarge. ✅
  • Test_FormBinder_BindMultipart_BodyLimitExceeded: direct FormBinding with MaxBodySize: 64 returns ErrBodyTooLarge. ✅
  • Full test suite: all passing. Lint: 0 issues. Markdown: 0 errors.

Docs: ctx.md, fiber.md, compress.md, and whats_new.md are all updated correctly and consistently.

Copilot finished work on behalf of gaby April 14, 2026 12:19
@gaby
Copy link
Copy Markdown
Member Author

gaby commented Apr 15, 2026

@copilot Ctx.Body() returns 200 OK even when the body limit is exceeded during decompression. It would be better to return 413 Request Entity Too Large in this scenario to accurately reflect the failure to the client

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 15, 2026

@copilot Ctx.Body() returns 200 OK even when the body limit is exceeded during decompression. It would be better to return 413 Request Entity Too Large in this scenario to accurately reflect the failu...

Fixed in fafaf8f. Added a fasthttp.ErrBodyTooLarge case to the error switch in Body() that calls SendStatus(StatusRequestEntityTooLarge), and updated the test to assert StatusRequestEntityTooLarge instead of StatusOK.

Copilot finished work on behalf of gaby April 15, 2026 12:57
@gaby
Copy link
Copy Markdown
Member Author

gaby commented Apr 15, 2026

@copilot You forgot to update the tests for the compress middleware.

Copilot AI review requested due to automatic review settings April 15, 2026 13:11
@gaby gaby review requested due to automatic review settings April 15, 2026 13:11
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 15, 2026

@copilot You forgot to update the tests for the compress middleware.

Fixed in ad614eb. Updated Test_Compress_RespectsBodyLimitOnCompressedRequestBody to assert StatusRequestEntityTooLarge (413) instead of StatusOK (200).

Copilot finished work on behalf of gaby April 15, 2026 13:12
@gaby
Copy link
Copy Markdown
Member Author

gaby commented Apr 15, 2026

@copilot While MultipartForm() now correctly enforces the BodyLimit, other multipart-related methods in req.go such as FormFile() and FormValue() still call the underlying fasthttp methods directly. Those methods use a default 8MB limit, effectively bypassing the application's configured BodyLimit. Consider updating them to call this MultipartForm() method first to ensure consistent limit enforcement.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 97efe65 Previous: b08638a Ratio
Benchmark_ShutdownServices/no-services (github.com/gofiber/fiber/v3) 3889 ns/op 3912 B/op 19 allocs/op 2535 ns/op 3912 B/op 19 allocs/op 1.53
Benchmark_ShutdownServices/no-services (github.com/gofiber/fiber/v3) - ns/op 3889 ns/op 2535 ns/op 1.53
Benchmark_Compress/Zstd (github.com/gofiber/fiber/v3/middleware/compress) - B/op 1 B/op 0 B/op +∞

This comment was automatically generated by workflow using github-action-benchmark.

Copilot AI review requested due to automatic review settings April 15, 2026 13:26
@gaby gaby review requested due to automatic review settings April 15, 2026 13:26
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 15, 2026

@copilot While MultipartForm() now correctly enforces the BodyLimit, other multipart-related methods in req.go such as FormFile() and FormValue() still call the underlying fasthttp methods directly. T...

Fixed in 97efe65.

  • FormFile() now calls r.MultipartForm() first and propagates ErrBodyTooLarge directly, so it never falls through to fasthttp's 8 MiB parse.
  • FormValue() on multipart requests now queries QueryArgsPostArgs → our limit-aware MultipartForm() directly, returning the default value if the body limit is exceeded, instead of delegating to fasthttp's FormValue which would re-parse with 8 MiB. Non-multipart requests still delegate to fasthttp's FormValue unchanged.

Tests Test_Ctx_FormFile_BodyLimitExceeded and Test_Ctx_FormValue_BodyLimitExceeded cover both cases.

Copilot finished work on behalf of gaby April 15, 2026 13:28
@gaby
Copy link
Copy Markdown
Member Author

gaby commented Apr 15, 2026

@copilot The FormValue function in req.go needs 100% test coverage.

Copilot AI review requested due to automatic review settings April 15, 2026 14:19
@gaby gaby review requested due to automatic review settings April 15, 2026 14:19
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 15, 2026

@copilot The FormValue function in req.go needs 100% test coverage.

Fixed in 1b232b5. Added four new test functions covering all previously-untested branches of FormValue, bringing it to 100% coverage:

  • Test_Ctx_FormValue_QueryArgs — multipart request; key found in QueryArgs (returns before parsing form)
  • Test_Ctx_FormValue_PostArgs — multipart request; key found in PostArgs (returns before parsing form)
  • Test_Ctx_FormValue_MultipartKeyNotFound — multipart request; key absent from form (returns "" without a default, returns provided default with one)
  • Test_Ctx_FormValue_NonMultipart — URL-encoded body; delegates to fasthttp's FormValue (returns value and provided default when missing)

Copilot finished work on behalf of gaby April 15, 2026 14:20
@ReneWerner87 ReneWerner87 merged commit a04daa2 into main Apr 15, 2026
20 checks passed
@ReneWerner87 ReneWerner87 deleted the update-fasthttp-compression-to-use-withlimit branch April 15, 2026 14:56
@github-project-automation github-project-automation Bot moved this from In Progress to Done in v3 Apr 15, 2026
@ReneWerner87 ReneWerner87 modified the milestones: v3, v3.2.0 Apr 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants