Skip to content

Fix GCS ':' encoding for proxied multipart complete and abort#220

Merged
matthiasL-scality merged 2 commits into
mainfrom
fix/gcs-presign-colon-encoding
Jul 17, 2026
Merged

Fix GCS ':' encoding for proxied multipart complete and abort#220
matthiasL-scality merged 2 commits into
mainfrom
fix/gcs-presign-colon-encoding

Conversation

@matthiasL-scality

Copy link
Copy Markdown
Contributor

Summary

GCS normalises : to %3A in the canonical resource whenever S3 subresource params (uploadId, partNumber) are present — not only for presigned URLs (fixed in #218/#219) but also for Authorization-header proxied requests.

MULTIPART_COMPLETE and MULTIPART_ABORT both include ?uploadId=X in the canonical resource, so GCS rejects them with 403. MULTIPART_UPLOAD_PART (proxied part upload) has the same issue.

Pattern:

Change: for GCS backends (ENDPOINT_URL contains googleapis), encode : as %3A in encoded_key before signing. The proxy_pass URL uses $encoded_key so the path sent to GCS is updated automatically. Standard S3-compatible backends (cloudserver, Scaleway) keep literal :.

Test plan

  • CI passes (test.yml — cloudserver round-trip test exercises complete + abort)
  • New release and devinfra bump; re-run test-upload in scality/action-artifacts

🤖 Generated with Claude Code

GCS normalises ':' to '%3A' in the canonical resource whenever S3
subresource params (uploadId, partNumber) are present — not only for
presigned URLs but also for Authorization-header proxied requests.

MULTIPART_COMPLETE and MULTIPART_ABORT both include '?uploadId=X' in
the canonical resource, so GCS rejects them with 403 when the key
contains literal ':'. MULTIPART_UPLOAD_PART has the same issue.

For GCS backends (ENDPOINT_URL contains 'googleapis'), encode ':'  as
'%3A' in encoded_key before signing. The proxy_pass URL uses $encoded_key
so the path sent to GCS is also updated automatically.

Standard S3-compatible backends (cloudserver, Scaleway) keep literal ':'.
MULTIPART_INITIATE uses '?uploads' (no value) and is unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@matthiasL-scality
matthiasL-scality requested a review from a team as a code owner July 17, 2026 12:41
@claude

claude Bot commented Jul 17, 2026

Copy link
Copy Markdown

LGTM

Review by Claude Code

The test showed that GCS rejects both literal ':' and '%3A' variants
when '?uploadId=X' is included in the canonical resource. GCS computes:

  POST\n\napplication/xml\n\nx-amz-date:...\n/bucket/key%3A...

No '?uploadId=X' — consistent with the presigned URL behaviour where
'?partNumber=N&uploadId=X' is also excluded.

Update MULTIPART_COMPLETE, MULTIPART_ABORT, and MULTIPART_UPLOAD_PART:
for GCS, encode ':' as '%3A' AND omit uploadId/partNumber subresources
from the canonical resource (the URL still carries them for GCS to route
the operation; only the signature computation omits them).

Standard S3-compatible backends keep literal ':' and include subresources.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude

claude Bot commented Jul 17, 2026

Copy link
Copy Markdown

LGTM

The GCS colon-encoding fix for proxied multipart operations is consistent with the existing PRESIGN_PART approach: encode : as %3A in encoded_key (so proxy_pass picks it up) and drop subresource query params from the canonical resource. The os.getenv check and Lua %%3A replacement pattern are correct.

Review by Claude Code

@matthiasL-scality
matthiasL-scality merged commit 003946d into main Jul 17, 2026
5 checks passed
@matthiasL-scality
matthiasL-scality deleted the fix/gcs-presign-colon-encoding branch July 17, 2026 13:03
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.

1 participant