mirror of
https://github.com/pgsty/minio.git
synced 2026-10-30 12:30:39 +03:00
fix: strip all reserved metadata on federated CopyObject (#100)
The legacy etcd federation branch of CopyObjectHandler forwards the copied source metadata to the remote deployment with minio-go Core.PutObject, after removing only two reserved keys (compression and actual-size). Every small object is stored inline, so its stored metadata also carries X-Minio-Internal-inline-data; the remote's setRequestLimitMiddleware rejects any request bearing a reserved-prefix header (containsReservedMetadata), so the forwarded write failed with 400 InvalidArgument "Your metadata headers are not supported." for the default COPY metadata directive. A plain federated PutObject must not carry any internal storage metadata, so strip the whole reserved-prefix class before forwarding instead of an enumerated subset. Enumerating a third key would only defer the next leak: besides inline-data, replication bookkeeping (replica/replication status and timestamps) is added to the same map earlier in the handler and would be rejected just the same. None of these keys is required by the remote for a correct plain PutObject; they are internal storage details the remote sets for itself. The stripping uses stringsHasPrefixFold, matching the remote's own case-insensitive detection. Ordinary user metadata (x-amz-meta-*) is untouched and still copied. The pre-existing UUID ETag on the federated write (no Content-MD5 is sent) is out of scope and left unchanged, as recorded in the issue. A new end-to-end test drives the real federation branch through getRemoteInstanceClient and minio-go into a second in-process deployment, copying an inline source with the default COPY directive. It asserts the copy now succeeds, that no reserved-prefix header reaches the remote on any forwarded request, and that copied user metadata survives. Fixes #100 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L7qJqWwy8oFA6aCXWRzXQe Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
+12
-3
@@ -1884,9 +1884,18 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
// Remove the metadata for remote calls.
|
||||
delete(srcInfo.UserDefined, ReservedMetadataPrefix+"compression")
|
||||
delete(srcInfo.UserDefined, ReservedMetadataPrefix+"actual-size")
|
||||
// A plain federated PutObject must not carry any internal storage
|
||||
// metadata. The remote rejects every reserved-prefix header as a class
|
||||
// (containsReservedMetadata), so strip the whole class here rather than
|
||||
// an enumerated subset: an inline source object also carries
|
||||
// inline-data, and replication bookkeeping adds still more, so removing
|
||||
// only compression/actual-size just defers the next rejected key. Match
|
||||
// the remote's case-insensitive detection.
|
||||
for k := range srcInfo.UserDefined {
|
||||
if stringsHasPrefixFold(k, ReservedMetadataPrefix) {
|
||||
delete(srcInfo.UserDefined, k)
|
||||
}
|
||||
}
|
||||
opts := miniogo.PutObjectOptions{
|
||||
UserMetadata: srcInfo.UserDefined,
|
||||
ServerSideEncryption: dstOpts.ServerSideEncryption,
|
||||
|
||||
Reference in New Issue
Block a user