Skip to content

fix(copy-object): forward request-payer to the source-size HEAD - #653

Closed
ph-tgs wants to merge 1 commit into
awslabs:mainfrom
ph-tgs:copy-object-forward-request-payer
Closed

fix(copy-object): forward request-payer to the source-size HEAD#653
ph-tgs wants to merge 1 commit into
awslabs:mainfrom
ph-tgs:copy-object-forward-request-payer

Conversation

@ph-tgs

@ph-tgs ph-tgs commented Jul 8, 2026

Copy link
Copy Markdown

Issue #, if available: Fixes #652

Description of changes:

Every CopyObject meta-request first issues a HEAD on the source object to determine its size, before any small-vs-multipart branching. That HEAD is built from a fresh aws_http_message in aws_s3_get_source_object_size_message_new() and inherited none of the original request's headers, so x-amz-request-payer was never sent on it. Against a Requester Pays bucket the size-HEAD is rejected with 403 and the whole copy fails — even though the later bypass / multipart-copy sub-requests do forward the header.

This change forwards the request-scoped headers from the original request onto the source-size HEAD, in both the copy_source_uri branch and the x-amz-copy-source fallback branch:

  • x-amz-request-payer — forwarded verbatim (the actual 403 fix).
  • x-amz-source-expected-bucket-owner — mapped onto the HEAD's x-amz-expected-bucket-owner. This is deliberate: on a CopyObject, the source owner is asserted via x-amz-source-expected-bucket-owner, while the plain x-amz-expected-bucket-owner asserts the destination owner. Forwarding the destination owner onto a read of the source object would newly 403 legitimate cross-account copies, so it is intentionally not forwarded.

Testing:

  • New unit test test_s3_get_source_object_size_message_new covering both branches: asserts x-amz-request-payer is forwarded, x-amz-source-expected-bucket-owner maps onto the HEAD's x-amz-expected-bucket-owner, and the destination x-amz-expected-bucket-owner is not leaked onto the source HEAD.
  • Verified adversarially: with the source change reverted the new test fails (x-amz-request-payer absent → AWS_ERROR_HTTP_HEADER_NOT_FOUND); with the fix it passes. The existing message-builder tests (copy bypass, MPU create / upload-part / complete / abort, ranged-get) all still pass.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Every CopyObject meta-request first issues a HEAD on the source object
to learn its size, before any small-vs-multipart branching. That HEAD
is built from a fresh aws_http_message in
aws_s3_get_source_object_size_message_new() and inherited none of the
original request's headers, so x-amz-request-payer was never sent on it.
Against a Requester Pays bucket the size HEAD is rejected with 403 and
the whole copy fails, even though the later bypass / multipart-copy
sub-requests do forward the header.

Forward x-amz-request-payer onto the source-size HEAD in both the
copy_source_uri branch and the x-amz-copy-source fallback branch. Also
map the CopyObject source-owner assertion
(x-amz-source-expected-bucket-owner) onto the HEAD's
x-amz-expected-bucket-owner. The destination x-amz-expected-bucket-owner
is intentionally not forwarded: asserting the destination owner on a read
of the source object would break legitimate cross-account copies.

@TingDaoK TingDaoK left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, I moved the PR to #654 which applies couple trivial fix.

if (aws_http_message_add_header(message, header)) {
return AWS_OP_ERR;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
}
}
/* Avoid leaking the error code. */
aws_reset_error();

@ph-tgs

ph-tgs commented Jul 9, 2026

Copy link
Copy Markdown
Author

Thanks for the format fix! Closing

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.

CopyObject returns 403 on Requester Pays buckets: the source-size HEAD drops x-amz-request-payer

2 participants