@ -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 : m etadata,
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 {