diff --git a/.changes/next-release/bugfix-Endpoint-d580bc63.json b/.changes/next-release/bugfix-Endpoint-d580bc63.json new file mode 100644 index 0000000000..7efd719339 --- /dev/null +++ b/.changes/next-release/bugfix-Endpoint-d580bc63.json @@ -0,0 +1,5 @@ +{ + "type": "bugfix", + "category": "Endpoint", + "description": "fix bug in regional endpoints and add more tests" +} \ No newline at end of file diff --git a/features/s3/buckets.feature b/features/s3/buckets.feature index bf00bc0c53..d0fa695d0f 100644 --- a/features/s3/buckets.feature +++ b/features/s3/buckets.feature @@ -16,6 +16,14 @@ Feature: Working with Buckets When I delete the bucket Then the bucket should not exist + @us-east-1-regional-endpoint + Scenario: Support us-east-1 regional endpoint + Given I am using the S3 us-east-1 regional endpoint + When I create a bucket + Then the bucket should exist + When I delete the bucket + Then the bucket should not exist + @cors Scenario: Bucket CORS When I create a bucket diff --git a/features/s3/step_definitions/buckets.js b/features/s3/step_definitions/buckets.js index f97e8fcdd5..187deb4216 100644 --- a/features/s3/step_definitions/buckets.js +++ b/features/s3/step_definitions/buckets.js @@ -10,6 +10,11 @@ module.exports = function() { callback(); }); + this.Given(/^I am using the S3 us-east-1 regional endpoint$/, function(callback) { + this.s3 = new this.AWS.S3({region: 'us-east-1', s3UsEast1RegionalEndpoint: 'regional'}); + callback(); + }); + this.When(/^I create a bucket with the location constraint "([^"]*)"$/, function(location, callback) { var bucket = this.bucket = this.uniqueName('aws-sdk-js-integration'); var params = { diff --git a/features/sts/step_definitions/sts.js b/features/sts/step_definitions/sts.js index e0133b7ff1..1feaa557c7 100644 --- a/features/sts/step_definitions/sts.js +++ b/features/sts/step_definitions/sts.js @@ -8,6 +8,16 @@ module.exports = function() { this.request(null, 'getSessionToken', {DurationSeconds: parseInt(duration)}, callback, false); }); + this.Before('@sts-regional-endpoints', function(callback) { + this.service = new this.AWS.STS({region: 'us-east-1', stsRegionalEndpoints: 'regional'}); + callback(); + }); + + this.After('@sts-regional-endpoints', function(callback) { + this.service = new this.AWS.STS(); + callback(); + }) + this.Then(/^the result should contain an access key ID and secret access key$/, function(callback) { this.assert.compare(this.data.Credentials.AccessKeyId.length, '>', 0); this.assert.compare(this.data.Credentials.SecretAccessKey.length, '>', 0); diff --git a/features/sts/sts.feature b/features/sts/sts.feature index e30799c045..2d0d562690 100644 --- a/features/sts/sts.feature +++ b/features/sts/sts.feature @@ -12,3 +12,8 @@ Feature: AWS Security Token Service Scenario: Error handling Given I get an STS session token with a duration of 60 seconds Then the error code should be "ValidationError" + + @sts-regional-endpoints + Scenario: Get a session token from regional endpoint + Given I get an STS session token with a duration of 900 seconds + Then the result should contain an access key ID and secret access key diff --git a/lib/config.d.ts b/lib/config.d.ts index 780f50d008..2639720843 100644 --- a/lib/config.d.ts +++ b/lib/config.d.ts @@ -250,6 +250,18 @@ export abstract class ConfigurationOptions { * Whether to force path style URLs for S3 objects. */ s3ForcePathStyle?: boolean + /** + * when region is set to 'us-east-1', whether to send s3 request to global endpoints + * or 'us-east-1' regional endpoints. This config is only applicable to S3 client; + * Defaults to 'legacy' + */ + s3UsEast1RegionalEndpoint?: "regional"|"legacy" + /** + * whether to override the request region with the region inferred + * from requested resource's ARN. Only available for S3 buckets + * Defaults to `true` + */ + s3UseArnRegion?: boolean /** * Whether the signature to sign requests with (overriding the API configuration) is cached. */ diff --git a/lib/services/s3.js b/lib/services/s3.js index 99956422e4..69553e3c1c 100644 --- a/lib/services/s3.js +++ b/lib/services/s3.js @@ -375,9 +375,7 @@ AWS.util.update(AWS.S3.prototype, { var insertPoint = config.endpoint.indexOf('.amazonaws.com'); regionalEndpoint = config.endpoint.substring(0, insertPoint) + '.us-east-1' + config.endpoint.substring(insertPoint); - var endpoint = req.httpRequest.endpoint; - endpoint.hostname = regionalEndpoint; - endpoint.host = regionalEndpoint; + req.httpRequest.updateEndpoint(regionalEndpoint); } }, diff --git a/lib/services/sts.js b/lib/services/sts.js index 4a86294587..11abdb4318 100644 --- a/lib/services/sts.js +++ b/lib/services/sts.js @@ -76,11 +76,9 @@ AWS.util.update(AWS.STS.prototype, { {code: 'ConfigError', message: 'Missing region in config'}); } var insertPoint = config.endpoint.indexOf('.amazonaws.com'); - regionalEndpoint = config.endpoint.substring(0, insertPoint) + + var regionalEndpoint = config.endpoint.substring(0, insertPoint) + '.' + config.region + config.endpoint.substring(insertPoint); - var endpoint = req.httpRequest.endpoint; - endpoint.hostname = regionalEndpoint; - endpoint.host = regionalEndpoint; + req.httpRequest.updateEndpoint(regionalEndpoint); req.httpRequest.region = config.region; } } diff --git a/scripts/region-checker/whitelist.js b/scripts/region-checker/whitelist.js index ecfa4822f2..55c40ef9a3 100644 --- a/scripts/region-checker/whitelist.js +++ b/scripts/region-checker/whitelist.js @@ -36,12 +36,12 @@ var whitelist = { 370, 376, 748, - 750, - 869, + 746, + 867, 880, - 881, - 882, - 887 + 878, + 879, + 885 ] }; diff --git a/test/services/s3.spec.js b/test/services/s3.spec.js index a740227a58..9a9fe3a4cc 100644 --- a/test/services/s3.spec.js +++ b/test/services/s3.spec.js @@ -3319,18 +3319,18 @@ describe('AWS.S3', function() { it('according to config settings', function() { var s3 = new AWS.S3({region: 'us-west-2'}); var request = s3.listBuckets().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('s3.us-west-2.amazonaws.com'); + expect(request.httpRequest.endpoint.hostname).to.equal('s3.us-west-2.amazonaws.com'); s3 = new AWS.S3({region: 'us-east-1'}); var request = s3.listBuckets().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('s3.amazonaws.com'); + expect(request.httpRequest.endpoint.hostname).to.equal('s3.amazonaws.com'); s3 = new AWS.S3({region: 'us-east-1', s3UsEast1RegionalEndpoint: 'regional'}); request = s3.listBuckets().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('s3.us-east-1.amazonaws.com'); + expect(request.httpRequest.endpoint.hostname).to.equal('s3.us-east-1.amazonaws.com'); }); it('should use global endpoints for when config is set to legacy', function() { s3 = new AWS.S3({region: 'us-east-1', s3UsEast1RegionalEndpoint: 'legacy'}); request = s3.listBuckets().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('s3.amazonaws.com'); + expect(request.httpRequest.endpoint.hostname).to.equal('s3.amazonaws.com'); }); it('should not update endpoint if supplied a custom endpoint', function() { s3 = new AWS.S3({ @@ -3339,7 +3339,7 @@ describe('AWS.S3', function() { endpoint: 's3.amazonaws.com' }); request = s3.listBuckets().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('s3.amazonaws.com'); + expect(request.httpRequest.endpoint.hostname).to.equal('s3.amazonaws.com'); }); }); } diff --git a/test/services/sts.spec.js b/test/services/sts.spec.js index 3150d7ca12..77084066a1 100644 --- a/test/services/sts.spec.js +++ b/test/services/sts.spec.js @@ -253,33 +253,33 @@ for (var i = 0; i < regions.length; i++) { var sts = new AWS.STS({region: regions[i]}); var request = sts.getCallerIdentity().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('sts.amazonaws.com'); + expect(request.httpRequest.endpoint.hostname).to.equal('sts.amazonaws.com'); } var sts = new AWS.STS({region: 'cn-north-1'}); request = sts.getCallerIdentity().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('sts.cn-north-1.amazonaws.com.cn'); + expect(request.httpRequest.endpoint.hostname).to.equal('sts.cn-north-1.amazonaws.com.cn'); }); it('should use global endpoints for when config is set to legacy', function() { var regions = ['us-west-2', 'ap-east-1']; for (var i = 0; i < regions.length; i++) { var sts = new AWS.STS({region: regions[i], stsRegionalEndpoints: 'legacy'}); var request = sts.getCallerIdentity().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('sts.amazonaws.com'); + expect(request.httpRequest.endpoint.hostname).to.equal('sts.amazonaws.com'); } var sts = new AWS.STS({region: 'cn-north-1', stsRegionalEndpoints: 'legacy'}); request = sts.getCallerIdentity().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('sts.cn-north-1.amazonaws.com.cn'); + expect(request.httpRequest.endpoint.hostname).to.equal('sts.cn-north-1.amazonaws.com.cn'); }); it('should use regional endpoints for when config is set to regional', function() { var regions = ['us-west-2', 'ap-east-1']; for (var i = 0; i < regions.length; i++) { var sts = new AWS.STS({region: regions[i], stsRegionalEndpoints: 'regional'}); var request = sts.getCallerIdentity().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('sts.' + regions[i] + '.amazonaws.com'); + expect(request.httpRequest.endpoint.hostname).to.equal('sts.' + regions[i] + '.amazonaws.com'); } var sts = new AWS.STS({region: 'cn-north-1', stsRegionalEndpoints: 'regional'}); request = sts.getCallerIdentity().build(function() {}); - expect(request.httpRequest.endpoint.hostname).to.contain('sts.cn-north-1.amazonaws.com.cn'); + expect(request.httpRequest.endpoint.hostname).to.equal('sts.cn-north-1.amazonaws.com.cn'); }); it('should ask for region if stsRegionalEndpoints is set', function() { var error;