Skip to content

fix(net/gclient): fix form field value truncation when uploading files#4627

Merged
hailaz merged 1 commit intogogf:masterfrom
lingcoder:fix/issue-4156-gclient-form-field-truncation
Jan 19, 2026
Merged

fix(net/gclient): fix form field value truncation when uploading files#4627
hailaz merged 1 commit intogogf:masterfrom
lingcoder:fix/issue-4156-gclient-form-field-truncation

Conversation

@lingcoder
Copy link
Contributor

What does this PR do?

Fixes #4156

When posting form data with file upload, if a field value contains = or &, the value was being truncated.

Example

data := g.Map{
    "file":      "@file:/path/to/file.txt",
    "fieldName": "aaa=1&b=2",
}
client.Post(ctx, "/upload", data)

Expected: Server receives fieldName = "aaa=1&b=2"
Actual (before fix): Server receives fieldName = "aaa" (truncated)

Root Cause Analysis

The issue was caused by three problems in the original code:

Problem 1: Global URL encoding disable (httputils.go)

// Original code - PROBLEMATIC
if urlEncode {
    for k, v := range m {
        if gstr.Contains(k, fileUploadingKey) || gstr.Contains(gconv.String(v), fileUploadingKey) {
            urlEncode = false  // Disables URL encoding for ALL values!
            break
        }
    }
}

When any value contained @file:, URL encoding was disabled for ALL values, causing "aaa=1&b=2" to remain unencoded. The & character was then treated as a parameter separator.

Problem 2: Split on all = characters (gclient_request.go)

// Original code - PROBLEMATIC
array := strings.Split(item, "=")  // Splits on ALL '=' characters

This caused "fieldName=aaa=1" to be split into ["fieldName", "aaa", "1"].

Problem 3: No URL decoding for field values

URL-encoded values were written directly to the multipart form without decoding.

Solution

Fix 1: Remove global URL encoding disable

Only @file: prefixed values are kept unencoded for file upload detection. Other values are properly URL-encoded.

Fix 2: Use SplitN to limit split count

array := strings.SplitN(item, "=", 2)  // Only split on first '='

Fix 3: Add URL decoding for field values

if v, err := gurl.Decode(fieldValue); err == nil {
    fieldValue = v
}

Compatibility Analysis

Scenario Before After Compatible
Normal form POST (no file upload) ✅ Works ✅ Works ✅ Yes
File upload + normal field values ✅ Works ✅ Works ✅ Yes
File upload + field values containing = or & ❌ Truncated ✅ Works ✅ Fixed
Field value is @file: (no path) ✅ Works ✅ Works ✅ Yes
Field value starts with @file: but file doesn't exist ❌ Error ❌ Error ✅ Yes
User sends pre-encoded value like "aaa%3D1" ✅ Works ✅ Works ✅ Yes
Content-Type: application/json ✅ Works ✅ Works ✅ Yes
Content-Type: application/xml ✅ Works ✅ Works ✅ Yes

Breaking Change Assessment

No breaking changes. The fix only affects the file upload scenario where field values contain special characters (=, &). Previously this scenario was broken, now it works correctly.

Edge Cases

  1. Literal @file: value: GoFrame treats @file: as a special marker for file upload. This is a framework design decision and remains unchanged.

  2. URL decode failure: If URL decoding fails (e.g., invalid %XX sequence), the original value is preserved.

Test Coverage

Added comprehensive tests covering:

  • Test_Issue4156 - Basic fix verification
  • Test_Issue4156_MultipleSpecialChars - Multiple =, &, %, +, spaces
  • Test_Issue4156_MultipleFields - Multiple fields with special characters
  • Test_Issue4156_NoFileUpload - Normal POST without file upload
  • Test_Issue4156_PreEncodedValue - Pre-encoded values like %3D
  • Test_Issue4156_EmptyAndSpecialValues - Edge cases (= at start/end, only special chars)
  • TestBuildParams_* - httputil.BuildParams comprehensive tests

All tests pass, including existing Test_Issue3748 which tests the @file: marker handling.

Files Changed

  • internal/httputil/httputils.go - Remove global URL encoding disable, adjust @file: condition
  • internal/httputil/httputils_test.go - Add comprehensive BuildParams tests
  • net/gclient/gclient_request.go - Use SplitN, add URL decoding
  • net/gclient/gclient_z_unit_issue_test.go - Add Issue 4156 test cases

gogf#4156)

When posting form data with file upload, if a field value contains '=' or '&',
the value was being truncated. This was caused by:

1. Global URL encoding was disabled when any value contained '@file:' marker
2. strings.Split(item, "=") split on ALL '=' characters in the value
3. URL-encoded values were not decoded before writing to multipart form

This fix:
- Removes the global URL encoding disable logic
- Uses strings.SplitN(item, "=", 2) to only split on the first '='
- Adds URL decoding for field values before writing to multipart form
- Keeps '@file:' prefixed values unencoded for file upload detection
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 fixes a bug where form field values containing = or & characters were being truncated when uploading files via multipart form data.

Changes:

  • Modified parameter parsing to use SplitN with limit 2 to only split on the first = character
  • Added URL decoding for form field names and values in multipart requests
  • Removed global URL encoding disable logic that was causing the truncation issue
  • Added comprehensive test coverage for various edge cases

Reviewed changes

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

File Description
net/gclient/gclient_z_unit_issue_test.go Added 7 comprehensive test functions covering the fix and edge cases including special characters, multiple fields, pre-encoded values, and various scenarios
net/gclient/gclient_request.go Changed Split to SplitN for limiting splits and added URL decoding for field names and values; imported gurl package for decoding
internal/httputil/httputils_test.go Added 5 test functions to verify URL encoding behavior, file upload marker handling, and parameter building
internal/httputil/httputils.go Removed global URL encoding disable logic and simplified @file: marker detection; removed unused gstr import

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@hailaz hailaz merged commit 5e677a1 into gogf:master Jan 19, 2026
24 checks passed
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.

net/gclient: when posting a form, if there is an equal sign in the value, it will be truncated

3 participants