Skip to content

🐛 bug: Fix enforcement of Immutable config for some edge cases#3835

Merged
ReneWerner87 merged 12 commits intov2from
verify-and-fix-immutable-config-flag-usage
Nov 3, 2025
Merged

🐛 bug: Fix enforcement of Immutable config for some edge cases#3835
ReneWerner87 merged 12 commits intov2from
verify-and-fix-immutable-config-flag-usage

Conversation

@gaby
Copy link
Member

@gaby gaby commented Nov 2, 2025

Summary

  • Enforce usage of c.app.getString and c.app.getBytes for Immutable config

Fixes #3236

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 2, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Replaces unsafe byte→string conversions with safe, config-aware helpers and adds immutability-aware return paths for Agent.String and multiple Ctx getters; introduces tests validating Agent.String copies body across repeated calls and that context values remain immutable when Config.Immutable is enabled.

Changes

Cohort / File(s) Summary
Agent safe string
client.go
Agent.String() changed to use safe string conversion via string(body) / app.getString(...) instead of an unsafe byte→string conversion; retains defer release() and existing control flow.
Immutable-aware context getters
ctx.go
Ctx.Body(), error-body paths, BodyParser (multipart/form-data), Hostname(), Params(), Subdomains(), and String() now use app.getBytes() / app.getString() or conditional conversions when Config.Immutable is enabled; comments updated to reflect immutability behavior.
Tests: Agent
client_test.go
Added import sync/atomic and new test Test_Client_Agent_StringCopiesBody which verifies Agent.String() returns independent copied bodies across consecutive calls on a reused connection.
Tests: Context immutability
ctx_test.go
Added Test_Ctx_Immutable_AfterHandler (appears duplicated in diff) that snapshots many Ctx getters under Immutable=true and asserts the first request's captured values remain unchanged after a second request with different headers/values.

Sequence Diagram(s)

sequenceDiagram
    participant Handler
    participant Agent
    participant Server
    participant AppConfig
    Note over Agent,Server: Agent.String call sequence (reused connection)
    Handler->>Agent: Agent.String()
    activate Agent
    Agent->>Server: read response body bytes
    Server-->>Agent: body bytes ("body-1")
    Agent->>AppConfig: Config.Immutable? → getString/getBytes
    AppConfig-->>Agent: returned safe copy or view
    Agent-->>Handler: string(body) (copied)
    deactivate Agent

    Note over Handler,Server: Subsequent call returns new body ("body-2")
    Handler->>Agent: Agent.String()
    activate Agent
    Agent->>Server: read response body bytes
    Server-->>Agent: body bytes ("body-2")
    Agent->>AppConfig: Config.Immutable? → getString/getBytes
    AppConfig-->>Agent: returned safe copy or view
    Agent-->>Handler: string(body) (copied)
    deactivate Agent
Loading
sequenceDiagram
    participant Handler
    participant Ctx
    participant AppConfig
    Handler->>Ctx: c.Body()
    activate Ctx
    Ctx->>AppConfig: Config.Immutable?
    alt Immutable = true
        AppConfig-->>Ctx: getBytes(copy of bodyBytes)
    else Immutable = false
        AppConfig-->>Ctx: original bodyBytes (zero-copy view)
    end
    Ctx-->>Handler: []byte body
    deactivate Ctx
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review app.getString() / app.getBytes() implementations to ensure they enforce copy semantics when Immutable=true.
  • Inspect Hostname() proxy header parsing and comma-trimming byte-slicing for edge cases (IPv6, ports, multiple forwarded hosts).
  • Verify multipart BodyParser changes preserve behavior when Immutable=false.
  • Check duplicated insertion of Test_Ctx_Immutable_AfterHandler in ctx_test.go (possible accidental duplication).
  • Validate new test Test_Client_Agent_StringCopiesBody for flakiness related to reused connections and atomic increment timing.

Possibly related PRs

Suggested reviewers

  • sixcolors
  • efectn
  • ReneWerner87

Poem

