Skip to content

Commit 39e7905

Browse files
authored
fix(GCS+gRPC): unused mutable Object fields (#8997)
A few fields in the `WithObjectMetadata()` option were not used. Notably `custom_time()` and `acl()`. I changed the unit test to make it easier to inspect that all fields are tested, the expectation is created via `ExpectedFullObjectMetadata()`. A few fields are complicated, because they only setable in requests that create new objects. To fix the problem I refactored the code to copy mutable fields from the `storage::*Request` classes to the `google.storage.v2.Object` proto.
1 parent d2f74ae commit 39e7905

File tree

4 files changed

+328
-481
lines changed

4 files changed

+328
-481
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ https://github.com/googleapis/google-cloud-cpp/issues/8234.
5555

5656
## v1.40.0 - TBD
5757

58+
## v1.39.2 - 2022-05
59+
60+
* fix(GCS+gRPC): unused mutable Object fields ([#8997](https://github.com/googleapis/google-cloud-cpp/pull/8997))
61+
5862
## v1.39.1 - 2022-04
5963

6064
* Update Bazel builds, CI builds, and packaging instructions to use grpc-1.45.2

google/cloud/storage/internal/grpc_object_request_parser.cc

Lines changed: 28 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -137,28 +137,33 @@ Status SetObjectMetadata(google::storage::v2::Object& resource,
137137
if (!metadata.content_type().empty()) {
138138
resource.set_content_type(metadata.content_type());
139139
}
140-
if (metadata.event_based_hold()) {
141-
resource.set_event_based_hold(metadata.event_based_hold());
142-
}
143-
140+
resource.set_temporary_hold(metadata.temporary_hold());
144141
for (auto const& kv : metadata.metadata()) {
145142
(*resource.mutable_metadata())[kv.first] = kv.second;
146143
}
147-
148-
if (!metadata.storage_class().empty()) {
149-
resource.set_storage_class(metadata.storage_class());
144+
if (metadata.event_based_hold()) {
145+
resource.set_event_based_hold(metadata.event_based_hold());
150146
}
151-
resource.set_temporary_hold(metadata.temporary_hold());
152-
153-
if (metadata.has_customer_encryption()) {
154-
auto encryption =
155-
GrpcObjectMetadataParser::ToProto(metadata.customer_encryption());
156-
if (!encryption) return std::move(encryption).status();
157-
*resource.mutable_customer_encryption() = *std::move(encryption);
147+
// The customer_encryption field is never set via the object resource, gRPC
148+
// defines a separate message (`CommonObjectRequestParams`) and field in each
149+
// request to include the encryption info.
150+
// *resource.mutable_customer_encryption() = ...;
151+
if (metadata.has_custom_time()) {
152+
*resource.mutable_custom_time() =
153+
google::cloud::internal::ToProtoTimestamp(metadata.custom_time());
158154
}
159155
return Status{};
160156
}
161157

158+
// Only a few requests can set the storage class of the destination Object.
159+
template <typename StorageRequest>
160+
void SetStorageClass(google::storage::v2::Object& resource,
161+
StorageRequest const& req) {
162+
if (!req.template HasOption<WithObjectMetadata>()) return;
163+
auto metadata = req.template GetOption<WithObjectMetadata>().value();
164+
resource.set_storage_class(metadata.storage_class());
165+
}
166+
162167
} // namespace
163168

164169
StatusOr<google::storage::v2::ComposeObjectRequest>
@@ -184,6 +189,7 @@ GrpcObjectRequestParser::ToProto(ComposeObjectRequest const& request) {
184189
destination.set_cache_control(metadata.cache_control());
185190
destination.set_content_language(metadata.content_language());
186191
destination.set_content_type(metadata.content_type());
192+
destination.set_storage_class(metadata.storage_class());
187193
destination.set_temporary_hold(metadata.temporary_hold());
188194
destination.set_event_based_hold(metadata.event_based_hold());
189195
if (metadata.has_custom_time()) {
@@ -423,6 +429,7 @@ GrpcObjectRequestParser::ToProto(InsertObjectMediaRequest const& request) {
423429
SetResourceOptions(resource, request);
424430
auto status = SetObjectMetadata(resource, request);
425431
if (!status.ok()) return status;
432+
SetStorageClass(resource, request);
426433
SetPredefinedAcl(object_spec, request);
427434
SetGenerationConditions(object_spec, request);
428435
SetMetagenerationConditions(object_spec, request);
@@ -535,27 +542,9 @@ GrpcObjectRequestParser::ToProto(RewriteObjectRequest const& request) {
535542
auto& destination = *result.mutable_destination();
536543
destination.set_kms_key(
537544
request.GetOption<DestinationKmsKeyName>().value_or(""));
538-
// Only a few fields can be set as part of the metadata request.
539-
auto m = request.GetOption<WithObjectMetadata>().value();
540-
destination.set_storage_class(m.storage_class());
541-
destination.set_content_encoding(m.content_encoding());
542-
destination.set_content_disposition(m.content_disposition());
543-
destination.set_cache_control(m.cache_control());
544-
destination.set_content_language(m.content_language());
545-
destination.set_content_type(m.content_type());
546-
destination.set_temporary_hold(m.temporary_hold());
547-
for (auto const& kv : m.metadata()) {
548-
(*destination.mutable_metadata())[kv.first] = kv.second;
549-
}
550-
if (m.event_based_hold()) {
551-
// The proto is an optional<bool>, avoid setting it to `false`, seems
552-
// confusing.
553-
destination.set_event_based_hold(m.event_based_hold());
554-
}
555-
if (m.has_custom_time()) {
556-
*destination.mutable_custom_time() =
557-
google::cloud::internal::ToProtoTimestamp(m.custom_time());
558-
}
545+
status = SetObjectMetadata(destination, request);
546+
if (!status.ok()) return status;
547+
SetStorageClass(destination, request);
559548
}
560549
result.set_source_bucket("projects/_/buckets/" + request.source_bucket());
561550
result.set_source_object(request.source_object());
@@ -634,27 +623,9 @@ GrpcObjectRequestParser::ToProto(CopyObjectRequest const& request) {
634623
auto& destination = *result.mutable_destination();
635624
destination.set_kms_key(
636625
request.GetOption<DestinationKmsKeyName>().value_or(""));
637-
// Only a few fields can be set as part of the metadata request.
638-
auto m = request.GetOption<WithObjectMetadata>().value();
639-
destination.set_storage_class(m.storage_class());
640-
destination.set_content_encoding(m.content_encoding());
641-
destination.set_content_disposition(m.content_disposition());
642-
destination.set_cache_control(m.cache_control());
643-
destination.set_content_language(m.content_language());
644-
destination.set_content_type(m.content_type());
645-
destination.set_temporary_hold(m.temporary_hold());
646-
for (auto const& kv : m.metadata()) {
647-
(*destination.mutable_metadata())[kv.first] = kv.second;
648-
}
649-
if (m.event_based_hold()) {
650-
// The proto is an optional<bool>, avoid setting it to `false`, seems
651-
// confusing.
652-
destination.set_event_based_hold(m.event_based_hold());
653-
}
654-
if (m.has_custom_time()) {
655-
*destination.mutable_custom_time() =
656-
google::cloud::internal::ToProtoTimestamp(m.custom_time());
657-
}
626+
status = SetObjectMetadata(destination, request);
627+
if (!status.ok()) return status;
628+
SetStorageClass(destination, request);
658629
}
659630
result.set_source_bucket("projects/_/buckets/" + request.source_bucket());
660631
result.set_source_object(request.source_object());
@@ -710,6 +681,7 @@ GrpcObjectRequestParser::ToProto(ResumableUploadRequest const& request) {
710681
SetResourceOptions(resource, request);
711682
status = SetObjectMetadata(resource, request);
712683
if (!status.ok()) return status;
684+
SetStorageClass(resource, request);
713685
SetPredefinedAcl(object_spec, request);
714686
SetGenerationConditions(object_spec, request);
715687
SetMetagenerationConditions(object_spec, request);

0 commit comments

Comments
 (0)