Skip to content

Commit d5b0ca2

Browse files
committed
fix(storage): correctly merge options and handle MD5 for appendable uploads
1 parent a7707bf commit d5b0ca2

3 files changed

Lines changed: 15 additions & 20 deletions

File tree

google/cloud/storage/examples/storage_async_samples.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ void CreateAndWriteAppendableObjectWithChecksum(
750750

751751
// Set the expected CRC32C checksum in the current options scope
752752
// just before calling Finalize().
753+
// Note: 548262564U is the pre-computed CRC32C checksum for the string "Some data\n".
754+
// If the data changes, this checksum must be updated to match.
753755
google::cloud::internal::OptionsSpan span(
754756
google::cloud::Options{}.set<gcs::UseCrc32cValueOption>(548262564U));
755757
co_return (co_await writer.Finalize(std::move(token))).value();

google/cloud/storage/internal/async/writer_connection_impl.cc

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -144,37 +144,30 @@ AsyncWriterConnectionImpl::Finalize(storage::WritePayload payload) {
144144
auto is_append = request_.has_append_object_spec() ||
145145
request_.write_object_spec().appendable();
146146
auto current_options = google::cloud::internal::CurrentOptions();
147-
147+
auto merged = google::cloud::internal::MergeOptions(
148+
current_options, options_ ? *options_ : google::cloud::Options{});
149+
148150
// Default to letting the internal hash function compute and send the checksum.
149151
auto action = PartialUpload::kFinalizeWithChecksum;
150152

151-
if (current_options.has<google::cloud::storage::UseCrc32cValueOption>()) {
152-
// The user provided a final CRC via OptionsSpan. We manually inject it into the
153-
// request. We use `kFinalize` so the internal hash function doesn't overwrite it.
154-
write.mutable_object_checksums()->set_crc32c(
155-
current_options.get<google::cloud::storage::UseCrc32cValueOption>());
156-
action = PartialUpload::kFinalize;
157-
} else if (current_options.has<google::cloud::storage::UseMD5ValueOption>()) {
158-
auto as_proto = storage_internal::MD5ToProto(
159-
current_options.get<google::cloud::storage::UseMD5ValueOption>());
160-
if (as_proto) {
161-
write.mutable_object_checksums()->set_md5_hash(*as_proto);
162-
action = PartialUpload::kFinalize;
163-
}
164-
} else if (is_append) {
165-
if (options_->has<google::cloud::storage::UseCrc32cValueOption>()) {
153+
if (is_append || current_options.has<google::cloud::storage::UseCrc32cValueOption>() ||
154+
current_options.has<google::cloud::storage::UseMD5ValueOption>()) {
155+
if (merged.has<google::cloud::storage::UseCrc32cValueOption>()) {
166156
write.mutable_object_checksums()->set_crc32c(
167-
options_->get<google::cloud::storage::UseCrc32cValueOption>());
168-
} else if (options_->has<google::cloud::storage::UseMD5ValueOption>()) {
157+
merged.get<google::cloud::storage::UseCrc32cValueOption>());
158+
}
159+
if (merged.has<google::cloud::storage::UseMD5ValueOption>()) {
169160
auto as_proto = storage_internal::MD5ToProto(
170-
options_->get<google::cloud::storage::UseMD5ValueOption>());
161+
merged.get<google::cloud::storage::UseMD5ValueOption>());
171162
if (as_proto) {
172163
write.mutable_object_checksums()->set_md5_hash(*as_proto);
173164
}
174165
}
175166
// For appendable uploads, the internal hash function only sees the chunks uploaded
176167
// in this stream, not the full object. We use `kFinalize` to avoid sending this
177168
// partial hash, which would otherwise fail validation.
169+
// If the user specified a manual expected checksum in `current_options`, we must
170+
// also use `kFinalize` so the internal hash function doesn't overwrite it.
178171
action = PartialUpload::kFinalize;
179172
}
180173

google/cloud/storage/internal/async/writer_connection_impl_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ TEST(AsyncWriterConnectionTest, FinalizeAppendableWithExpectedChecksum) {
758758
"test-only-algo");
759759
EXPECT_TRUE(request.has_object_checksums());
760760
EXPECT_EQ(request.object_checksums().crc32c(),
761-
123456); // wait, it might be an int in proto
761+
123456);
762762
return sequencer.PushBack("Write");
763763
});
764764
EXPECT_CALL(*mock, Read).WillOnce([&]() {

0 commit comments

Comments
 (0)