Skip to content

Commit 32583a4

Browse files
authored
fix(GCS+gRPC): unused mutable Object fields (#8998)
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 99b7b1d commit 32583a4

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
@@ -84,6 +84,10 @@ For status on this, see https://github.com/googleapis/google-cloud-cpp/issues/88
8484

8585
## v1.41.0 - TBD
8686

87+
## v1.40.2 - 2022-05
88+
89+
* fix(GCS+gRPC): unused mutable Object fields ([#8998](https://github.com/googleapis/google-cloud-cpp/pull/8998))
90+
8791
## v1.40.1 - 2022-05
8892

8993
* fix: correct check for storage vs. rest enabled ([#8850](https://github.com/googleapis/google-cloud-cpp/pull/8850))

google/cloud/storage/internal/grpc_object_request_parser.cc

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

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

162167
StatusOr<google::storage::v2::ComposeObjectRequest>
@@ -182,6 +187,7 @@ GrpcObjectRequestParser::ToProto(ComposeObjectRequest const& request) {
182187
destination.set_cache_control(metadata.cache_control());
183188
destination.set_content_language(metadata.content_language());
184189
destination.set_content_type(metadata.content_type());
190+
destination.set_storage_class(metadata.storage_class());
185191
destination.set_temporary_hold(metadata.temporary_hold());
186192
destination.set_event_based_hold(metadata.event_based_hold());
187193
if (metadata.has_custom_time()) {
@@ -420,6 +426,7 @@ GrpcObjectRequestParser::ToProto(InsertObjectMediaRequest const& request) {
420426
SetResourceOptions(resource, request);
421427
auto status = SetObjectMetadata(resource, request);
422428
if (!status.ok()) return status;
429+
SetStorageClass(resource, request);
423430
SetPredefinedAcl(object_spec, request);
424431
SetGenerationConditions(object_spec, request);
425432
SetMetagenerationConditions(object_spec, request);
@@ -530,27 +537,9 @@ GrpcObjectRequestParser::ToProto(RewriteObjectRequest const& request) {
530537
auto& destination = *result.mutable_destination();
531538
destination.set_kms_key(
532539
request.GetOption<DestinationKmsKeyName>().value_or(""));
533-
// Only a few fields can be set as part of the metadata request.
534-
auto m = request.GetOption<WithObjectMetadata>().value();
535-
destination.set_storage_class(m.storage_class());
536-
destination.set_content_encoding(m.content_encoding());
537-
destination.set_content_disposition(m.content_disposition());
538-
destination.set_cache_control(m.cache_control());
539-
destination.set_content_language(m.content_language());
540-
destination.set_content_type(m.content_type());
541-
destination.set_temporary_hold(m.temporary_hold());
542-
for (auto const& kv : m.metadata()) {
543-
(*destination.mutable_metadata())[kv.first] = kv.second;
544-
}
545-
if (m.event_based_hold()) {
546-
// The proto is an optional<bool>, avoid setting it to `false`, seems
547-
// confusing.
548-
destination.set_event_based_hold(m.event_based_hold());
549-
}
550-
if (m.has_custom_time()) {
551-
*destination.mutable_custom_time() =
552-
google::cloud::internal::ToProtoTimestamp(m.custom_time());
553-
}
540+
status = SetObjectMetadata(destination, request);
541+
if (!status.ok()) return status;
542+
SetStorageClass(destination, request);
554543
}
555544
result.set_source_bucket("projects/_/buckets/" + request.source_bucket());
556545
result.set_source_object(request.source_object());
@@ -628,27 +617,9 @@ GrpcObjectRequestParser::ToProto(CopyObjectRequest const& request) {
628617
auto& destination = *result.mutable_destination();
629618
destination.set_kms_key(
630619
request.GetOption<DestinationKmsKeyName>().value_or(""));
631-
// Only a few fields can be set as part of the metadata request.
632-
auto m = request.GetOption<WithObjectMetadata>().value();
633-
destination.set_storage_class(m.storage_class());
634-
destination.set_content_encoding(m.content_encoding());
635-
destination.set_content_disposition(m.content_disposition());
636-
destination.set_cache_control(m.cache_control());
637-
destination.set_content_language(m.content_language());
638-
destination.set_content_type(m.content_type());
639-
destination.set_temporary_hold(m.temporary_hold());
640-
for (auto const& kv : m.metadata()) {
641-
(*destination.mutable_metadata())[kv.first] = kv.second;
642-
}
643-
if (m.event_based_hold()) {
644-
// The proto is an optional<bool>, avoid setting it to `false`, seems
645-
// confusing.
646-
destination.set_event_based_hold(m.event_based_hold());
647-
}
648-
if (m.has_custom_time()) {
649-
*destination.mutable_custom_time() =
650-
google::cloud::internal::ToProtoTimestamp(m.custom_time());
651-
}
620+
status = SetObjectMetadata(destination, request);
621+
if (!status.ok()) return status;
622+
SetStorageClass(destination, request);
652623
}
653624
result.set_source_bucket("projects/_/buckets/" + request.source_bucket());
654625
result.set_source_object(request.source_object());
@@ -703,6 +674,7 @@ GrpcObjectRequestParser::ToProto(ResumableUploadRequest const& request) {
703674
SetResourceOptions(resource, request);
704675
status = SetObjectMetadata(resource, request);
705676
if (!status.ok()) return status;
677+
SetStorageClass(resource, request);
706678
SetPredefinedAcl(object_spec, request);
707679
SetGenerationConditions(object_spec, request);
708680
SetMetagenerationConditions(object_spec, request);

0 commit comments

Comments
 (0)