From d703daa48046c072f6c7d971ac6e784805e3c747 Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Thu, 30 Mar 2023 12:20:42 -0700 Subject: [PATCH] Add metadata extension to ListObjectVersions (#16930) --- cmd/api-response.go | 26 +++++++++++++++++++++++++- cmd/api-router.go | 3 +++ cmd/bucket-listobjects-handlers.go | 15 +++++++++++---- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/cmd/api-response.go b/cmd/api-response.go index 90de4add5..c1cbea3c7 100644 --- a/cmd/api-response.go +++ b/cmd/api-response.go @@ -493,7 +493,7 @@ func generateListBucketsResponse(buckets []BucketInfo) ListBucketsResponse { } // generates an ListBucketVersions response for the said bucket with other enumerated options. -func generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delimiter, encodingType string, maxKeys int, resp ListObjectVersionsInfo) ListVersionsResponse { +func generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delimiter, encodingType string, maxKeys int, resp ListObjectVersionsInfo, metadata bool) ListVersionsResponse { versions := make([]ObjectVersion, 0, len(resp.Objects)) owner := Owner{ @@ -518,6 +518,30 @@ func generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delim } else { content.StorageClass = globalMinioDefaultStorageClass } + if metadata { + content.UserTags = object.UserTags + content.UserMetadata = &Metadata{} + switch kind, _ := crypto.IsEncrypted(object.UserDefined); kind { + case crypto.S3: + content.UserMetadata.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionAES) + case crypto.S3KMS: + content.UserMetadata.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS) + case crypto.SSEC: + content.UserMetadata.Set(xhttp.AmzServerSideEncryptionCustomerAlgorithm, xhttp.AmzEncryptionAES) + } + for k, v := range cleanMinioInternalMetadataKeys(object.UserDefined) { + if strings.HasPrefix(strings.ToLower(k), ReservedMetadataPrefixLower) { + // Do not need to send any internal metadata + // values to client. + continue + } + // https://github.com/google/security-research/security/advisories/GHSA-76wf-9vgp-pj7w + if equals(k, xhttp.AmzMetaUnencryptedContentLength, xhttp.AmzMetaUnencryptedContentMD5) { + continue + } + content.UserMetadata.Set(k, v) + } + } content.Owner = owner content.VersionID = object.VersionID if content.VersionID == "" { diff --git a/cmd/api-router.go b/cmd/api-router.go index e09b7bc25..3b7751888 100644 --- a/cmd/api-router.go +++ b/cmd/api-router.go @@ -392,6 +392,9 @@ func registerAPIRouter(router *mux.Router) { router.Methods(http.MethodGet).HandlerFunc( collectAPIStats("listobjectsv2", maxClients(gz(httpTraceAll(api.ListObjectsV2Handler))))).Queries("list-type", "2") // ListObjectVersions + router.Methods(http.MethodGet).HandlerFunc( + collectAPIStats("listobjectversions", maxClients(gz(httpTraceAll(api.ListObjectVersionsMHandler))))).Queries("versions", "", "metadata", "true") + // ListObjectVersions router.Methods(http.MethodGet).HandlerFunc( collectAPIStats("listobjectversions", maxClients(gz(httpTraceAll(api.ListObjectVersionsHandler))))).Queries("versions", "") // GetBucketPolicyStatus diff --git a/cmd/bucket-listobjects-handlers.go b/cmd/bucket-listobjects-handlers.go index 7da346a69..c74dc7e46 100644 --- a/cmd/bucket-listobjects-handlers.go +++ b/cmd/bucket-listobjects-handlers.go @@ -59,10 +59,18 @@ func validateListObjectsArgs(prefix, marker, delimiter, encodingType string, max return ErrNone } -// ListObjectVersions - GET Bucket Object versions +func (api objectAPIHandlers) ListObjectVersionsHandler(w http.ResponseWriter, r *http.Request) { + api.listObjectVersionsHandler(w, r, false) +} + +func (api objectAPIHandlers) ListObjectVersionsMHandler(w http.ResponseWriter, r *http.Request) { + api.listObjectVersionsHandler(w, r, true) +} + +// ListObjectVersionsHandler - GET Bucket Object versions // You can use the versions subresource to list metadata about all // of the versions of objects in a bucket. -func (api objectAPIHandlers) ListObjectVersionsHandler(w http.ResponseWriter, r *http.Request) { +func (api objectAPIHandlers) listObjectVersionsHandler(w http.ResponseWriter, r *http.Request, metadata bool) { ctx := newContext(r, w, "ListObjectVersions") defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) @@ -111,8 +119,7 @@ func (api objectAPIHandlers) ListObjectVersionsHandler(w http.ResponseWriter, r writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) return } - - response := generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delimiter, encodingType, maxkeys, listObjectVersionsInfo) + response := generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delimiter, encodingType, maxkeys, listObjectVersionsInfo, metadata) // Write success response. writeSuccessResponseXML(w, encodeResponseList(response))