Skip to content

Commit 608dd15

Browse files
authored
Use non-throwing JSON parser for ObjectMetadata. (#1745)
This is the last PR in the series to use the non-throwing version of nl::json::parse(). It fixes #1685.
1 parent b531139 commit 608dd15

15 files changed

Lines changed: 191 additions & 93 deletions

google/cloud/storage/client_object_copy_test.cc

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,8 @@ class ObjectCopyTest : public ::testing::Test {
6060
};
6161

6262
TEST_F(ObjectCopyTest, CopyObject) {
63-
std::string text = R"""({
64-
"name": "test-bucket-name/test-object-name/1"
65-
})""";
66-
auto expected = storage::ObjectMetadata::ParseFromString(text);
63+
std::string text = R"""({"name": "test-bucket-name/test-object-name/1"})""";
64+
auto expected = storage::ObjectMetadata::ParseFromString(text).value();
6765

6866
EXPECT_CALL(*mock, CopyObject(_))
6967
.WillOnce(Invoke([&expected](internal::CopyObjectRequest const& request) {
@@ -76,9 +74,9 @@ TEST_F(ObjectCopyTest, CopyObject) {
7674
Client client{std::shared_ptr<internal::RawClient>(mock),
7775
LimitedErrorCountRetryPolicy(2)};
7876

79-
ObjectMetadata actual = client.CopyObject(
80-
"source-bucket-name", "source-object-name", "test-bucket-name",
81-
"test-object-name");
77+
ObjectMetadata actual =
78+
client.CopyObject("source-bucket-name", "source-object-name",
79+
"test-bucket-name", "test-object-name");
8280
EXPECT_EQ(expected, actual);
8381
}
8482

@@ -130,8 +128,8 @@ TEST_F(ObjectCopyTest, ComposeObject) {
130128
"timeStorageClassUpdated": "2018-05-19T19:31:34Z",
131129
"updated": "2018-05-19T19:31:24Z",
132130
"componentCount": 2
133-
})""";
134-
auto expected = ObjectMetadata::ParseFromString(response);
131+
})""";
132+
auto expected = ObjectMetadata::ParseFromString(response).value();
135133

136134
EXPECT_CALL(*mock, ComposeObject(_))
137135
.WillOnce(Return(StatusOr<ObjectMetadata>(TransientError())))
@@ -149,9 +147,8 @@ TEST_F(ObjectCopyTest, ComposeObject) {
149147
Client client{std::shared_ptr<internal::RawClient>(mock),
150148
LimitedErrorCountRetryPolicy(2)};
151149

152-
auto actual =
153-
client.ComposeObject("test-bucket-name", {{"object1"}, {"object2"}},
154-
"test-object-name");
150+
auto actual = client.ComposeObject(
151+
"test-bucket-name", {{"object1"}, {"object2"}}, "test-object-name");
155152
EXPECT_EQ(expected, actual);
156153
}
157154

@@ -181,8 +178,8 @@ TEST_F(ObjectCopyTest, ComposeObjectPermanentFailure) {
181178

182179
TEST_F(ObjectCopyTest, RewriteObject) {
183180
EXPECT_CALL(*mock, RewriteObject(_))
184-
.WillOnce(Return(
185-
StatusOr<internal::RewriteObjectResponse>(TransientError())))
181+
.WillOnce(
182+
Return(StatusOr<internal::RewriteObjectResponse>(TransientError())))
186183
.WillOnce(Invoke([](internal::RewriteObjectRequest const& r) {
187184
EXPECT_EQ("test-source-bucket-name", r.source_bucket());
188185
EXPECT_EQ("test-source-object-name", r.source_object());
@@ -197,8 +194,8 @@ TEST_F(ObjectCopyTest, RewriteObject) {
197194
"done": false,
198195
"rewriteToken": "abcd-test-token-0"
199196
})""";
200-
return make_status_or(internal::RewriteObjectResponse::FromHttpResponse(
201-
internal::HttpResponse{200, response, {}}));
197+
return internal::RewriteObjectResponse::FromHttpResponse(
198+
internal::HttpResponse{200, response, {}});
202199
}))
203200
.WillOnce(Invoke([](internal::RewriteObjectRequest const& r) {
204201
EXPECT_EQ("test-source-bucket-name", r.source_bucket());
@@ -214,8 +211,8 @@ TEST_F(ObjectCopyTest, RewriteObject) {
214211
"done": false,
215212
"rewriteToken": "abcd-test-token-2"
216213
})""";
217-
return make_status_or(internal::RewriteObjectResponse::FromHttpResponse(
218-
internal::HttpResponse{200, response, {}}));
214+
return internal::RewriteObjectResponse::FromHttpResponse(
215+
internal::HttpResponse{200, response, {}});
219216
}))
220217
.WillOnce(Invoke([](internal::RewriteObjectRequest const& r) {
221218
EXPECT_EQ("test-source-bucket-name", r.source_bucket());
@@ -235,8 +232,8 @@ TEST_F(ObjectCopyTest, RewriteObject) {
235232
"name": "test-destination-object-name"
236233
}
237234
})""";
238-
return make_status_or(internal::RewriteObjectResponse::FromHttpResponse(
239-
internal::HttpResponse{200, response, {}}));
235+
return internal::RewriteObjectResponse::FromHttpResponse(
236+
internal::HttpResponse{200, response, {}});
240237
}));
241238
Client client{std::shared_ptr<internal::RawClient>(mock),
242239
LimitedErrorCountRetryPolicy(2)};
@@ -278,8 +275,7 @@ TEST_F(ObjectCopyTest, RewriteObjectTooManyFailures) {
278275
[](Client& client) {
279276
client.RewriteObjectBlocking(
280277
"test-source-bucket-name", "test-source-object",
281-
"test-dest-bucket-name", "test-dest-object",
282-
IfGenerationMatch(7));
278+
"test-dest-bucket-name", "test-dest-object", IfGenerationMatch(7));
283279
},
284280
"RewriteObject");
285281
}

google/cloud/storage/client_write_object_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ TEST_F(WriteObjectTest, WriteObject) {
7171
std::string text = R"""({
7272
"name": "test-bucket-name/test-object-name/1"
7373
})""";
74-
auto expected = ObjectMetadata::ParseFromString(text);
74+
auto expected = ObjectMetadata::ParseFromString(text).value();
7575

7676
EXPECT_CALL(*mock, WriteObject(_))
7777
.WillOnce(Invoke(

google/cloud/storage/internal/curl_client.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,14 +215,17 @@ CurlClient::CreateResumableSessionGeneric(RequestType const& request) {
215215
}
216216
auto response =
217217
ResumableUploadResponse::FromHttpResponse(*std::move(http_response));
218-
if (response.upload_session_url.empty()) {
218+
if (not response.ok()) {
219+
return std::move(response).status();
220+
}
221+
if (response->upload_session_url.empty()) {
219222
std::ostringstream os;
220-
os << __func__ << " - invalid server response, parsed to " << response;
223+
os << __func__ << " - invalid server response, parsed to " << *response;
221224
return Status(StatusCode::INTERNAL, std::move(os).str());
222225
}
223226
return std::unique_ptr<ResumableUploadSession>(
224227
google::cloud::internal::make_unique<CurlResumableUploadSession>(
225-
shared_from_this(), std::move(response.upload_session_url)));
228+
shared_from_this(), std::move(response->upload_session_url)));
226229
}
227230

228231
CurlClient::CurlClient(ClientOptions options)

google/cloud/storage/internal/hash_validator_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ TEST(CompositeHashValidator, ProcessMetadata) {
259259
auto object_metadata = ObjectMetadata::ParseFromJson(internal::nl::json{
260260
{"crc32c", QUICK_FOX_CRC32C_CHECKSUM},
261261
{"md5Hash", QUICK_FOX_MD5_HASH},
262-
});
262+
}).value();
263263
validator.ProcessMetadata(object_metadata);
264264
auto result = std::move(validator).Finish();
265265
EXPECT_EQ(

google/cloud/storage/internal/logging_client_test.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ TEST_F(LoggingClientTest, InsertObjectMedia) {
119119

120120
auto mock = std::make_shared<testing::MockClient>();
121121
EXPECT_CALL(*mock, InsertObjectMedia(_))
122-
.WillOnce(Return(ObjectMetadata::ParseFromString(text)));
122+
.WillOnce(Return(ObjectMetadata::ParseFromString(text).value()));
123123

124124
// We want to test that the key elements are logged, but do not want a
125125
// "change detection test", so this is intentionally not exhaustive.
@@ -145,8 +145,10 @@ TEST_F(LoggingClientTest, InsertObjectMedia) {
145145

146146
TEST_F(LoggingClientTest, ListObjects) {
147147
std::vector<ObjectMetadata> items = {
148-
ObjectMetadata::ParseFromString(R""({"name": "response-object-o1"})""),
149-
ObjectMetadata::ParseFromString(R""({"name": "response-object-o2"})""),
148+
ObjectMetadata::ParseFromString(R""({"name": "response-object-o1"})"")
149+
.value(),
150+
ObjectMetadata::ParseFromString(R""({"name": "response-object-o2"})"")
151+
.value(),
150152
};
151153
auto mock = std::make_shared<testing::MockClient>();
152154
EXPECT_CALL(*mock, ListObjects(_))

google/cloud/storage/internal/object_requests.cc

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,23 @@ std::ostream& operator<<(std::ostream& os, ListObjectsRequest const& r) {
3030
return os << "}";
3131
}
3232

33-
ListObjectsResponse ListObjectsResponse::FromHttpResponse(
33+
StatusOr<ListObjectsResponse> ListObjectsResponse::FromHttpResponse(
3434
HttpResponse&& response) {
35-
auto json = storage::internal::nl::json::parse(response.payload);
35+
auto json =
36+
storage::internal::nl::json::parse(response.payload, nullptr, false);
37+
if (not json.is_object()) {
38+
return Status(StatusCode::INVALID_ARGUMENT, __func__);
39+
}
3640

3741
ListObjectsResponse result;
3842
result.next_page_token = json.value("nextPageToken", "");
3943

4044
for (auto const& kv : json["items"].items()) {
41-
result.items.emplace_back(ObjectMetadata::ParseFromJson(kv.value()));
45+
auto parsed = ObjectMetadata::ParseFromJson(kv.value());
46+
if (not parsed.ok()) {
47+
return std::move(parsed).status();
48+
}
49+
result.items.emplace_back(std::move(*parsed));
4250
}
4351

4452
return result;
@@ -170,20 +178,20 @@ std::ostream& operator<<(std::ostream& os, UpdateObjectRequest const& r) {
170178
}
171179

172180
ComposeObjectRequest::ComposeObjectRequest(
173-
std::string bucket_name,
174-
std::vector<ComposeSourceObject> source_objects,
181+
std::string bucket_name, std::vector<ComposeSourceObject> source_objects,
175182
std::string destination_object_name)
176183
: GenericObjectRequest(std::move(bucket_name),
177184
std::move(destination_object_name)),
178-
source_objects_(std::move(source_objects)) {}
185+
source_objects_(std::move(source_objects)) {}
179186

180187
std::string ComposeObjectRequest::JsonPayload() const {
181188
using internal::nl::json;
182189
json compose_object_payload_json;
183190
compose_object_payload_json["kind"] = "storage#composeRequest";
184191
json destination_metadata_payload;
185192
if (HasOption<WithObjectMetadata>()) {
186-
destination_metadata_payload = GetOption<WithObjectMetadata>().value().JsonPayloadForCompose();
193+
destination_metadata_payload =
194+
GetOption<WithObjectMetadata>().value().JsonPayloadForCompose();
187195
}
188196
if (!destination_metadata_payload.is_null()) {
189197
compose_object_payload_json["destination"] = destination_metadata_payload;
@@ -305,17 +313,25 @@ std::ostream& operator<<(std::ostream& os, RewriteObjectRequest const& r) {
305313
return os << "}";
306314
}
307315

308-
RewriteObjectResponse RewriteObjectResponse::FromHttpResponse(
316+
StatusOr<RewriteObjectResponse> RewriteObjectResponse::FromHttpResponse(
309317
HttpResponse const& response) {
310-
nl::json object = nl::json::parse(response.payload);
318+
nl::json object = nl::json::parse(response.payload, nullptr, false);
319+
if (not object.is_object()) {
320+
return Status(StatusCode::INVALID_ARGUMENT, __func__);
321+
}
322+
311323
RewriteObjectResponse result;
312324
result.total_bytes_rewritten =
313325
ParseUnsignedLongField(object, "totalBytesRewritten");
314326
result.object_size = ParseUnsignedLongField(object, "objectSize");
315327
result.done = object.value("done", false);
316328
result.rewrite_token = object.value("rewriteToken", "");
317329
if (object.count("resource") != 0U) {
318-
result.resource = ObjectMetadata::ParseFromJson(object["resource"]);
330+
auto parsed = ObjectMetadata::ParseFromJson(object["resource"]);
331+
if (not parsed.ok()) {
332+
return std::move(parsed).status();
333+
}
334+
result.resource = std::move(*parsed);
319335
}
320336
return result;
321337
}
@@ -373,7 +389,7 @@ std::ostream& operator<<(std::ostream& os,
373389
return os << "}";
374390
}
375391

376-
ResumableUploadResponse ResumableUploadResponse::FromHttpResponse(
392+
StatusOr<ResumableUploadResponse> ResumableUploadResponse::FromHttpResponse(
377393
HttpResponse&& response) {
378394
ResumableUploadResponse result;
379395
result.last_committed_byte = 0;

google/cloud/storage/internal/object_requests.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ class ListObjectsRequest
5353
std::ostream& operator<<(std::ostream& os, ListObjectsRequest const& r);
5454

5555
struct ListObjectsResponse {
56-
static ListObjectsResponse FromHttpResponse(HttpResponse&& response);
56+
static StatusOr<ListObjectsResponse> FromHttpResponse(
57+
HttpResponse&& response);
5758

5859
std::string next_page_token;
5960
std::vector<ObjectMetadata> items;
@@ -344,7 +345,8 @@ std::ostream& operator<<(std::ostream& os, RewriteObjectRequest const& r);
344345

345346
/// Holds an `Objects: rewrite` response.
346347
struct RewriteObjectResponse {
347-
static RewriteObjectResponse FromHttpResponse(HttpResponse const& response);
348+
static StatusOr<RewriteObjectResponse> FromHttpResponse(
349+
HttpResponse const& response);
348350

349351
std::uint64_t total_bytes_rewritten;
350352
std::uint64_t object_size;
@@ -447,7 +449,8 @@ std::ostream& operator<<(std::ostream& os,
447449
QueryResumableUploadRequest const& r);
448450

449451
struct ResumableUploadResponse {
450-
static ResumableUploadResponse FromHttpResponse(HttpResponse&& response);
452+
static StatusOr<ResumableUploadResponse> FromHttpResponse(
453+
HttpResponse&& response);
451454

452455
std::string upload_session_url;
453456
std::uint64_t last_committed_byte;

0 commit comments

Comments
 (0)