From 6226e68b744fa33de62fcc1aa19629d541b8df6e Mon Sep 17 00:00:00 2001 From: "Matthew N. Heler" Date: Wed, 6 May 2026 11:10:32 -0500 Subject: [PATCH] rgw/cloud-transition: url-encode rgwx-source-key metadata header For non-ASCII object keys, raw UTF-8 bytes end up in the signed x-amz-meta-rgwx-source-key header. Strict S3-compatible backends normalize non-ASCII bytes when verifying SigV4, producing a signature mismatch -> HTTP 403, surfaced in LC as -EACCES (-13). url_encode() the value before signing. The header is write-only, so no decode is needed. Signed-off-by: Matthew N. Heler --- src/rgw/driver/rados/rgw_lc_tier.cc | 5 +++-- src/rgw/driver/rados/rgw_sync_module_aws.cc | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/rgw/driver/rados/rgw_lc_tier.cc b/src/rgw/driver/rados/rgw_lc_tier.cc index 56e49a63d39..c02d19f2b52 100644 --- a/src/rgw/driver/rados/rgw_lc_tier.cc +++ b/src/rgw/driver/rados/rgw_lc_tier.cc @@ -823,9 +823,10 @@ void RGWLCCloudStreamPut::init_send_attrs(const DoutPrefixProvider *dpp, attrs["x-amz-meta-rgwx-source-mtime"] = buf; attrs["x-amz-meta-rgwx-source-etag"] = obj_properties.etag; - attrs["x-amz-meta-rgwx-source-key"] = rest_obj.key.name; + // url-encoded; decode the fields for restore if required + attrs["x-amz-meta-rgwx-source-key"] = url_encode(rest_obj.key.name); if (!rest_obj.key.instance.empty()) { - attrs["x-amz-meta-rgwx-source-version-id"] = rest_obj.key.instance; + attrs["x-amz-meta-rgwx-source-version-id"] = url_encode(rest_obj.key.instance); } for (const auto& a : attrs) { ldpp_dout(dpp, 30) << "init_send_attrs attr[" << a.first << "] = " << a.second <