Skip to content

Commit e2be8c1

Browse files
authored
Harden parseErrorCodeFromS3 to never throw on non-XML responses (#13021)
* Harden parseErrorCodeFromS3 to never throw on non-XML responses 7.3 (#12997) - 7.3 * Harden parseErrorCodeFromS3 to never throw on non-XML responses (#12986) - main Add parseErrorCodeFromS3 function that safely extracts S3 error codes from XML responses, returning "" instead of throwing on parse failures since many HTTP error responses (502/503 HTML pages, empty bodies) are not XML. Wire it into doRequest_impl error handling to log S3ErrorCode and detect bad requests. Add unit tests. (cherry picked from commit 7388f54) * Log all S3 4xx client errors, not just 400 Widen the S3 error logging from only HTTP 400 to all 4xx client errors (403, 404, 409, etc). Remove unused badRequestCode variable. Rename trace event from S3BlobStoreBadRequest to S3BlobStoreClientError. * Fix trace * Simplify S3BlobStore request error handling (merge PR #13001) * Remove separate S3BlobStoreClientError event, use existing event
1 parent 0ec3117 commit e2be8c1

1 file changed

Lines changed: 28 additions & 31 deletions

File tree

fdbclient/S3BlobStore.actor.cpp

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,21 +1210,24 @@ ACTOR Future<Reference<HTTP::IncomingResponse>> doRequest_impl(Reference<S3BlobS
12101210

12111211
// If err is not present then r is valid.
12121212
// If r->code is in successCodes then record the successful request and return r.
1213-
if (!err.present() && successCodes.count(r->code) != 0) {
1214-
TraceEvent(SevDebug, "S3BlobStoreDoRequestSuccessful")
1215-
.detail("Verb", verb)
1216-
.detail("Error", err.present())
1217-
.detail("ErrorString", err.present() ? err.get().name() : "")
1218-
.detail("Resource", resource)
1219-
.detail("ResponseCode", r->code)
1220-
.detail("ResponseContentSize", r->data.content.size())
1221-
.log();
1222-
bstore->s_stats.requests_successful++;
1223-
++bstore->blobStats->requestsSuccessful;
1224-
return r;
1213+
if (!err.present()) {
1214+
ASSERT(r);
1215+
if (successCodes.count(r->code) != 0) {
1216+
TraceEvent(SevDebug, "S3BlobStoreDoRequestSuccessful")
1217+
.detail("Verb", verb)
1218+
.detail("Error", err.present())
1219+
.detail("ErrorString", err.present() ? err.get().name() : "")
1220+
.detail("Resource", resource)
1221+
.detail("ResponseCode", r->code)
1222+
.detail("ResponseContentSize", r->data.content.size())
1223+
.log();
1224+
bstore->s_stats.requests_successful++;
1225+
++bstore->blobStats->requestsSuccessful;
1226+
return r;
1227+
}
12251228
}
12261229

1227-
// Otherwise, this request is considered failed. Update failure count.
1230+
// This request is considered failed. Update failure count.
12281231
bstore->s_stats.requests_failed++;
12291232
++bstore->blobStats->requestsFailed;
12301233

@@ -1241,32 +1244,16 @@ ACTOR Future<Reference<HTTP::IncomingResponse>> doRequest_impl(Reference<S3BlobS
12411244
retryable ? (fastRetry ? "S3BlobStoreEndpointRequestFailedFastRetryable"
12421245
: "S3BlobStoreEndpointRequestFailedRetryable")
12431246
: "S3BlobStoreEndpointRequestFailed");
1247+
event.suppressFor(1);
12441248

12451249
bool connectionFailed = false;
1246-
// Attach err to trace event if present, otherwise extract some stuff from the response
1250+
12471251
if (err.present()) {
12481252
event.errorUnsuppressed(err.get());
12491253
if (err.get().code() == error_code_connection_failed) {
12501254
connectionFailed = true;
12511255
}
12521256
}
1253-
event.suppressFor(60);
1254-
1255-
if (!err.present()) {
1256-
event.detail("ResponseCode", r->code);
1257-
std::string s3Error = parseErrorCodeFromS3(r->data.content);
1258-
event.detail("S3ErrorCode", s3Error);
1259-
if (r->code == badRequestCode) {
1260-
if (isS3TokenError(s3Error) || simulateS3TokenError) {
1261-
s3TokenError = true;
1262-
}
1263-
TraceEvent(SevWarnAlways, "S3BlobStoreBadRequest")
1264-
.detail("HttpCode", r->code)
1265-
.detail("HttpResponseContent", r->data.content)
1266-
.detail("S3Error", s3Error)
1267-
.log();
1268-
}
1269-
}
12701257

12711258
event.detail("ConnectionEstablished", connectionEstablished);
12721259
event.detail("ReusingConn", reusingConn);
@@ -1281,6 +1268,16 @@ ACTOR Future<Reference<HTTP::IncomingResponse>> doRequest_impl(Reference<S3BlobS
12811268
else
12821269
event.detail("RemoteHost", bstore->host);
12831270

1271+
if (r) {
1272+
event.detail("ResponseCode", r->code);
1273+
event.detail("HttpResponseContent", r->data.content);
1274+
std::string s3Error = parseErrorCodeFromS3(r->data.content);
1275+
event.detail("S3ErrorCode", s3Error);
1276+
if (r->code == badRequestCode && (isS3TokenError(s3Error) || simulateS3TokenError)) {
1277+
s3TokenError = true;
1278+
}
1279+
}
1280+
12841281
event.detail("Verb", verb)
12851282
.detail("Resource", resource)
12861283
.detail("ThisTry", thisTry)

0 commit comments

Comments
 (0)