mirror of
https://github.com/minio/minio.git
synced 2025-01-11 23:13:23 -05:00
Fix PutObject/CopyObject with metadata for GCS gateway (#5828)
Make sure to apply standard headers such as Content-Type, Content-Disposition and Content-Language to the correct GCS object attributes during object upload and copy operations. Fixes: #5800
This commit is contained in:
parent
0e9c73cbcf
commit
9f31da5d57
@ -758,18 +758,57 @@ func (l *gcsGateway) GetObject(ctx context.Context, bucket string, key string, s
|
|||||||
func fromGCSAttrsToObjectInfo(attrs *storage.ObjectAttrs) minio.ObjectInfo {
|
func fromGCSAttrsToObjectInfo(attrs *storage.ObjectAttrs) minio.ObjectInfo {
|
||||||
// All google cloud storage objects have a CRC32c hash, whereas composite objects may not have a MD5 hash
|
// All google cloud storage objects have a CRC32c hash, whereas composite objects may not have a MD5 hash
|
||||||
// Refer https://cloud.google.com/storage/docs/hashes-etags. Use CRC32C for ETag
|
// Refer https://cloud.google.com/storage/docs/hashes-etags. Use CRC32C for ETag
|
||||||
|
metadata := make(map[string]string)
|
||||||
|
for k, v := range attrs.Metadata {
|
||||||
|
metadata[k] = v
|
||||||
|
}
|
||||||
|
if attrs.ContentType != "" {
|
||||||
|
metadata["content-type"] = attrs.ContentType
|
||||||
|
}
|
||||||
|
if attrs.ContentEncoding != "" {
|
||||||
|
metadata["content-encoding"] = attrs.ContentEncoding
|
||||||
|
}
|
||||||
|
if attrs.CacheControl != "" {
|
||||||
|
metadata["cache-control"] = attrs.CacheControl
|
||||||
|
}
|
||||||
|
if attrs.ContentDisposition != "" {
|
||||||
|
metadata["content-disposition"] = attrs.ContentDisposition
|
||||||
|
}
|
||||||
|
if attrs.ContentLanguage != "" {
|
||||||
|
metadata["content-language"] = attrs.ContentLanguage
|
||||||
|
}
|
||||||
return minio.ObjectInfo{
|
return minio.ObjectInfo{
|
||||||
Name: attrs.Name,
|
Name: attrs.Name,
|
||||||
Bucket: attrs.Bucket,
|
Bucket: attrs.Bucket,
|
||||||
ModTime: attrs.Updated,
|
ModTime: attrs.Updated,
|
||||||
Size: attrs.Size,
|
Size: attrs.Size,
|
||||||
ETag: minio.ToS3ETag(fmt.Sprintf("%d", attrs.CRC32C)),
|
ETag: minio.ToS3ETag(fmt.Sprintf("%d", attrs.CRC32C)),
|
||||||
UserDefined: attrs.Metadata,
|
UserDefined: metadata,
|
||||||
ContentType: attrs.ContentType,
|
ContentType: attrs.ContentType,
|
||||||
ContentEncoding: attrs.ContentEncoding,
|
ContentEncoding: attrs.ContentEncoding,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applyMetadataToGCSAttrs applies metadata to a GCS ObjectAttrs instance
|
||||||
|
func applyMetadataToGCSAttrs(metadata map[string]string, attrs *storage.ObjectAttrs) {
|
||||||
|
attrs.ContentType = metadata["content-type"]
|
||||||
|
attrs.ContentEncoding = metadata["content-encoding"]
|
||||||
|
attrs.CacheControl = metadata["cache-control"]
|
||||||
|
attrs.ContentDisposition = metadata["content-disposition"]
|
||||||
|
attrs.ContentLanguage = metadata["content-language"]
|
||||||
|
|
||||||
|
attrs.Metadata = make(map[string]string)
|
||||||
|
for k, v := range metadata {
|
||||||
|
attrs.Metadata[k] = v
|
||||||
|
}
|
||||||
|
// Filter metadata which is stored as a unique attribute
|
||||||
|
for _, key := range []string{
|
||||||
|
"content-type", "content-encoding", "cache-control", "content-disposition", "content-language",
|
||||||
|
} {
|
||||||
|
delete(attrs.Metadata, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetObjectInfo - reads object info and replies back ObjectInfo
|
// GetObjectInfo - reads object info and replies back ObjectInfo
|
||||||
func (l *gcsGateway) GetObjectInfo(ctx context.Context, bucket string, object string) (minio.ObjectInfo, error) {
|
func (l *gcsGateway) GetObjectInfo(ctx context.Context, bucket string, object string) (minio.ObjectInfo, error) {
|
||||||
// if we want to mimic S3 behavior exactly, we need to verify if bucket exists first,
|
// if we want to mimic S3 behavior exactly, we need to verify if bucket exists first,
|
||||||
@ -800,10 +839,7 @@ func (l *gcsGateway) PutObject(ctx context.Context, bucket string, key string, d
|
|||||||
object := l.client.Bucket(bucket).Object(key)
|
object := l.client.Bucket(bucket).Object(key)
|
||||||
|
|
||||||
w := object.NewWriter(l.ctx)
|
w := object.NewWriter(l.ctx)
|
||||||
|
applyMetadataToGCSAttrs(metadata, &w.ObjectAttrs)
|
||||||
w.ContentType = metadata["content-type"]
|
|
||||||
w.ContentEncoding = metadata["content-encoding"]
|
|
||||||
w.Metadata = metadata
|
|
||||||
|
|
||||||
if _, err := io.Copy(w, data); err != nil {
|
if _, err := io.Copy(w, data); err != nil {
|
||||||
// Close the object writer upon error.
|
// Close the object writer upon error.
|
||||||
@ -832,7 +868,7 @@ func (l *gcsGateway) CopyObject(ctx context.Context, srcBucket string, srcObject
|
|||||||
dst := l.client.Bucket(destBucket).Object(destObject)
|
dst := l.client.Bucket(destBucket).Object(destObject)
|
||||||
|
|
||||||
copier := dst.CopierFrom(src)
|
copier := dst.CopierFrom(src)
|
||||||
copier.ObjectAttrs.Metadata = srcInfo.UserDefined
|
applyMetadataToGCSAttrs(srcInfo.UserDefined, &copier.ObjectAttrs)
|
||||||
|
|
||||||
attrs, err := copier.Run(l.ctx)
|
attrs, err := copier.Run(l.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -865,9 +901,7 @@ func (l *gcsGateway) NewMultipartUpload(ctx context.Context, bucket string, key
|
|||||||
w := l.client.Bucket(bucket).Object(meta).NewWriter(l.ctx)
|
w := l.client.Bucket(bucket).Object(meta).NewWriter(l.ctx)
|
||||||
defer w.Close()
|
defer w.Close()
|
||||||
|
|
||||||
w.ContentType = metadata["content-type"]
|
applyMetadataToGCSAttrs(metadata, &w.ObjectAttrs)
|
||||||
w.ContentEncoding = metadata["content-encoding"]
|
|
||||||
w.Metadata = metadata
|
|
||||||
|
|
||||||
if err = json.NewEncoder(w).Encode(gcsMultipartMetaV1{
|
if err = json.NewEncoder(w).Encode(gcsMultipartMetaV1{
|
||||||
gcsMinioMultipartMetaCurrentVersion,
|
gcsMinioMultipartMetaCurrentVersion,
|
||||||
@ -1076,6 +1110,10 @@ func (l *gcsGateway) CompleteMultipartUpload(ctx context.Context, bucket string,
|
|||||||
|
|
||||||
composer := l.client.Bucket(bucket).Object(key).ComposerFrom(parts...)
|
composer := l.client.Bucket(bucket).Object(key).ComposerFrom(parts...)
|
||||||
composer.ContentType = partZeroAttrs.ContentType
|
composer.ContentType = partZeroAttrs.ContentType
|
||||||
|
composer.ContentEncoding = partZeroAttrs.ContentEncoding
|
||||||
|
composer.CacheControl = partZeroAttrs.CacheControl
|
||||||
|
composer.ContentDisposition = partZeroAttrs.ContentDisposition
|
||||||
|
composer.ContentLanguage = partZeroAttrs.ContentLanguage
|
||||||
composer.Metadata = partZeroAttrs.Metadata
|
composer.Metadata = partZeroAttrs.Metadata
|
||||||
attrs, err := composer.Run(l.ctx)
|
attrs, err := composer.Run(l.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user