Skip to content

S3 gateway: replace Content-Type on CopyObject with REPLACE directive - #10593

Open
RaphaelFakhri wants to merge 1 commit into
treeverse:masterfrom
RaphaelFakhri:fix/s3-copy-replace-content-type-10577
Open

RaphaelFakhri wants to merge 1 commit into
treeverse:masterfrom
RaphaelFakhri:fix/s3-copy-replace-content-type-10577

Conversation

@RaphaelFakhri

Copy link
Copy Markdown

Closes #10577

Change Description

Background

With x-amz-metadata-directive: REPLACE, S3 replaces the object's content type with the Content-Type sent on the copy request. Copying an object onto itself with a new content type is the usual way to fix a wrong one. The lakeFS S3 gateway replaces only the user metadata and keeps the source content type.

Bug Fix

  1. Problem: aws s3api copy-object --metadata-directive REPLACE --content-type application/json through the S3 gateway keeps the source content type (for example text/plain). The new user metadata is applied.
  2. Root cause: handleCopy passes only the x-amz-meta-* headers to Catalog.CopyEntry, and CopyEntry copies ContentType from the source entry in every case.
  3. Solution: Catalog.CopyEntry (and cloneEntry) take a contentType argument and set it on the new entry when replaceSrcMetadata is true, together with the metadata. The gateway passes the request's Content-Type. As with PUT, an empty value stores no content type and reads return the default. The API copy handler passes "" with replaceSrcMetadata set to false, so its behavior does not change.

Testing Details

  • New test TestCopyObjectReplaceContentType in pkg/gateway/handler_test.go. It uploads an object with text/plain through the gateway, copies it with REPLACE and with COPY while sending Content-Type: application/json, and checks the Content-Type that HEAD returns: application/json for REPLACE, text/plain for COPY.
  • Without the fix, the replace subtest fails (expected: "application/json", actual: "text/plain") and the copy subtest passes. With the fix, both pass.
  • GetBasicHandler in pkg/gateway/testutil now gives the handler the catalog's block adapter when USE_BLOCK_ADAPTER is unset or mem. Each in-memory adapter keeps its own data, so before this change a copy through the test handler could not read an object written through the same handler. When USE_BLOCK_ADAPTER names another adapter, the handler still gets that adapter.
  • go test ./pkg/gateway/... ./pkg/catalog/, go test -run Copy ./pkg/api/, go build ./..., go vet, and go tool golangci-lint run ./pkg/gateway/... ./pkg/catalog/ ./pkg/api/ (0 issues) pass.

Breaking Change?

No API, CLI, or client change. S3 gateway clients that send REPLACE now get the request's Content-Type on the copy, which matches S3.

Additional info

Reproduction from the issue, against the S3 gateway:

aws s3api put-object --bucket rep --key main/data.json --body data.json --content-type text/plain --metadata '{"k":"v"}'
aws s3api copy-object --bucket rep --key main/data.json --copy-source rep/main/data.json \
  --metadata-directive REPLACE --content-type application/json --metadata '{"k":"w"}'
aws s3api head-object --bucket rep --key main/data.json --query ContentType --output text
# before: text/plain
# after:  application/json

Contact Details

mail@raphaelfakhri.com

@CLAassistant

CLAassistant commented Nov 3, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions github-actions Bot added area/cataloger Improvements or additions to the cataloger area/gateway Changes to the gateway area/testing Improvements or additions to tests labels Nov 3, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/cataloger Improvements or additions to the cataloger area/gateway Changes to the gateway area/testing Improvements or additions to tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: S3 gateway CopyObject with REPLACE keeps the source Content-Type

2 participants