Skip to content

Commit 57a2e80

Browse files
authored
fix(storage): copy metadata when using Copier with grpc (#12919)
We need to not set `destination` on the request unless the user specifies attrs. Since the struct is not a pointer, we have to check if it is empty to determine if it has not been set.
1 parent cc321f4 commit 57a2e80

3 files changed

Lines changed: 35 additions & 3 deletions

File tree

storage/grpc_client.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -952,14 +952,24 @@ func (c *grpcStorageClient) ComposeObject(ctx context.Context, req *composeObjec
952952
}
953953
func (c *grpcStorageClient) RewriteObject(ctx context.Context, req *rewriteObjectRequest, opts ...storageOption) (*rewriteObjectResponse, error) {
954954
s := callSettings(c.settings, opts...)
955-
obj := req.dstObject.attrs.toProtoObject("")
955+
956+
var dst *storagepb.Object
957+
// If the destination object attributes are not set, do not include them
958+
// in the request. This indicates that the object attributes should be
959+
// copied from the source object.
960+
if req.dstObject.attrs.isZero() {
961+
dst = nil
962+
} else {
963+
dst = req.dstObject.attrs.toProtoObject("")
964+
}
965+
956966
call := &storagepb.RewriteObjectRequest{
957967
SourceBucket: bucketResourceName(globalProjectAlias, req.srcObject.bucket),
958968
SourceObject: req.srcObject.name,
959969
RewriteToken: req.token,
960970
DestinationBucket: bucketResourceName(globalProjectAlias, req.dstObject.bucket),
961971
DestinationName: req.dstObject.name,
962-
Destination: obj,
972+
Destination: dst,
963973
DestinationKmsKey: req.dstObject.keyName,
964974
DestinationPredefinedAcl: req.predefinedACL,
965975
CommonObjectRequestParams: toProtoCommonObjectRequestParams(req.dstObject.encryptionKey),

storage/integration_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2406,7 +2406,7 @@ func TestIntegration_Copy(t *testing.T) {
24062406
})
24072407

24082408
// Create new bucket
2409-
if err := bucketInDifferentRegion.Create(ctx, testutil.ProjID(), &BucketAttrs{Location: "NORTHAMERICA-NORTHEAST2"}); err != nil {
2409+
if err := bucketInDifferentRegion.Create(ctx, testutil.ProjID(), &BucketAttrs{Location: "US-EAST1"}); err != nil {
24102410
t.Fatalf("bucket.Create: %v", err)
24112411
}
24122412
t.Cleanup(func() {
@@ -2434,6 +2434,14 @@ func TestIntegration_Copy(t *testing.T) {
24342434
h.mustDeleteObject(obj)
24352435
})
24362436

2437+
// Set metadata on the source object to check if it's copied.
2438+
if _, err := obj.Update(ctx, ObjectAttrsToUpdate{
2439+
ContentLanguage: "en",
2440+
ContentDisposition: "inline",
2441+
}); err != nil {
2442+
t.Fatalf("obj.Update: %v", err)
2443+
}
2444+
24372445
attrs, err := obj.Attrs(ctx)
24382446
if err != nil {
24392447
t.Fatalf("obj.Attrs: %v", err)
@@ -2518,6 +2526,14 @@ func TestIntegration_Copy(t *testing.T) {
25182526
if attrs.ContentEncoding != test.copierAttrs.contentEncoding {
25192527
t.Errorf("unexpected ContentEncoding; got: %s, want: %s", attrs.ContentEncoding, test.copierAttrs.contentEncoding)
25202528
}
2529+
} else {
2530+
// Check that metadata is copied when no destination attributes are provided.
2531+
if attrs.ContentLanguage != "en" {
2532+
t.Errorf("unexpected ContentLanguage; got: %s, want: en", attrs.ContentLanguage)
2533+
}
2534+
if attrs.ContentDisposition != "inline" {
2535+
t.Errorf("unexpected ContentDisposition; got: %s, want: inline", attrs.ContentDisposition)
2536+
}
25212537
}
25222538

25232539
// Check the copied contents

storage/storage.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,6 +1672,12 @@ type ObjectAttrs struct {
16721672
HardDeleteTime time.Time
16731673
}
16741674

1675+
// isZero reports whether the ObjectAttrs struct is empty (i.e. all the
1676+
// fields are their zero value).
1677+
func (o *ObjectAttrs) isZero() bool {
1678+
return reflect.DeepEqual(o, &ObjectAttrs{})
1679+
}
1680+
16751681
// ObjectRetention contains the retention configuration for this object.
16761682
type ObjectRetention struct {
16771683
// Mode is the retention policy's mode on this object. Valid values are

0 commit comments

Comments
 (0)