diff --git a/.changes/next-release/bugfix-S3-cba1d450.json b/.changes/next-release/bugfix-S3-cba1d450.json new file mode 100644 index 0000000000..df2d8a0a1a --- /dev/null +++ b/.changes/next-release/bugfix-S3-cba1d450.json @@ -0,0 +1,5 @@ +{ + "type": "bugfix", + "category": "S3", + "description": "Updates S3 client to no longer attempt to determine a bucket's region when a request is aborted." +} \ No newline at end of file diff --git a/lib/event_listeners.js b/lib/event_listeners.js index 4fb4e6448c..010a4366fe 100644 --- a/lib/event_listeners.js +++ b/lib/event_listeners.js @@ -282,12 +282,16 @@ AWS.EventListeners = { } function error(err) { - resp.error = AWS.util.error(err, { - code: 'NetworkingError', - region: resp.request.httpRequest.region, - hostname: resp.request.httpRequest.endpoint.hostname, - retryable: true - }); + if (err.code !== 'RequestAbortedError') { + var errCode = err.code === 'TimeoutError' ? err.code : 'NetworkingError'; + err = AWS.util.error(err, { + code: errCode, + region: resp.request.httpRequest.region, + hostname: resp.request.httpRequest.endpoint.hostname, + retryable: true + }); + } + resp.error = err; resp.request.emit('httpError', [resp.error, resp], function() { done(); }); diff --git a/lib/service.js b/lib/service.js index 67e1b7b83d..30fedcdf3a 100644 --- a/lib/service.js +++ b/lib/service.js @@ -354,6 +354,7 @@ AWS.Service = inherit({ * @api private */ retryableError: function retryableError(error) { + if (this.timeoutError(error)) return true; if (this.networkingError(error)) return true; if (this.expiredCredentialsError(error)) return true; if (this.throttledError(error)) return true; @@ -368,6 +369,13 @@ AWS.Service = inherit({ return error.code === 'NetworkingError'; }, + /** + * @api private + */ + timeoutError: function timeoutError(error) { + return error.code === 'TimeoutError'; + }, + /** * @api private */ diff --git a/test/browser.spec.js b/test/browser.spec.js index 9571e78e90..feb6f9c4c4 100644 --- a/test/browser.spec.js +++ b/test/browser.spec.js @@ -136,7 +136,7 @@ req.on('httpHeaders', function() { return this.abort(); }); - return req.send(function(err) { + req.send(function(err) { expect(err.name).to.equal('RequestAbortedError'); return done(); }); @@ -1125,8 +1125,56 @@ }); }); }); + + it('won\'t attempt to update bucket region if request is aborted', function(done) { + var req; + var s3Config = AWS.util.merge(config, config.s3); + s3Config.params = AWS.util.copy(s3Config.params); + s3Config.region = 'us-west-2'; + s3Config.params.Bucket += '-us-west-2'; + var s3 = new AWS.S3(s3Config); + req = s3.putObject({ + Key: 'key', + Body: 'body' + }); + req.on('httpHeaders', function() { + return this.abort(); + }); + var spy = helpers.spyOn(s3, 'updateReqBucketRegion').andCallThrough(); + req.send(function(err) { + expect(err.name).to.equal('RequestAbortedError'); + expect(spy.calls.length).to.equal(0); + return done(); + }); + }); + + it('won\'t attempt to update bucket region if request times out', function(done) { + var req; + var s3Config = AWS.util.merge(config, config.s3); + s3Config.params = AWS.util.copy(s3Config.params); + s3Config.httpOptions = { + timeout: 1 + }; + s3Config.region = 'us-west-2'; + s3Config.params.Bucket += '-us-west-2'; + var s3 = new AWS.S3(s3Config); + req = s3.putObject({ + Key: 'key', + Body: 'body' + }); + req.on('httpHeaders', function() { + throw AWS.util.error(new Error('TimeoutError'), {code: 'TimeoutError'}); + }); + var spy = helpers.spyOn(s3, 'updateReqBucketRegion').andCallThrough(); + req.send(function(err) { + expect(err.name).to.equal('TimeoutError'); + expect(spy.calls.length).to.equal(0); + return done(); + }); + }); + describe('upload()', function() { - return it('supports blobs using upload()', function(done) { + it('supports blobs using upload()', function(done) { var key, size, u; key = uniqueName('test'); size = 100; @@ -1134,7 +1182,7 @@ Key: key, Body: new Blob([new Uint8Array(size)]) }); - return u.send(function(err, data) { + u.send(function(err, data) { expect(err).not.to.exist; expect(typeof data.ETag).to.equal('string'); expect(typeof data.Location).to.equal('string');