Skip to content

fix: declare aws-chunked content encoding on streaming uploads - #2277

Merged
harshavardhana merged 2 commits into
minio:masterfrom
allanrogerr:issue-1802-content-encoding-aws-chunked
Aug 10, 2026
Merged

harshavardhana merged 2 commits into
minio:masterfrom
allanrogerr:issue-1802-content-encoding-aws-chunked

Conversation

@allanrogerr

@allanrogerr allanrogerr commented Aug 3, 2026 •

Copy link
Copy Markdown
Contributor

RDMA failure fixed in #2276

Description

Streaming SigV4 and unsigned-trailer uploads frame the request body as aws-chunked but never declare it. PR #1803 tried to declare it through req.TransferEncoding = []string{"aws-chunked"}, which Go's net/http silently drops (it only honors "chunked"), so nothing reached the wire and #1802 was reopened.

  • Adds one idempotent helper, setAwsChunkedContentEncoding, used by all four production call sites: the shared signed-streaming preparer (StreamingSignV4/Express/Outposts), the unsigned-streaming preparer, and the two trailer paths in request-signature-v4.go.
  • Sets Content-Encoding: aws-chunked before the seed signature is computed, so the header is signed. A caller-set encoding survives as aws-chunked,gzip (the two trailer paths previously clobbered it), multi-value headers are merged, and an already-present token (any case, with or without whitespace) is left unchanged.
  • Removes the two dead req.TransferEncoding = []string{"aws-chunked"} writes.
  • Updates two golden signatures (content-encoding now joins SignedHeaders). The AWS-docs-derived trailer golden is unchanged, which pins helper idempotence.
  • Adds six tests: a 7-case table test asserting header value and SignedHeaders membership, an httptest wire round-trip, and one test per entry point (StreamingUnsignedV4, SignV4Trailer, UnsignedTrailer, multi-value header).

Motivation and Context

Fixes #1802. Servers that do not sniff x-amz-content-sha256 store the chunk framing as object data (see the issue thread and gitea#33638). The AWS SigV4 streaming spec lists Content-Encoding under the headers a chunked upload must include ("Set the value to aws-chunked ... For example: Content-Encoding : aws-chunked,gzip"), and its example request signs it.

Compatibility notes:

  • minio-go already sends and signs this header on the trailing-checksum path (request-signature-v4.go), so this extends an existing wire shape to plain-HTTP streaming uploads rather than introducing a new one. Conformant verifiers recompute the signature from received headers, so signatures stay valid.
  • AWS documents that S3 stores the object without the aws-chunked encoding, and MinIO server strips it in trimAwsChunkedContentEncoding. A server that stores Content-Encoding verbatim would now echo aws-chunked in object metadata for plain-HTTP streaming PUTs, as it already does for trailing-checksum PUTs.

How to test this PR?

go test -race -count=1 ./pkg/signer/

Side-by-side results, master (802bd60) versus this PR:

Check master 802bd60 this PR
Wire capture through a real net/http round trip (httptest), all three streaming paths server receives Content-Encoding: "", Transfer-Encoding: [] — the framing is never declared server receives Content-Encoding: aws-chunked on all three paths
The added tests, run against each tree FAIL: Content-Encoding = "", want "aws-chunked" and content-encoding missing from SignedHeaders PASS: 26/26 under -race, repeated across 8 runs
Live server, plain-HTTP streaming signature (quay.io/minio/minio:latest): PutObject + GetObject + StatObject for plain, user-gzip, and no-trailing shapes accepted only because MinIO sniffs x-amz-content-sha256; nothing declares the framing all three accepted with the new signed header; GET round-trip byte-identical; stored Content-Encoding is ""/"gzip" — aws-chunked stripped, user gzip preserved
Golden signatures seed 38cab3af... (content-encoding not signed) 00748050... — re-derived independently from first principles; the derivation reproduces the AWS-docs control 4f232c43..., and the unchanged trailer golden 106e2a8a... still passes byte-identically
Guard coverage — TrimSpace and Header.Values guards are mutation-verified: reverting either one fails the matching new test
Helper cost — 396-860 ns/op, ≤3 allocs/op per request (micro-benchmark) — noise against a network PUT

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Optimization (provides speedup with no functional changes)
  • Cleanup/Maintenance (no functional changes)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • Fixes a regression (If yes, please add commit-id or PR # here)
  • Unit tests added/updated
  • Internal documentation updated

Summary by CodeRabbit

  • Bug Fixes
    • Improved AWS-chunked streaming uploads to preserve existing content encodings.
    • Prevented duplicate aws-chunked encoding values in request headers.
    • Updated signed and unsigned streaming requests for more consistent transfer handling.
  • Tests
    • Added coverage for signed, unsigned, trailer-based, and multi-value content-encoding scenarios.

@allanrogerr allanrogerr self-assigned this Aug 3, 2026
@coderabbitai

coderabbitai Bot commented Aug 3, 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: ASSERTIVE

Plan: Pro Plus

Run ID: eafe3b64-0698-4bd2-9bb4-267f5352b139

📥 Commits

Reviewing files that changed from the base of the PR and between 802bd60 and 43d9cc1.

📒 Files selected for processing (5)
  • pkg/signer/request-signature-streaming-unsigned-trailer.go
  • pkg/signer/request-signature-streaming.go
  • pkg/signer/request-signature-streaming_test.go
  • pkg/signer/request-signature-v4.go
  • pkg/signer/utils.go

📝 Walkthrough

Walkthrough

The signer now uses shared AWS chunked content-encoding handling for streaming requests. Existing encodings are preserved, duplicate aws-chunked values are avoided, and tests cover signed, unsigned, trailer, and HTTP transmission behavior.

Changes

AWS chunked encoding

Layer / File(s) Summary
Shared content-encoding helper
pkg/signer/utils.go
Adds setAwsChunkedContentEncoding, which preserves existing encodings and avoids duplicate aws-chunked values.
Streaming request wiring
pkg/signer/request-signature-v4.go, pkg/signer/request-signature-streaming.go, pkg/signer/request-signature-streaming-unsigned-trailer.go
Signed and unsigned trailer requests use the shared helper instead of directly assigning transfer or content encoding.
Streaming behavior validation
pkg/signer/request-signature-streaming_test.go
Tests cover signatures, encoding combinations, trailers, HTTP transmission, body closure, and multi-value headers.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Poem

A rabbit checks each chunk with care,
Adds AWS encoding to the air.
Gzip stays, duplicates flee,
Signed streams hop successfully.
The headers line up neat and bright.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main fix: declaring aws-chunked content encoding for streaming uploads.
Linked Issues check ✅ Passed The changes ensure streaming uploads declare aws-chunked encoding, which directly addresses issue #1802.
Out of Scope Changes check ✅ Passed The code changes, signature updates, and tests are directly related to the streaming upload encoding fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

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.

Streaming SigV4 and unsigned-trailer uploads framed the body as
aws-chunked without declaring it: the req.TransferEncoding writes
were silently dropped by net/http. Set the Content-Encoding header
at all four call sites, preserving caller-set encodings.

Fixes minio#1802
@allanrogerr
allanrogerr force-pushed the issue-1802-content-encoding-aws-chunked branch from ef2b4ac to 43d9cc1 Compare August 3, 2026 17:08
@allanrogerr
allanrogerr marked this pull request as ready for review August 3, 2026 17:09
@harshavardhana
harshavardhana merged commit f230068 into minio:master Aug 10, 2026
9 of 11 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.

PUT dont set "Transfer-Encoding" but send chucked data

4 participants