diff --git a/.changes/next-release/bugfix-s3-09efbe2a.json b/.changes/next-release/bugfix-s3-09efbe2a.json
new file mode 100644
index 0000000000..7b770c0738
--- /dev/null
+++ b/.changes/next-release/bugfix-s3-09efbe2a.json
@@ -0,0 +1,5 @@
+{
+ "type": "bugfix",
+ "category": "s3",
+ "description": "update s3 status 200 error classification"
+}
\ No newline at end of file
diff --git a/lib/services/s3.js b/lib/services/s3.js
index 0d0b11bbdc..3773481474 100644
--- a/lib/services/s3.js
+++ b/lib/services/s3.js
@@ -531,17 +531,21 @@ AWS.util.update(AWS.S3.prototype, {
* @api private
*/
extractErrorFrom200Response: function extractErrorFrom200Response(resp) {
- if (!operationsWith200StatusCodeError[resp.request.operation]) return;
+ var service = this.service ? this.service : this;
+ if (!service.is200Error(resp) && !operationsWith200StatusCodeError[resp.request.operation]) {
+ return;
+ }
var httpResponse = resp.httpResponse;
- if (httpResponse.body && httpResponse.body.toString().match('')) {
+ var bodyString = httpResponse.body && httpResponse.body.toString() || '';
+ if (bodyString && bodyString.indexOf('') === bodyString.length - 8) {
// Response body with '...' indicates an exception.
// Get S3 client object. In ManagedUpload, this.service refers to
// S3 client object.
resp.data = null;
- var service = this.service ? this.service : this;
service.extractError(resp);
+ resp.error.is200Error = true;
throw resp.error;
- } else if (!httpResponse.body || !httpResponse.body.toString().match(/<[\w_]/)) {
+ } else if (!httpResponse.body || !bodyString.match(/<[\w_]/)) {
// When body is empty or incomplete, S3 might stop the request on detecting client
// side aborting the request.
resp.data = null;
@@ -552,13 +556,54 @@ AWS.util.update(AWS.S3.prototype, {
}
},
+ /**
+ * @api private
+ * @param resp - to evaluate.
+ * @return true if the response has status code 200 but is an error.
+ */
+ is200Error: function is200Error(resp) {
+ var code = resp && resp.httpResponse && resp.httpResponse.statusCode;
+ if (code !== 200) {
+ return false;
+ }
+ try {
+ var req = resp.request;
+ var outputMembers = req.service.api.operations[req.operation].output.members;
+ var keys = Object.keys(outputMembers);
+ for (var i = 0; i < keys.length; ++i) {
+ var member = outputMembers[keys[i]];
+ if (member.type === 'binary' && member.isStreaming) {
+ return false;
+ }
+ }
+
+ var body = resp.httpResponse.body;
+ if (body && body.byteLength !== undefined) {
+ if (body.byteLength < 15 || body.byteLength > 3000) {
+ // body is too short or long to be an error message.
+ return false;
+ }
+ }
+ if (!body) {
+ return false;
+ }
+ var bodyString = body.toString();
+ if (bodyString.indexOf('') === bodyString.length - 8) {
+ return true;
+ }
+ } catch (e) {
+ return false;
+ }
+ return false;
+ },
+
/**
* @return [Boolean] whether the error can be retried
* @api private
*/
retryableError: function retryableError(error, request) {
- if (operationsWith200StatusCodeError[request.operation] &&
- error.statusCode === 200) {
+ if (error.is200Error ||
+ (operationsWith200StatusCodeError[request.operation] && error.statusCode === 200)) {
return true;
} else if (request._requestRegionForBucket &&
request.service.bucketRegionCache[request._requestRegionForBucket]) {
diff --git a/scripts/region-checker/allowlist.js b/scripts/region-checker/allowlist.js
index b7d173bfb5..4b61e6a79d 100644
--- a/scripts/region-checker/allowlist.js
+++ b/scripts/region-checker/allowlist.js
@@ -44,13 +44,13 @@ var allowlist = {
263,
276,
282,
- 642,
- 644,
- 763,
- 774,
- 775,
- 776,
- 781
+ 687,
+ 689,
+ 808,
+ 819,
+ 820,
+ 821,
+ 826
],
'/token/sso_token_provider.js': [
60