🐰
I nibbled bytes till tails were sound and neat,
Copied every crumb so races face defeat,
Two String calls hopped — each got its treat,
Immutable paws left no overlapping beat. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The pull request description is minimal, providing only a summary ('Enforce usage of c.app.getString and c.app.getBytes for Immutable config') and an issue reference ('Fixes #3236'), but it does not follow the provided template structure. While the summary is relevant, key sections like 'Changes introduced', 'Type of change', and 'Checklist' are not addressed in the description, making it difficult to assess completeness against the expected template. The PR description should be expanded to include the structured sections from the template: a detailed description of the problem and solution, the specific changes introduced, the type of change (e.g., bug fix, enhancement), and confirmation of the checklist items (self-review, tests added, documentation updates if applicable).
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title '🐛 bug: Fix enforcement of Immutable config for some edge cases' is directly related to the main objective of this PR. It clearly communicates that the PR addresses a bug related to enforcing the Immutable configuration, which aligns with the core changes made to ensure c.app.getString and c.app.getBytes are used consistently throughout the codebase.
Linked Issues check ✅ Passed The PR directly addresses the objectives outlined in linked issue #3236. The changes enforce proper use of c.app.getString and c.app.getBytes across multiple files (client.go, ctx.go) to ensure that when Immutable is enabled, request values are properly copied and safe to access from goroutines. The test additions (Test_Client_Agent_StringCopiesBody and Test_Ctx_Immutable_AfterHandler) validate the immutability guarantees, which aligns with the issue's requirement for immutable and race-safe request values.
Out of Scope Changes check ✅ Passed All changes in this PR are directly related to enforcing the Immutable configuration flag. Modifications to client.go, ctx.go, client_test.go, and ctx_test.go all focus on ensuring proper string/byte conversions and immutability guarantees. The String() method fix, Body() error handling, Hostname() hardening, Params conversion, Subdomains() conversion, and test additions are all within scope of fixing the Immutable config enforcement issue.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch verify-and-fix-immutable-config-flag-usage

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.

@gaby gaby changed the title Copy multipart form values in immutable mode 🐛 bug: Fix enforcement of Immutable config Nov 2, 2025
@gaby gaby requested a review from Copilot November 2, 2025 14:28
@gaby gaby changed the title 🐛 bug: Fix enforcement of Immutable config 🐛 bug: Fix enforcement of Immutable config for some edge cases Nov 2, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR enhances the immutable mode in Fiber to ensure that all string values returned from request context methods are properly copied when Config.Immutable is enabled, preventing data races and use-after-free bugs when values are accessed after the request lifecycle.

Key changes:

  • Added immutability support to additional context methods (Params, Hostname, IPs, IP, Protocol, Subdomains, Body error handling, and multipart form values)
  • Fixed a data race in the HTTP client's String() method by using safe string conversion instead of utils.UnsafeString()
  • Updated documentation comments to clarify when immutability applies

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.

File Description
ctx.go Added Config.Immutable checks to multiple methods to ensure returned strings are copied; updated documentation for Params() and Hostname()
ctx_test.go Added comprehensive tests to verify immutability behavior across common methods and pointer isolation
client.go Fixed data race in String() method by replacing utils.UnsafeString() with safe string() conversion
client_test.go Added test to verify that reused agents properly copy response bodies

@gaby gaby marked this pull request as ready for review November 3, 2025 04:33
@gaby gaby requested a review from a team as a code owner November 3, 2025 04:33
Copy link
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.

Actionable comments posted: 0

🧹 Nitpick comments (3)
ctx.go (3)

425-439: Consider a dedicated string copy helper.

The pattern c.app.getString([]byte(key)) and c.app.getString([]byte(val)) converts string → bytes → string, which adds unnecessary overhead since key and values are already strings from the multipart form map.

Consider adding a dedicated helper like c.app.copyString(str string) string that directly copies strings when immutability is enabled, avoiding the intermediate byte slice conversion.

Note: Similar efficiency concerns were raised in past review comments for comparable patterns.


1080-1084: Consider a dedicated string copy helper.

Line 1082 uses c.app.getString([]byte(value)) where value is already a string from route parameters. This string → bytes → string conversion adds unnecessary overhead.

A dedicated c.app.copyString(str string) string helper would avoid the intermediate byte slice allocation and improve efficiency for this common pattern.

Note: This mirrors efficiency concerns raised in past review comments.


1837-1841: Consider a dedicated string copy helper.

The pattern c.app.getString([]byte(subdomain)) converts string → bytes → string where subdomain is already a string from strings.Split(). This adds unnecessary conversion overhead.

Using a dedicated string copy helper would be more efficient for this immutability enforcement.

Note: Consistent with efficiency concerns from past review comments.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa098a7 and 1e72a51.

📒 Files selected for processing (2)
  • client.go (1 hunks)
  • ctx.go (7 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Apply formatting using gofumpt (Make target: format)
Optimize struct field alignment using betteralign (Make target: betteralign)
Modernize code using gopls modernize (Make target: modernize)

Files:

  • client.go
  • ctx.go
🧠 Learnings (3)
📚 Learning: 2025-09-28T17:39:26.644Z
Learnt from: arturmelanchyk
Repo: gofiber/fiber PR: 3768
File: client/request.go:162-166
Timestamp: 2025-09-28T17:39:26.644Z
Learning: In fasthttp-based code like gofiber, using utils.UnsafeString(key) instead of string(key) is acceptable when values are used immediately within the same call stack and not stored for later use, as it avoids allocations and aligns with fasthttp's zero-allocation design philosophy.

Applied to files:

  • client.go
  • ctx.go
📚 Learning: 2024-11-15T07:56:21.623Z
Learnt from: ReneWerner87
Repo: gofiber/fiber PR: 3161
File: app.go:923-932
Timestamp: 2024-11-15T07:56:21.623Z
Learning: In the Fiber framework, breaking changes are acceptable when moving from version 2 to version 3, including modifications to method signatures such as in the `Test` method in `app.go`.

Applied to files:

  • ctx.go
📚 Learning: 2024-12-01T10:28:36.011Z
Learnt from: ReneWerner87
Repo: gofiber/fiber PR: 0
File: :0-0
Timestamp: 2024-12-01T10:28:36.011Z
Learning: Fiber currently supports square bracket notation in form data with 'application/x-www-form-urlencoded' content type, but this feature is not available for multipart form data. The implementation for form-urlencoded is in ctx.go (BodyParser method), while multipart form data handling needs enhancement to support this feature.

Applied to files:

  • ctx.go
🧬 Code graph analysis (1)
ctx.go (1)
helpers.go (1)
  • HeaderXForwardedHost (1033-1033)
🔇 Additional comments (4)
client.go (1)

800-804: LGTM: Safe string conversion.

The change from utils.UnsafeString(body) to string(body) correctly ensures the returned string is safe for storage beyond the immediate call stack, aligning with the PR's goal to enforce immutability guarantees.

ctx.go (3)

353-355: LGTM: Consistent error handling.

Using c.app.getBytes(err.Error()) ensures consistent handling through the app's helper methods.


730-743: LGTM: Correct immutability enforcement for Hostname.

The updated implementation correctly:

  • Works with byte slices from fasthttp headers
  • Handles comma-separated forwarded hosts by trimming at the first comma
  • Returns safe string copies via c.app.getString(hostBytes) when proxy is trusted
  • Updated documentation reflects the conditional immutability behavior

1883-1885: LGTM: Appropriate byte-to-string conversions.

Using c.app.getString() for Method() and FullURI() is correct since both return []byte from fasthttp. This ensures safe string copies for the string representation.

@ReneWerner87
Copy link
Member

@gaby can we add some tests for these special cases ?

Copy link
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.

Actionable comments posted: 0

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

2962-3081: LGTM! Comprehensive immutability test that properly validates the fix.

The test effectively verifies that context values remain immutable across request lifecycles by:

  1. Capturing snapshots of context values during handler execution
  2. Processing a second request with different data (causing context reuse)
  3. Asserting the first snapshot retains its original values

The coverage is thorough, testing Method, Path, OriginalURL, BaseURL, Protocol, Hostname, route params, query strings, cookies, headers, IP/IPs, subdomains, body, and route path.

Optional enhancements to consider:

  1. Subtests for clarity: Consider organizing the assertions into subtests (e.g., t.Run("first_request_data", ...) and t.Run("second_request_data", ...)).

  2. Concurrent access: Issue #3236 specifically mentions goroutines. While this test validates immutability across sequential requests, consider adding a companion test that spawns goroutines to access captured values concurrently and verifies no data races occur (potentially with -race flag).

  3. Documentation: A brief comment at the top explaining this validates immutability guarantees per issue #3236 would help future maintainers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5681594 and cd46723.

📒 Files selected for processing (1)
  • ctx_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Apply formatting using gofumpt (Make target: format)
Optimize struct field alignment using betteralign (Make target: betteralign)
Modernize code using gopls modernize (Make target: modernize)

Files:

  • ctx_test.go
🧠 Learnings (4)
📚 Learning: 2024-11-10T23:44:13.704Z
Learnt from: gaby
Repo: gofiber/fiber PR: 3193
File: middleware/adaptor/adaptor.go:111-111
Timestamp: 2024-11-10T23:44:13.704Z
Learning: In the `middleware/adaptor/adaptor.go` file of the Fiber framework, when updating context handling, replacing `c.Context()` with `c.RequestCtx()` is appropriate to access the `fasthttp.RequestCtx`.

Applied to files:

  • ctx_test.go
📚 Learning: 2024-11-08T04:10:42.990Z
Learnt from: gaby
Repo: gofiber/fiber PR: 3193
File: middleware/cache/cache_test.go:897-897
Timestamp: 2024-11-08T04:10:42.990Z
Learning: In the Fiber framework, `Context()` is being renamed to `RequestCtx()`, and `UserContext()` to `Context()` to improve clarity and align with Go's context conventions.

Applied to files:

  • ctx_test.go
📚 Learning: 2024-11-15T07:56:21.623Z
Learnt from: ReneWerner87
Repo: gofiber/fiber PR: 3161
File: app.go:923-932
Timestamp: 2024-11-15T07:56:21.623Z
Learning: In the Fiber framework, breaking changes are acceptable when moving from version 2 to version 3, including modifications to method signatures such as in the `Test` method in `app.go`.

Applied to files:

  • ctx_test.go
📚 Learning: 2024-11-29T12:37:27.581Z
Learnt from: efectn
Repo: gofiber/fiber PR: 3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.

Applied to files:

  • ctx_test.go
🧬 Code graph analysis (1)
ctx_test.go (4)
app.go (2)
  • New (497-590)
  • Config (121-398)
helpers.go (8)
  • HeaderXForwardedFor (1032-1032)
  • HeaderUserAgent (1043-1043)
  • MethodPost (821-821)
  • HeaderXForwardedHost (1033-1033)
  • HeaderXForwardedProto (1034-1034)
  • HeaderCookie (1007-1007)
  • StatusOK (865-865)
  • MethodPatch (823-823)
ctx.go (5)
  • Ctx (82-100)
  • Ctx (1328-1344)
  • Ctx (1667-1669)
  • Ctx (1672-1688)
  • Ctx (1992-1999)
utils/assertions.go (1)
  • AssertEqual (19-68)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Build (1.22.x, macos-latest)
  • GitHub Check: Build (1.21.x, windows-latest)
  • GitHub Check: Build (1.23.x, macos-latest)
  • GitHub Check: Build (1.22.x, ubuntu-latest)
  • GitHub Check: Build (1.23.x, windows-latest)
  • GitHub Check: Build (1.20.x, windows-latest)
  • GitHub Check: Build (1.19.x, windows-latest)
  • GitHub Check: Build (1.18.x, macos-latest)
  • GitHub Check: Compare

@gaby
Copy link
Member Author

gaby commented Nov 3, 2025

@gaby can we add some tests for these special cases ?

@ReneWerner87 Added tests for client and ctx

@ReneWerner87 ReneWerner87 added this to the v2.52.10 milestone Nov 3, 2025
@ReneWerner87 ReneWerner87 merged commit aa2f7c5 into v2 Nov 3, 2025
27 checks passed
@ReneWerner87 ReneWerner87 deleted the verify-and-fix-immutable-config-flag-usage branch November 3, 2025 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants