aws-sdk 2.0.1 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +20 -0
- package/.gitignore +10 -0
- package/.travis.yml +20 -0
- package/.yardopts +20 -0
- package/.yardopts_guide +21 -0
- package/Gemfile +16 -0
- package/Gemfile.lock +34 -0
- package/README.md +5 -6
- package/Rakefile +14 -0
- package/UPGRADING.md +9 -4
- package/configuration.sample +5 -0
- package/dist/BUNDLE_LICENSE.txt +96 -0
- package/dist/aws-sdk.js +9594 -0
- package/dist/aws-sdk.min.js +21 -0
- package/dist-tools/.eslintrc +10 -0
- package/dist-tools/browser-builder.js +142 -0
- package/dist-tools/strategies/cache.js +68 -0
- package/dist-tools/strategies/default.js +165 -0
- package/dist-tools/test/browser-builder.mocha.spec.coffee +182 -0
- package/dist-tools/test/helpers.coffee +16 -0
- package/doc-src/guide/browser-building.md +93 -0
- package/doc-src/guide/browser-configuring-wif.md +287 -0
- package/doc-src/guide/browser-configuring.md +218 -0
- package/doc-src/guide/browser-examples.md +220 -0
- package/doc-src/guide/browser-intro.md +46 -0
- package/doc-src/guide/browser-making-requests.md +279 -0
- package/doc-src/guide/browser-services.md +75 -0
- package/doc-src/guide/index.md +41 -0
- package/doc-src/guide/node-configuring.md +272 -0
- package/doc-src/guide/node-examples.md +341 -0
- package/doc-src/guide/node-intro.md +32 -0
- package/doc-src/guide/node-making-requests.md +309 -0
- package/doc-src/guide/node-services.md +159 -0
- package/doc-src/templates/api-versions/model_documentor.rb +366 -0
- package/doc-src/templates/api-versions/plugin.rb +230 -0
- package/doc-src/templates/api-versions/templates/default/class/html/setup.rb +9 -0
- package/doc-src/templates/api-versions/templates/default/class/html/waiter_details_list.erb +7 -0
- package/doc-src/templates/api-versions/templates/default/class/html/waiter_summary.erb +7 -0
- package/doc-src/templates/api-versions/templates/default/docstring/html/experimental.erb +4 -0
- package/doc-src/templates/api-versions/templates/default/docstring/setup.rb +9 -0
- package/doc-src/templates/api-versions/templates/default/fulldoc/html/css/common.css +6 -0
- package/doc-src/templates/api-versions/templates/default/fulldoc/html/setup.rb +62 -0
- package/doc-src/templates/api-versions/templates/default/layout/html/services.erb +10 -0
- package/doc-src/templates/api-versions/templates/default/layout/html/setup.rb +28 -0
- package/doc-src/templates/api-versions/templates/default/module/html/box_info.erb +45 -0
- package/doc-src/templates/api-versions/templates/default/module/html/children.erb +8 -0
- package/doc-src/templates/api-versions/templates/default/tags/setup.rb +3 -0
- package/doc-src/templates/api-versions/templates/default/waiter_details/html/method_signature.erb +3 -0
- package/doc-src/templates/api-versions/templates/default/waiter_details/html/setup.rb +5 -0
- package/doc-src/templates/default/layout/html/footer.erb +31 -0
- package/doc-src/templates/default/layout/html/layout.erb +23 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/css/highlight.github.css +127 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/css/style.css +1192 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/img/logo.png +0 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/app.js +33 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/highlight.pack.js +27 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/AUTHORS +55 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/LICENSE +25 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/doctools.js +247 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/file.png +0 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/sphinx/searchtools.js +568 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/js/underscore.js +23 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/search.erb +29 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/search_index.erb +1 -0
- package/doc-src/templates/flasky_sphinx_guide/fulldoc/html/setup.rb +75 -0
- package/doc-src/templates/flasky_sphinx_guide/layout/html/layout.erb +93 -0
- package/doc-src/templates/flasky_sphinx_guide/layout/html/setup.rb +9 -0
- package/doc-src/templates/flasky_sphinx_guide/layout/html/sidebar.erb +45 -0
- package/doc-src/templates/flasky_sphinx_guide/onefile/html/layout.erb +51 -0
- package/doc-src/templates/flasky_sphinx_guide/onefile/html/setup.rb +1 -0
- package/eslint-rules/no-require-in-service.js +10 -0
- package/features/autoscaling/autoscaling.feature +21 -0
- package/features/autoscaling/step_definitions/autoscaling.js +49 -0
- package/features/cloudformation/cloudformation.feature +22 -0
- package/features/cloudformation/step_definitions/cloudformation.js +26 -0
- package/features/cloudfront/cloudfront.feature +28 -0
- package/features/cloudfront/step_definitions/cloudfront-latest.js +54 -0
- package/features/cloudfront/step_definitions/cloudfront.js +21 -0
- package/features/cloudsearch/cloudsearch.feature +34 -0
- package/features/cloudsearch/step_definitions/cloudsearch.js +42 -0
- package/features/cloudtrail/cloudtrail.feature +17 -0
- package/features/cloudtrail/step_definitions/cloudtrail.js +14 -0
- package/features/cloudwatch/cloudwatch.feature +15 -0
- package/features/cloudwatch/step_definitions/cloudwatch.js +48 -0
- package/features/datapipeline/datapipeline.feature +23 -0
- package/features/datapipeline/step_definitions/datapipeline.js +79 -0
- package/features/directconnect/directconnect.feature +20 -0
- package/features/directconnect/step_definitions/directconnect.js +44 -0
- package/features/dynamodb/crc32.feature +18 -0
- package/features/dynamodb/step_definitions/dynamodb.js +154 -0
- package/features/dynamodb/tables.feature +50 -0
- package/features/ec2/ec2.feature +28 -0
- package/features/ec2/step_definitions/ec2.js +65 -0
- package/features/elasticache/elasticache.feature +20 -0
- package/features/elasticache/step_definitions/elasticache.js +34 -0
- package/features/elasticbeanstalk/elasticbeanstalk.feature +22 -0
- package/features/elasticbeanstalk/step_definitions/elasticbeanstalk.js +38 -0
- package/features/elastictranscoder/elastictranscoder.feature +24 -0
- package/features/elastictranscoder/step_definitions/elastictranscoder.js +56 -0
- package/features/elb/elb.feature +19 -0
- package/features/elb/step_definitions/elb.js +37 -0
- package/features/emr/emr.feature +16 -0
- package/features/emr/step_definitions/emr.js +45 -0
- package/features/extra/assertions.js +29 -0
- package/features/extra/dummy.feature +0 -0
- package/features/extra/fixtures/testfile.txt +1 -0
- package/features/extra/helpers.js +113 -0
- package/features/extra/hooks.js +107 -0
- package/features/extra/world.js +12 -0
- package/features/glacier/glacier.feature +47 -0
- package/features/glacier/step_definitions/glacier.js +112 -0
- package/features/iam/iam.feature +24 -0
- package/features/iam/step_definitions/iam.js +66 -0
- package/features/importexport/importexport.feature +53 -0
- package/features/importexport/step_definitions/importexport.js +42 -0
- package/features/kinesis/kinesis.feature +9 -0
- package/features/kinesis/step_definitions/kinesis.js +10 -0
- package/features/opsworks/opsworks.feature +26 -0
- package/features/opsworks/step_definitions/opsworks.js +42 -0
- package/features/rds/rds.feature +32 -0
- package/features/rds/step_definitions/rds.js +72 -0
- package/features/redshift/redshift.feature +20 -0
- package/features/redshift/step_definitions/redshift.js +33 -0
- package/features/route53/route53.feature +41 -0
- package/features/route53/step_definitions/route53.js +97 -0
- package/features/s3/buckets.feature +40 -0
- package/features/s3/objects.feature +122 -0
- package/features/s3/step_definitions/buckets.js +136 -0
- package/features/s3/step_definitions/hooks.js +39 -0
- package/features/s3/step_definitions/objects.js +204 -0
- package/features/s3/step_definitions/proxy.js +44 -0
- package/features/ses/ses.feature +20 -0
- package/features/ses/step_definitions/ses.js +22 -0
- package/features/simpledb/simpledb.feature +29 -0
- package/features/simpledb/step_definitions/simpledb.js +46 -0
- package/features/sns/sns.feature +15 -0
- package/features/sns/step_definitions/sns.js +33 -0
- package/features/sqs/messages.feature +21 -0
- package/features/sqs/queues.feature +18 -0
- package/features/sqs/step_definitions/messages.js +46 -0
- package/features/sqs/step_definitions/queues.js +33 -0
- package/features/sqs/step_definitions/sqs.js +7 -0
- package/features/storagegateway/step_definitions/storagegateway.js +16 -0
- package/features/storagegateway/storagegateway.feature +13 -0
- package/features/sts/step_definitions/sts.js +35 -0
- package/features/sts/sts.feature +29 -0
- package/features/support/step_definitions/support.js +35 -0
- package/features/support/support.feature +18 -0
- package/features/swf/step_definitions/swf.js +38 -0
- package/features/swf/swf.feature +15 -0
- package/index.js +2 -0
- package/lib/core.js +2 -2
- package/lib/credentials/shared_ini_file_credentials.js +0 -1
- package/lib/event_listeners.js +13 -1
- package/lib/http/node.js +19 -30
- package/lib/model/resource_waiter.js +0 -4
- package/lib/model/shape.js +2 -1
- package/lib/protocol/rest_xml.js +1 -1
- package/lib/region_config.js +31 -0
- package/lib/region_config.json +56 -0
- package/lib/request.js +37 -45
- package/lib/sequential_executor.js +17 -34
- package/lib/service.js +17 -44
- package/lib/services/cloudsearchdomain.js +69 -0
- package/lib/services/route53.js +0 -12
- package/lib/services/s3.js +3 -19
- package/lib/signers/v4.js +2 -1
- package/lib/util.js +28 -3
- package/package.json +3 -3
- package/scripts/console +11 -3
- package/scripts/coverage +126 -0
- package/tasks/apis.rake +122 -0
- package/tasks/browser.rake +89 -0
- package/tasks/docs.rake +36 -0
- package/tasks/lib/cucumber_generator.rb +40 -0
- package/tasks/util.rake +33 -0
- package/test/browser/js/jasmine-1.3.1.js +2600 -0
- package/test/browser/js/jasmine-html.js +681 -0
- package/test/browser/runner.html +109 -0
- package/test/browser/runner.js +92 -0
- package/test/browser/sample/appinfo.sample.js +15 -0
- package/test/browser/sample/console.html +429 -0
- package/test/browser/sample/css/smoothness/images/animated-overlay.gif +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- package/test/browser/sample/css/smoothness/jquery-ui-1.10.1.custom.css +1175 -0
- package/test/browser/sample/css/smoothness/jquery-ui-1.10.1.custom.min.css +5 -0
- package/test/browser/sample/img/loading.gif +0 -0
- package/test/browser/sample/js/jquery-1.9.1.js +9597 -0
- package/test/browser/sample/js/jquery-ui-1.10.1.custom.js +14903 -0
- package/test/browser/sample/js/jquery-ui-1.10.1.custom.min.js +6 -0
- package/test/browser/sample/s3upload.html +111 -0
- package/test/browser.spec.coffee +207 -0
- package/test/config.spec.coffee +202 -0
- package/test/credential_provider_chain.spec.coffee +90 -0
- package/test/credentials.spec.coffee +452 -0
- package/test/endpoint.spec.coffee +80 -0
- package/test/event_listeners.spec.coffee +493 -0
- package/test/helpers.coffee +150 -0
- package/test/http_request.spec.coffee +55 -0
- package/test/json/builder.spec.coffee +129 -0
- package/test/json/parser.spec.coffee +108 -0
- package/test/metadata_service.spec.coffee +54 -0
- package/test/model/api.spec.coffee +67 -0
- package/test/model/shape.spec.coffee +23 -0
- package/test/node_http_client.spec.coffee +40 -0
- package/test/param_validator.spec.coffee +456 -0
- package/test/protocol/json.spec.coffee +167 -0
- package/test/protocol/query.spec.coffee +191 -0
- package/test/protocol/rest.spec.coffee +237 -0
- package/test/protocol/rest_json.spec.coffee +255 -0
- package/test/protocol/rest_xml.spec.coffee +329 -0
- package/test/query/query_param_serializer.spec.coffee +327 -0
- package/test/region_config.spec.coffee +50 -0
- package/test/request.spec.coffee +316 -0
- package/test/resource_waiter.spec.coffee +89 -0
- package/test/response.spec.coffee +81 -0
- package/test/sequential_executor.spec.coffee +118 -0
- package/test/service.spec.coffee +230 -0
- package/test/services/cloudfront.spec.coffee +44 -0
- package/test/services/cloudsearchdomain.spec.coffee +23 -0
- package/test/services/dynamodb.spec.coffee +32 -0
- package/test/services/ec2.spec.coffee +78 -0
- package/test/services/elastictranscoder.spec.coffee +43 -0
- package/test/services/glacier.spec.coffee +61 -0
- package/test/services/rds.spec.coffee +38 -0
- package/test/services/route53.spec.coffee +77 -0
- package/test/services/s3.spec.coffee +538 -0
- package/test/services/simpledb.spec.coffee +12 -0
- package/test/services/sqs.spec.coffee +130 -0
- package/test/services/sts.spec.coffee +72 -0
- package/test/services/swf.spec.coffee +6 -0
- package/test/signers/presign.spec.coffee +36 -0
- package/test/signers/s3.spec.coffee +297 -0
- package/test/signers/v2.spec.coffee +68 -0
- package/test/signers/v4.spec.coffee +135 -0
- package/test/util.spec.coffee +510 -0
- package/test/xml/builder.spec.coffee +529 -0
- package/test/xml/parser.spec.coffee +587 -0
- package/lib/services/simpledb.js +0 -15
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
helpers = require('../helpers')
|
|
2
|
+
AWS = helpers.AWS
|
|
3
|
+
Stream = require('stream').Stream
|
|
4
|
+
Buffer = AWS.util.Buffer
|
|
5
|
+
|
|
6
|
+
describe 'AWS.S3', ->
|
|
7
|
+
|
|
8
|
+
s3 = null
|
|
9
|
+
request = (operation, params) -> s3.makeRequest(operation, params)
|
|
10
|
+
|
|
11
|
+
beforeEach ->
|
|
12
|
+
s3 = new AWS.S3(region: undefined)
|
|
13
|
+
|
|
14
|
+
describe 'dnsCompatibleBucketName', ->
|
|
15
|
+
|
|
16
|
+
it 'must be at least 3 characters', ->
|
|
17
|
+
expect(s3.dnsCompatibleBucketName('aa')).toBe(false)
|
|
18
|
+
|
|
19
|
+
it 'must not be longer than 63 characters', ->
|
|
20
|
+
b = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
|
21
|
+
expect(s3.dnsCompatibleBucketName(b)).toBe(false)
|
|
22
|
+
|
|
23
|
+
it 'must start with a lower-cased letter or number', ->
|
|
24
|
+
expect(s3.dnsCompatibleBucketName('Abc')).toBe(false)
|
|
25
|
+
expect(s3.dnsCompatibleBucketName('-bc')).toBe(false)
|
|
26
|
+
expect(s3.dnsCompatibleBucketName('abc')).toBe(true)
|
|
27
|
+
|
|
28
|
+
it 'must end with a lower-cased letter or number', ->
|
|
29
|
+
expect(s3.dnsCompatibleBucketName('abC')).toBe(false)
|
|
30
|
+
expect(s3.dnsCompatibleBucketName('ab-')).toBe(false)
|
|
31
|
+
expect(s3.dnsCompatibleBucketName('abc')).toBe(true)
|
|
32
|
+
|
|
33
|
+
it 'may not contain multiple contiguous dots', ->
|
|
34
|
+
expect(s3.dnsCompatibleBucketName('abc.123')).toBe(true)
|
|
35
|
+
expect(s3.dnsCompatibleBucketName('abc..123')).toBe(false)
|
|
36
|
+
|
|
37
|
+
it 'may only contain letters numbers and dots', ->
|
|
38
|
+
expect(s3.dnsCompatibleBucketName('abc123')).toBe(true)
|
|
39
|
+
expect(s3.dnsCompatibleBucketName('abc_123')).toBe(false)
|
|
40
|
+
|
|
41
|
+
it 'must not look like an ip address', ->
|
|
42
|
+
expect(s3.dnsCompatibleBucketName('1.2.3.4')).toBe(false)
|
|
43
|
+
expect(s3.dnsCompatibleBucketName('a.b.c.d')).toBe(true)
|
|
44
|
+
|
|
45
|
+
describe 'endpoint', ->
|
|
46
|
+
|
|
47
|
+
it 'sets hostname to s3.amazonaws.com when region is un-specified', ->
|
|
48
|
+
s3 = new AWS.S3(region: undefined)
|
|
49
|
+
expect(s3.endpoint.hostname).toEqual('s3.amazonaws.com')
|
|
50
|
+
|
|
51
|
+
it 'sets hostname to s3.amazonaws.com when region is us-east-1', ->
|
|
52
|
+
s3 = new AWS.S3(region: 'us-east-1')
|
|
53
|
+
expect(s3.endpoint.hostname).toEqual('s3.amazonaws.com')
|
|
54
|
+
|
|
55
|
+
it 'sets region to us-east-1 when unspecified', ->
|
|
56
|
+
s3 = new AWS.S3(region: 'us-east-1')
|
|
57
|
+
expect(s3.config.region).toEqual('us-east-1')
|
|
58
|
+
|
|
59
|
+
it 'combines the region with s3 in the endpoint using a - instead of .', ->
|
|
60
|
+
s3 = new AWS.S3(region: 'us-west-1')
|
|
61
|
+
expect(s3.endpoint.hostname).toEqual('s3-us-west-1.amazonaws.com')
|
|
62
|
+
|
|
63
|
+
describe 'building a request', ->
|
|
64
|
+
build = (operation, params) ->
|
|
65
|
+
request(operation, params).build().httpRequest
|
|
66
|
+
|
|
67
|
+
it 'obeys the configuration for s3ForcePathStyle', ->
|
|
68
|
+
config = new AWS.Config(s3ForcePathStyle: true, accessKeyId: 'AKID', secretAccessKey: 'SECRET')
|
|
69
|
+
s3 = new AWS.S3(config)
|
|
70
|
+
expect(s3.config.s3ForcePathStyle).toEqual(true)
|
|
71
|
+
req = build('headObject', {Bucket:'bucket', Key:'key'})
|
|
72
|
+
expect(req.endpoint.hostname).toEqual('s3.amazonaws.com')
|
|
73
|
+
expect(req.path).toEqual('/bucket/key')
|
|
74
|
+
|
|
75
|
+
describe 'uri escaped params', ->
|
|
76
|
+
it 'uri-escapes path and querystring params', ->
|
|
77
|
+
# bucket param ends up as part of the hostname
|
|
78
|
+
params = { Bucket: 'bucket', Key: 'a b c', VersionId: 'a&b' }
|
|
79
|
+
req = build('headObject', params)
|
|
80
|
+
expect(req.path).toEqual('/a%20b%20c?versionId=a%26b')
|
|
81
|
+
|
|
82
|
+
it 'does not uri-escape forward slashes in the path', ->
|
|
83
|
+
params = { Bucket: 'bucket', Key: 'k e/y' }
|
|
84
|
+
req = build('headObject', params)
|
|
85
|
+
expect(req.path).toEqual('/k%20e/y')
|
|
86
|
+
|
|
87
|
+
it 'ensures a single forward slash exists', ->
|
|
88
|
+
req = build('listObjects', { Bucket: 'bucket' })
|
|
89
|
+
expect(req.path).toEqual('/')
|
|
90
|
+
|
|
91
|
+
req = build('listObjects', { Bucket: 'bucket', MaxKeys:123 })
|
|
92
|
+
expect(req.path).toEqual('/?max-keys=123')
|
|
93
|
+
|
|
94
|
+
describe 'adding Content-Type', ->
|
|
95
|
+
beforeEach -> spyOn(AWS.util, 'isBrowser').andReturn(true)
|
|
96
|
+
|
|
97
|
+
it 'adds default content-type when not supplied', ->
|
|
98
|
+
req = build('putObject', Bucket: 'bucket', Key: 'key', Body: 'body')
|
|
99
|
+
expect(req.headers['Content-Type']).toEqual('application/octet-stream; charset=UTF-8')
|
|
100
|
+
|
|
101
|
+
it 'adds charset to existing content-type if not supplied', ->
|
|
102
|
+
req = build('putObject', Bucket: 'bucket', Key: 'key', Body: 'body', ContentType: 'text/html')
|
|
103
|
+
expect(req.headers['Content-Type']).toEqual('text/html; charset=UTF-8')
|
|
104
|
+
|
|
105
|
+
it 'normalized charset to uppercase', ->
|
|
106
|
+
req = build('putObject', Bucket: 'bucket', Key: 'key', Body: 'body', ContentType: 'text/html; charset=utf-8')
|
|
107
|
+
expect(req.headers['Content-Type']).toEqual('text/html; charset=UTF-8')
|
|
108
|
+
|
|
109
|
+
it 'does not add charset to non-string data', ->
|
|
110
|
+
req = build('putObject', Bucket: 'bucket', Key: 'key', Body: new Buffer('body'), ContentType: 'image/png')
|
|
111
|
+
expect(req.headers['Content-Type']).toEqual('image/png')
|
|
112
|
+
|
|
113
|
+
describe 'virtual-hosted vs path-style bucket requests', ->
|
|
114
|
+
|
|
115
|
+
describe 'HTTPS', ->
|
|
116
|
+
|
|
117
|
+
beforeEach ->
|
|
118
|
+
s3 = new AWS.S3(sslEnabled: true, region: undefined)
|
|
119
|
+
|
|
120
|
+
it 'puts dns-compat bucket names in the hostname', ->
|
|
121
|
+
req = build('headObject', {Bucket:'bucket-name',Key:'abc'})
|
|
122
|
+
expect(req.method).toEqual('HEAD')
|
|
123
|
+
expect(req.endpoint.hostname).toEqual('bucket-name.s3.amazonaws.com')
|
|
124
|
+
expect(req.path).toEqual('/abc')
|
|
125
|
+
|
|
126
|
+
it 'ensures the path contains / at a minimum when moving bucket', ->
|
|
127
|
+
req = build('listObjects', {Bucket:'bucket-name'})
|
|
128
|
+
expect(req.endpoint.hostname).toEqual('bucket-name.s3.amazonaws.com')
|
|
129
|
+
expect(req.path).toEqual('/')
|
|
130
|
+
|
|
131
|
+
it 'puts dns-compat bucket names in path if they contain a dot', ->
|
|
132
|
+
req = build('listObjects', {Bucket:'bucket.name'})
|
|
133
|
+
expect(req.endpoint.hostname).toEqual('s3.amazonaws.com')
|
|
134
|
+
expect(req.path).toEqual('/bucket.name')
|
|
135
|
+
|
|
136
|
+
it 'puts dns-compat bucket names in path if configured to do so', ->
|
|
137
|
+
s3 = new AWS.S3(sslEnabled: true, s3ForcePathStyle: true, region: undefined)
|
|
138
|
+
req = build('listObjects', {Bucket:'bucket-name'})
|
|
139
|
+
expect(req.endpoint.hostname).toEqual('s3.amazonaws.com')
|
|
140
|
+
expect(req.path).toEqual('/bucket-name')
|
|
141
|
+
|
|
142
|
+
it 'puts dns-incompat bucket names in path', ->
|
|
143
|
+
req = build('listObjects', {Bucket:'bucket_name'})
|
|
144
|
+
expect(req.endpoint.hostname).toEqual('s3.amazonaws.com')
|
|
145
|
+
expect(req.path).toEqual('/bucket_name')
|
|
146
|
+
|
|
147
|
+
describe 'HTTP', ->
|
|
148
|
+
|
|
149
|
+
beforeEach ->
|
|
150
|
+
s3 = new AWS.S3(sslEnabled: false, region: undefined)
|
|
151
|
+
|
|
152
|
+
it 'puts dns-compat bucket names in the hostname', ->
|
|
153
|
+
req = build('listObjects', {Bucket:'bucket-name'})
|
|
154
|
+
expect(req.endpoint.hostname).toEqual('bucket-name.s3.amazonaws.com')
|
|
155
|
+
expect(req.path).toEqual('/')
|
|
156
|
+
|
|
157
|
+
it 'puts dns-compat bucket names in the hostname if they contain a dot', ->
|
|
158
|
+
req = build('listObjects', {Bucket:'bucket.name'})
|
|
159
|
+
expect(req.endpoint.hostname).toEqual('bucket.name.s3.amazonaws.com')
|
|
160
|
+
expect(req.path).toEqual('/')
|
|
161
|
+
|
|
162
|
+
it 'puts dns-incompat bucket names in path', ->
|
|
163
|
+
req = build('listObjects', {Bucket:'bucket_name'})
|
|
164
|
+
expect(req.endpoint.hostname).toEqual('s3.amazonaws.com')
|
|
165
|
+
expect(req.path).toEqual('/bucket_name')
|
|
166
|
+
|
|
167
|
+
describe 'SSE support', ->
|
|
168
|
+
beforeEach -> s3 = new AWS.S3
|
|
169
|
+
|
|
170
|
+
it 'encodes SSECustomerKey and fills in MD5', ->
|
|
171
|
+
req = s3.putObject
|
|
172
|
+
Bucket: 'bucket', Key: 'key', Body: 'data'
|
|
173
|
+
SSECustomerKey: 'KEY', SSECustomerAlgorithm: 'AES256'
|
|
174
|
+
req.build()
|
|
175
|
+
expect(req.httpRequest.headers['x-amz-server-side-encryption-customer-key']).
|
|
176
|
+
toEqual('S0VZ')
|
|
177
|
+
expect(req.httpRequest.headers['x-amz-server-side-encryption-customer-key-MD5']).
|
|
178
|
+
toEqual('TzFsSjRNSnJoM1o2UjFLaWR0NlZjQT09')
|
|
179
|
+
|
|
180
|
+
it 'encodes CopySourceSSECustomerKey and fills in MD5', ->
|
|
181
|
+
req = s3.copyObject
|
|
182
|
+
Bucket: 'bucket', Key: 'key', CopySource: 'bucket/oldkey', Body: 'data'
|
|
183
|
+
CopySourceSSECustomerKey: 'KEY', CopySourceSSECustomerAlgorithm: 'AES256'
|
|
184
|
+
req.build()
|
|
185
|
+
expect(req.httpRequest.headers['x-amz-copy-source-server-side-encryption-customer-key']).
|
|
186
|
+
toEqual('S0VZ')
|
|
187
|
+
expect(req.httpRequest.headers['x-amz-copy-source-server-side-encryption-customer-key-MD5']).
|
|
188
|
+
toEqual('TzFsSjRNSnJoM1o2UjFLaWR0NlZjQT09')
|
|
189
|
+
|
|
190
|
+
describe 'retry behavior', ->
|
|
191
|
+
it 'retries RequestTimeout errors', ->
|
|
192
|
+
s3.config.maxRetries = 3
|
|
193
|
+
helpers.mockHttpResponse 400, {},
|
|
194
|
+
'<xml><Code>RequestTimeout</Code><Message>message</Message></xml>'
|
|
195
|
+
s3.putObject (err, data) ->
|
|
196
|
+
expect(@retryCount).toEqual(s3.config.maxRetries)
|
|
197
|
+
|
|
198
|
+
# S3 returns a handful of errors without xml bodies (to match the
|
|
199
|
+
# http spec) these tests ensure we give meaningful codes/messages for these.
|
|
200
|
+
describe 'errors with no XML body', ->
|
|
201
|
+
|
|
202
|
+
extractError = (statusCode, body) ->
|
|
203
|
+
req = request('operation')
|
|
204
|
+
resp = new AWS.Response(req)
|
|
205
|
+
resp.httpResponse.body = new Buffer(body || '')
|
|
206
|
+
resp.httpResponse.statusCode = statusCode
|
|
207
|
+
req.emit('extractError', [resp])
|
|
208
|
+
resp.error
|
|
209
|
+
|
|
210
|
+
it 'handles 304 errors', ->
|
|
211
|
+
error = extractError(304)
|
|
212
|
+
expect(error.code).toEqual('NotModified')
|
|
213
|
+
expect(error.message).toEqual(null)
|
|
214
|
+
|
|
215
|
+
it 'handles 400 errors', ->
|
|
216
|
+
error = extractError(400)
|
|
217
|
+
expect(error.code).toEqual('BadRequest')
|
|
218
|
+
expect(error.message).toEqual(null)
|
|
219
|
+
|
|
220
|
+
it 'handles 403 errors', ->
|
|
221
|
+
error = extractError(403)
|
|
222
|
+
expect(error.code).toEqual('Forbidden')
|
|
223
|
+
expect(error.message).toEqual(null)
|
|
224
|
+
|
|
225
|
+
it 'handles 404 errors', ->
|
|
226
|
+
error = extractError(404)
|
|
227
|
+
expect(error.code).toEqual('NotFound')
|
|
228
|
+
expect(error.message).toEqual(null)
|
|
229
|
+
|
|
230
|
+
it 'misc errors not known to return an empty body', ->
|
|
231
|
+
error = extractError(412) # made up
|
|
232
|
+
expect(error.code).toEqual(412)
|
|
233
|
+
expect(error.message).toEqual(null)
|
|
234
|
+
|
|
235
|
+
it 'uses canned errors only when the body is empty', ->
|
|
236
|
+
body = """
|
|
237
|
+
<xml>
|
|
238
|
+
<Code>ErrorCode</Code>
|
|
239
|
+
<Message>ErrorMessage</Message>
|
|
240
|
+
</xml>
|
|
241
|
+
"""
|
|
242
|
+
error = extractError(403, body)
|
|
243
|
+
expect(error.code).toEqual('ErrorCode')
|
|
244
|
+
expect(error.message).toEqual('ErrorMessage')
|
|
245
|
+
|
|
246
|
+
# tests from this point on are "special cases" for specific aws operations
|
|
247
|
+
|
|
248
|
+
describe 'getBucketAcl', ->
|
|
249
|
+
it 'correctly parses the ACL XML document', ->
|
|
250
|
+
headers = { 'x-amz-request-id' : 'request-id' }
|
|
251
|
+
body =
|
|
252
|
+
"""
|
|
253
|
+
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
254
|
+
<AccessControlList>
|
|
255
|
+
<Grant>
|
|
256
|
+
<Grantee xsi:type="CanonicalUser" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
257
|
+
<DisplayName>aws-sdk</DisplayName>
|
|
258
|
+
<ID>id</ID>
|
|
259
|
+
</Grantee>
|
|
260
|
+
<Permission>FULL_CONTROL</Permission>
|
|
261
|
+
</Grant>
|
|
262
|
+
<Grant>
|
|
263
|
+
<Grantee xsi:type="Group" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
264
|
+
<URI>uri</URI>
|
|
265
|
+
</Grantee>
|
|
266
|
+
<Permission>READ</Permission>
|
|
267
|
+
</Grant>
|
|
268
|
+
</AccessControlList>
|
|
269
|
+
<Owner>
|
|
270
|
+
<DisplayName>aws-sdk</DisplayName>
|
|
271
|
+
<ID>id</ID>
|
|
272
|
+
</Owner>
|
|
273
|
+
</AccessControlPolicy>
|
|
274
|
+
"""
|
|
275
|
+
helpers.mockHttpResponse 200, headers, body
|
|
276
|
+
s3.getBucketAcl (error, data) ->
|
|
277
|
+
expect(error).toBe(null)
|
|
278
|
+
expect(data).toEqual({
|
|
279
|
+
Owner:
|
|
280
|
+
DisplayName: 'aws-sdk',
|
|
281
|
+
ID: 'id'
|
|
282
|
+
Grants: [
|
|
283
|
+
{
|
|
284
|
+
Permission: 'FULL_CONTROL'
|
|
285
|
+
Grantee:
|
|
286
|
+
Type: 'CanonicalUser'
|
|
287
|
+
DisplayName: 'aws-sdk'
|
|
288
|
+
ID: 'id'
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
Permission : 'READ'
|
|
292
|
+
Grantee:
|
|
293
|
+
Type: 'Group'
|
|
294
|
+
URI: 'uri'
|
|
295
|
+
}
|
|
296
|
+
]
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
describe 'putBucketAcl', ->
|
|
300
|
+
it 'correctly builds the ACL XML document', ->
|
|
301
|
+
xml =
|
|
302
|
+
"""
|
|
303
|
+
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
304
|
+
<AccessControlList>
|
|
305
|
+
<Grant>
|
|
306
|
+
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
|
|
307
|
+
<DisplayName>aws-sdk</DisplayName>
|
|
308
|
+
<ID>id</ID>
|
|
309
|
+
</Grantee>
|
|
310
|
+
<Permission>FULL_CONTROL</Permission>
|
|
311
|
+
</Grant>
|
|
312
|
+
<Grant>
|
|
313
|
+
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group">
|
|
314
|
+
<URI>uri</URI>
|
|
315
|
+
</Grantee>
|
|
316
|
+
<Permission>READ</Permission>
|
|
317
|
+
</Grant>
|
|
318
|
+
</AccessControlList>
|
|
319
|
+
<Owner>
|
|
320
|
+
<DisplayName>aws-sdk</DisplayName>
|
|
321
|
+
<ID>id</ID>
|
|
322
|
+
</Owner>
|
|
323
|
+
</AccessControlPolicy>
|
|
324
|
+
"""
|
|
325
|
+
helpers.mockHttpResponse 200, {}, ''
|
|
326
|
+
params =
|
|
327
|
+
AccessControlPolicy:
|
|
328
|
+
Owner:
|
|
329
|
+
DisplayName: 'aws-sdk',
|
|
330
|
+
ID: 'id'
|
|
331
|
+
Grants: [
|
|
332
|
+
{
|
|
333
|
+
Permission: 'FULL_CONTROL'
|
|
334
|
+
Grantee:
|
|
335
|
+
Type: 'CanonicalUser',
|
|
336
|
+
DisplayName: 'aws-sdk'
|
|
337
|
+
ID: 'id'
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
Permission : 'READ'
|
|
341
|
+
Grantee:
|
|
342
|
+
Type: 'Group',
|
|
343
|
+
URI: 'uri'
|
|
344
|
+
}
|
|
345
|
+
]
|
|
346
|
+
s3.putBucketAcl params, (err, data) ->
|
|
347
|
+
helpers.matchXML(this.request.httpRequest.body, xml)
|
|
348
|
+
|
|
349
|
+
describe 'completeMultipartUpload', ->
|
|
350
|
+
|
|
351
|
+
it 'returns data when the resp is 200 with valid response', ->
|
|
352
|
+
headers =
|
|
353
|
+
'x-amz-id-2': 'Uuag1LuByRx9e6j5Onimru9pO4ZVKnJ2Qz7/C1NPcfTWAtRPfTaOFg=='
|
|
354
|
+
'x-amz-request-id': '656c76696e6727732072657175657374'
|
|
355
|
+
body =
|
|
356
|
+
"""
|
|
357
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
358
|
+
<CompleteMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
359
|
+
<Location>http://Example-Bucket.s3.amazonaws.com/Example-Object</Location>
|
|
360
|
+
<Bucket>Example-Bucket</Bucket>
|
|
361
|
+
<Key>Example-Object</Key>
|
|
362
|
+
<ETag>"3858f62230ac3c915f300c664312c11f-9"</ETag>
|
|
363
|
+
</CompleteMultipartUploadResult>
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
helpers.mockHttpResponse 200, headers, body
|
|
367
|
+
s3.completeMultipartUpload (error, data) ->
|
|
368
|
+
expect(error).toBe(null)
|
|
369
|
+
expect(data).toEqual({
|
|
370
|
+
Location: 'http://Example-Bucket.s3.amazonaws.com/Example-Object'
|
|
371
|
+
Bucket: 'Example-Bucket'
|
|
372
|
+
Key: 'Example-Object'
|
|
373
|
+
ETag: '"3858f62230ac3c915f300c664312c11f-9"'
|
|
374
|
+
})
|
|
375
|
+
expect(this.requestId).toEqual('656c76696e6727732072657175657374')
|
|
376
|
+
|
|
377
|
+
it 'returns an error when the resp is 200 with an error xml document', ->
|
|
378
|
+
body =
|
|
379
|
+
"""
|
|
380
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
381
|
+
<Error>
|
|
382
|
+
<Code>InternalError</Code>
|
|
383
|
+
<Message>We encountered an internal error. Please try again.</Message>
|
|
384
|
+
<RequestId>656c76696e6727732072657175657374</RequestId>
|
|
385
|
+
<HostId>Uuag1LuByRx9e6j5Onimru9pO4ZVKnJ2Qz7/C1NPcfTWAtRPfTaOFg==</HostId>
|
|
386
|
+
</Error>
|
|
387
|
+
"""
|
|
388
|
+
|
|
389
|
+
helpers.mockHttpResponse 200, {}, body
|
|
390
|
+
s3.completeMultipartUpload (error, data) ->
|
|
391
|
+
expect(error instanceof Error).toBeTruthy()
|
|
392
|
+
expect(error.code).toEqual('InternalError')
|
|
393
|
+
expect(error.message).toEqual('We encountered an internal error. Please try again.')
|
|
394
|
+
expect(error.statusCode).toEqual(200)
|
|
395
|
+
expect(error.retryable).toEqual(true)
|
|
396
|
+
expect(data).toEqual(null)
|
|
397
|
+
|
|
398
|
+
describe 'getBucketLocation', ->
|
|
399
|
+
|
|
400
|
+
it 'returns null for the location constraint when not present', ->
|
|
401
|
+
body = '<?xml version="1.0" encoding="UTF-8"?>\n<LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/"/>'
|
|
402
|
+
helpers.mockHttpResponse 200, {}, body
|
|
403
|
+
s3.getBucketLocation (error, data) ->
|
|
404
|
+
expect(error).toBe(null)
|
|
405
|
+
expect(data).toEqual({})
|
|
406
|
+
|
|
407
|
+
it 'parses the location constraint from the root xml', ->
|
|
408
|
+
headers = { 'x-amz-request-id': 'abcxyz' }
|
|
409
|
+
body = '<?xml version="1.0" encoding="UTF-8"?>\n<LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/">EU</LocationConstraint>'
|
|
410
|
+
helpers.mockHttpResponse 200, headers, body
|
|
411
|
+
s3.getBucketLocation (error, data) ->
|
|
412
|
+
expect(error).toBe(null)
|
|
413
|
+
expect(data).toEqual(LocationConstraint: 'EU')
|
|
414
|
+
expect(this.requestId).toEqual('abcxyz')
|
|
415
|
+
|
|
416
|
+
describe 'createBucket', ->
|
|
417
|
+
it 'auto-populates the LocationConstraint based on the region', ->
|
|
418
|
+
loc = null
|
|
419
|
+
s3 = new AWS.S3(region:'eu-west-1')
|
|
420
|
+
s3.makeRequest = (op, params) ->
|
|
421
|
+
loc = params.CreateBucketConfiguration.LocationConstraint
|
|
422
|
+
s3.createBucket(Bucket:'name')
|
|
423
|
+
expect(loc).toEqual('eu-west-1')
|
|
424
|
+
|
|
425
|
+
it 'correctly builds the xml', ->
|
|
426
|
+
|
|
427
|
+
AWS.util.each AWS.S3.prototype.computableChecksumOperations, (operation) ->
|
|
428
|
+
describe operation, ->
|
|
429
|
+
it 'forces Content-MD5 header parameter', ->
|
|
430
|
+
req = s3[operation](Bucket: 'bucket', ContentMD5: '000').build()
|
|
431
|
+
hash = AWS.util.crypto.md5(req.httpRequest.body, 'base64')
|
|
432
|
+
expect(req.httpRequest.headers['Content-MD5']).toEqual(hash)
|
|
433
|
+
|
|
434
|
+
describe 'willComputeChecksums', ->
|
|
435
|
+
willCompute = (operation, opts) ->
|
|
436
|
+
compute = opts.computeChecksums
|
|
437
|
+
s3 = new AWS.S3(computeChecksums: compute)
|
|
438
|
+
req = s3.makeRequest(operation, Bucket: 'example', ContentMD5: opts.hash).build()
|
|
439
|
+
checksum = req.httpRequest.headers['Content-MD5']
|
|
440
|
+
if opts.hash != undefined
|
|
441
|
+
expect(checksum).toEqual(opts.hash)
|
|
442
|
+
else
|
|
443
|
+
realChecksum = AWS.util.crypto.md5(req.httpRequest.body, 'base64')
|
|
444
|
+
expect(checksum).toEqual(realChecksum)
|
|
445
|
+
|
|
446
|
+
it 'computes checksums if the operation requires it', ->
|
|
447
|
+
willCompute 'deleteObjects', computeChecksums: true
|
|
448
|
+
willCompute 'putBucketCors', computeChecksums: true
|
|
449
|
+
willCompute 'putBucketLifecycle', computeChecksums: true
|
|
450
|
+
willCompute 'putBucketTagging', computeChecksums: true
|
|
451
|
+
|
|
452
|
+
it 'computes checksums if computeChecksums is off and operation requires it', ->
|
|
453
|
+
willCompute 'deleteObjects', computeChecksums: false
|
|
454
|
+
willCompute 'putBucketCors', computeChecksums: false
|
|
455
|
+
willCompute 'putBucketLifecycle', computeChecksums: false
|
|
456
|
+
willCompute 'putBucketTagging', computeChecksums: false
|
|
457
|
+
|
|
458
|
+
it 'does not compute checksums if computeChecksums is off', ->
|
|
459
|
+
willCompute 'putObject', computeChecksums: false, hash: null
|
|
460
|
+
|
|
461
|
+
it 'does not compute checksums if computeChecksums is on and ContentMD5 is provided', ->
|
|
462
|
+
willCompute 'putBucketAcl', computeChecksums: true, hash: '000'
|
|
463
|
+
|
|
464
|
+
it 'does not compute checksums for Stream objects', ->
|
|
465
|
+
s3 = new AWS.S3(computeChecksums: true)
|
|
466
|
+
req = s3.putObject(Bucket: 'example', Key: 'foo', Body: new Stream)
|
|
467
|
+
expect(req.build(->).httpRequest.headers['Content-MD5']).toEqual(undefined)
|
|
468
|
+
|
|
469
|
+
it 'computes checksums if computeChecksums is on and ContentMD5 is not provided',->
|
|
470
|
+
willCompute 'putBucketAcl', computeChecksums: true
|
|
471
|
+
|
|
472
|
+
describe 'getSignedUrl', ->
|
|
473
|
+
date = null
|
|
474
|
+
beforeEach ->
|
|
475
|
+
date = AWS.util.date.getDate
|
|
476
|
+
AWS.util.date.getDate = -> new Date(0)
|
|
477
|
+
afterEach ->
|
|
478
|
+
AWS.util.date.getDate = date
|
|
479
|
+
|
|
480
|
+
it 'gets a signed URL for getObject', ->
|
|
481
|
+
url = s3.getSignedUrl('getObject', Bucket: 'bucket', Key: 'key')
|
|
482
|
+
expect(url).toEqual('https://bucket.s3.amazonaws.com/key?AWSAccessKeyId=akid&Expires=900&Signature=4mlYnRmz%2BBFEPrgYz5tXcl9Wc4w%3D&x-amz-security-token=session')
|
|
483
|
+
|
|
484
|
+
it 'gets a signed URL with Expires time', ->
|
|
485
|
+
url = s3.getSignedUrl('getObject', Bucket: 'bucket', Key: 'key', Expires: 60)
|
|
486
|
+
expect(url).toEqual('https://bucket.s3.amazonaws.com/key?AWSAccessKeyId=akid&Expires=60&Signature=kH2pMK%2Fgm7cCZKVG8GHVTRGXKzY%3D&x-amz-security-token=session')
|
|
487
|
+
|
|
488
|
+
it 'gets a signed URL with expiration and bound bucket parameters', ->
|
|
489
|
+
s3 = new AWS.S3(paramValidation: true, region: undefined, params: Bucket: 'bucket')
|
|
490
|
+
url = s3.getSignedUrl('getObject', Key: 'key', Expires: 60)
|
|
491
|
+
expect(url).toEqual('https://bucket.s3.amazonaws.com/key?AWSAccessKeyId=akid&Expires=60&Signature=kH2pMK%2Fgm7cCZKVG8GHVTRGXKzY%3D&x-amz-security-token=session')
|
|
492
|
+
|
|
493
|
+
it 'generates the right URL with a custom endpoint', ->
|
|
494
|
+
s3 = new AWS.S3(endpoint: 'https://foo.bar.baz:555/prefix', params: Bucket: 'bucket')
|
|
495
|
+
url = s3.getSignedUrl('getObject', Key: 'key', Expires: 60)
|
|
496
|
+
expect(url).toEqual('https://bucket.foo.bar.baz:555/prefix/key?AWSAccessKeyId=akid&Expires=60&Signature=zA6k0cQqDkTZgLamfoYLOd%2Bqfg8%3D&x-amz-security-token=session')
|
|
497
|
+
|
|
498
|
+
it 'gets a signed URL with callback', ->
|
|
499
|
+
url = null
|
|
500
|
+
runs ->
|
|
501
|
+
s3.getSignedUrl 'getObject', Bucket: 'bucket', Key: 'key', (err, value) -> url = value
|
|
502
|
+
waitsFor -> url
|
|
503
|
+
runs ->
|
|
504
|
+
expect(url).toEqual('https://bucket.s3.amazonaws.com/key?AWSAccessKeyId=akid&Expires=900&Signature=4mlYnRmz%2BBFEPrgYz5tXcl9Wc4w%3D&x-amz-security-token=session')
|
|
505
|
+
|
|
506
|
+
it 'gets a signed URL for putObject with no body', ->
|
|
507
|
+
url = s3.getSignedUrl('putObject', Bucket: 'bucket', Key: 'key')
|
|
508
|
+
expect(url).toEqual('https://bucket.s3.amazonaws.com/key?AWSAccessKeyId=akid&Expires=900&Signature=J%2BnWZ0lPUfLV0kio8ONhJmAttGc%3D&x-amz-security-token=session')
|
|
509
|
+
|
|
510
|
+
it 'gets a signed URL for putObject with special characters', ->
|
|
511
|
+
url = s3.getSignedUrl('putObject', Bucket: 'bucket', Key: '!@#$%^&*();\':"{}[],./?`~')
|
|
512
|
+
expect(url).toEqual('https://bucket.s3.amazonaws.com/%21%40%23%24%25%5E%26%2A%28%29%3B%27%3A%22%7B%7D%5B%5D%2C./%3F%60~?AWSAccessKeyId=akid&Expires=900&Signature=9nEltJACZKsriZqU2cmRel6g8LQ%3D&x-amz-security-token=session')
|
|
513
|
+
|
|
514
|
+
it 'gets a signed URL for putObject with a body (and checksum)', ->
|
|
515
|
+
url = s3.getSignedUrl('putObject', Bucket: 'bucket', Key: 'key', Body: 'body')
|
|
516
|
+
expect(url).toEqual('https://bucket.s3.amazonaws.com/key?AWSAccessKeyId=akid&Content-MD5=hBotaJrYa9FhFEdFPCLG%2FA%3D%3D&Expires=900&Signature=4ycA2tpHKxfFnNCdqnK1d5BG8gc%3D&x-amz-security-token=session')
|
|
517
|
+
|
|
518
|
+
it 'gets a signed URL and appends to existing query parameters', ->
|
|
519
|
+
url = s3.getSignedUrl('listObjects', Bucket: 'bucket', Prefix: 'prefix')
|
|
520
|
+
expect(url).toEqual('https://bucket.s3.amazonaws.com/?AWSAccessKeyId=akid&Expires=900&Signature=8W3pwZPfgucCyPNg1MsoYq8h5zw%3D&prefix=prefix&x-amz-security-token=session')
|
|
521
|
+
|
|
522
|
+
it 'gets a signed URL for getObject using SigV4', ->
|
|
523
|
+
s3 = new AWS.S3(signatureVersion: 'v4', region: undefined)
|
|
524
|
+
url = s3.getSignedUrl('getObject', Bucket: 'bucket', Key: 'object')
|
|
525
|
+
expect(url).toEqual('https://bucket.s3.amazonaws.com/object?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=akid%2F19700101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=19700101T000000Z&X-Amz-Expires=900&X-Amz-Security-Token=session&X-Amz-Signature=05ae40d2d22c93549a1de0686232ff56baf556876ec497d0d8349431f98b8dfe&X-Amz-SignedHeaders=host')
|
|
526
|
+
|
|
527
|
+
it 'errors when expiry time is greater than a week out on SigV4', ->
|
|
528
|
+
err = null; data = null
|
|
529
|
+
s3 = new AWS.S3(signatureVersion: 'v4', region: undefined)
|
|
530
|
+
params = Bucket: 'bucket', Key: 'object', Expires: 60 * 60 * 24 * 7 + 120
|
|
531
|
+
error = 'Presigning does not support expiry time greater than a week with SigV4 signing.'
|
|
532
|
+
runs ->
|
|
533
|
+
s3.getSignedUrl 'getObject', params, (e, d) -> data = d; err = e
|
|
534
|
+
waitsFor -> err || data
|
|
535
|
+
runs ->
|
|
536
|
+
expect(err).not.toEqual(null)
|
|
537
|
+
expect(err.message).toEqual(error)
|
|
538
|
+
#expect(-> s3.getSignedUrl('getObject', params)).toThrow(error) # sync mode
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
helpers = require('../helpers')
|
|
2
|
+
AWS = helpers.AWS
|
|
3
|
+
|
|
4
|
+
describe 'AWS.SimpleDB', ->
|
|
5
|
+
describe 'setEndpoint', ->
|
|
6
|
+
it 'uses global endpoint if region is us-east-1', ->
|
|
7
|
+
service = new AWS.SimpleDB(region: 'us-east-1')
|
|
8
|
+
expect(service.endpoint.host).toEqual('sdb.amazonaws.com')
|
|
9
|
+
|
|
10
|
+
it 'uses normal setEndpoint functionality if region is not us-east-1', ->
|
|
11
|
+
service = new AWS.SimpleDB(region: 'us-west-2')
|
|
12
|
+
expect(service.endpoint.host).toEqual('sdb.us-west-2.amazonaws.com')
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
helpers = require('../helpers')
|
|
2
|
+
AWS = helpers.AWS
|
|
3
|
+
|
|
4
|
+
describe 'AWS.SQS', ->
|
|
5
|
+
sqs = null
|
|
6
|
+
beforeEach ->
|
|
7
|
+
sqs = new AWS.SQS params: QueueUrl: 'http://url'
|
|
8
|
+
|
|
9
|
+
checksumValidate = (operation, input, response, shouldPass, cb) ->
|
|
10
|
+
output = null
|
|
11
|
+
helpers.mockHttpResponse 200, {}, response
|
|
12
|
+
runs ->
|
|
13
|
+
sqs[operation](input, (e, d) -> output = error: e, data: d)
|
|
14
|
+
waitsFor -> output
|
|
15
|
+
runs ->
|
|
16
|
+
if shouldPass
|
|
17
|
+
expect(output.error).toEqual(null)
|
|
18
|
+
else
|
|
19
|
+
expect(output.error).not.toEqual(null)
|
|
20
|
+
if cb
|
|
21
|
+
cb(output.error, output.data)
|
|
22
|
+
|
|
23
|
+
describe 'buildEndpoint', ->
|
|
24
|
+
it 'should detect correct region from QueueUrl', ->
|
|
25
|
+
sqs = new AWS.SQS
|
|
26
|
+
computeChecksums: false
|
|
27
|
+
params: QueueUrl: 'http://sqs.region-1.amazonaws.com/queue'
|
|
28
|
+
helpers.mockHttpResponse 200, {}, ''
|
|
29
|
+
req = sqs.sendMessage(MessageBody: 'foo')
|
|
30
|
+
req.build()
|
|
31
|
+
expect(req.httpRequest.region).toEqual('region-1')
|
|
32
|
+
|
|
33
|
+
describe 'sendMessage', ->
|
|
34
|
+
input = MessageBody: 'foo'
|
|
35
|
+
md5 = 'acbd18db4cc2f85cedef654fccc4a4d8'
|
|
36
|
+
payload = (md5) ->
|
|
37
|
+
"""
|
|
38
|
+
<SendMessageResponse><SendMessageResult>
|
|
39
|
+
<MD5OfMessageBody>#{md5}</MD5OfMessageBody>
|
|
40
|
+
<MessageId>MSGID</MessageId>
|
|
41
|
+
</SendMessageResult></SendMessageResponse>
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
it 'correctly validates MD5 of message input', ->
|
|
45
|
+
checksumValidate 'sendMessage', input, payload(md5), true, (err, data) ->
|
|
46
|
+
expect(data.MD5OfMessageBody).toEqual(md5)
|
|
47
|
+
|
|
48
|
+
it 'raises InvalidChecksum if MD5 does not match message input', ->
|
|
49
|
+
checksumValidate 'sendMessage', input, payload('000'), false, (err) ->
|
|
50
|
+
expect(err.message).toMatch('Got "000", expecting "acbd18db4cc2f85cedef654fccc4a4d8"')
|
|
51
|
+
expect(err.messageIds).toEqual(['MSGID'])
|
|
52
|
+
|
|
53
|
+
it 'ignores checksum errors if computeChecksums is false', ->
|
|
54
|
+
sqs.config.computeChecksums = false
|
|
55
|
+
checksumValidate 'sendMessage', input, payload('000'), true
|
|
56
|
+
|
|
57
|
+
describe 'sendMessageBatch', ->
|
|
58
|
+
input = Entries: [
|
|
59
|
+
{ Id: 'a', MessageBody: 'foo' },
|
|
60
|
+
{ Id: 'b', MessageBody: 'bar' },
|
|
61
|
+
{ Id: 'c', MessageBody: 'bar' }
|
|
62
|
+
]
|
|
63
|
+
md5foo = 'acbd18db4cc2f85cedef654fccc4a4d8'
|
|
64
|
+
md5bar = '37b51d194a7513e45b56f6524f2d51f2'
|
|
65
|
+
payload = (md5a, md5b, md5c) ->
|
|
66
|
+
"""
|
|
67
|
+
<SendMessageBatchResponse><SendMessageBatchResult>
|
|
68
|
+
<SendMessageBatchResultEntry>
|
|
69
|
+
<Id>a</Id>
|
|
70
|
+
<MessageId>MSGID1</MessageId>
|
|
71
|
+
<MD5OfMessageBody>#{md5a}</MD5OfMessageBody>
|
|
72
|
+
</SendMessageBatchResultEntry>
|
|
73
|
+
<SendMessageBatchResultEntry>
|
|
74
|
+
<Id>b</Id>
|
|
75
|
+
<MessageId>MSGID2</MessageId>
|
|
76
|
+
<MD5OfMessageBody>#{md5b}</MD5OfMessageBody>
|
|
77
|
+
</SendMessageBatchResultEntry>
|
|
78
|
+
<SendMessageBatchResultEntry>
|
|
79
|
+
<Id>c</Id>
|
|
80
|
+
<MessageId>MSGID3</MessageId>
|
|
81
|
+
<MD5OfMessageBody>#{md5c}</MD5OfMessageBody>
|
|
82
|
+
</SendMessageBatchResultEntry>
|
|
83
|
+
</SendMessageBatchResult></SendMessageBatchResponse>
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
it 'correctly validates MD5 of operation', ->
|
|
87
|
+
output = payload(md5foo, md5bar, md5bar)
|
|
88
|
+
checksumValidate 'sendMessageBatch', input, output, true, (err, data) ->
|
|
89
|
+
expect(data.Successful[0].MD5OfMessageBody).toEqual(md5foo)
|
|
90
|
+
expect(data.Successful[1].MD5OfMessageBody).toEqual(md5bar)
|
|
91
|
+
expect(data.Successful[2].MD5OfMessageBody).toEqual(md5bar)
|
|
92
|
+
|
|
93
|
+
it 'raises InvalidChecksum with relevent message IDs', ->
|
|
94
|
+
output = payload('000', md5bar, '000')
|
|
95
|
+
checksumValidate 'sendMessageBatch', input, output, false, (err, data) ->
|
|
96
|
+
expect(err.message).toMatch('Invalid messages: a, c')
|
|
97
|
+
expect(err.messageIds).toEqual(['MSGID1', 'MSGID3'])
|
|
98
|
+
|
|
99
|
+
it 'ignores checksum errors if computeChecksums is false', ->
|
|
100
|
+
output = payload(md5foo, '000', md5bar)
|
|
101
|
+
sqs.config.computeChecksums = false
|
|
102
|
+
checksumValidate 'sendMessageBatch', input, output, true
|
|
103
|
+
|
|
104
|
+
describe 'receiveMessage', ->
|
|
105
|
+
md5 = 'acbd18db4cc2f85cedef654fccc4a4d8'
|
|
106
|
+
payload = (body, md5, id) ->
|
|
107
|
+
"""
|
|
108
|
+
<ReceiveMessageResponse><ReceiveMessageResult><Message>
|
|
109
|
+
<Body>#{body}</Body>
|
|
110
|
+
<MD5OfBody>#{md5}</MD5OfBody>
|
|
111
|
+
<MessageId>#{id}</MessageId>
|
|
112
|
+
</Message></ReceiveMessageResult></ReceiveMessageResponse>
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
it 'correctly validates MD5 of operation', ->
|
|
116
|
+
output = payload('foo', md5, 'MSGID')
|
|
117
|
+
checksumValidate 'receiveMessage', {}, output, true, (err, data) ->
|
|
118
|
+
expect(data.Messages[0].MD5OfBody).toEqual(md5)
|
|
119
|
+
|
|
120
|
+
it 'raises InvalidChecksum with relevent message IDs', ->
|
|
121
|
+
output = payload('foo', '000', 'MSGID')
|
|
122
|
+
checksumValidate 'receiveMessage', {}, output, false, (err, data) ->
|
|
123
|
+
expect(err.message).toMatch('Invalid messages: MSGID')
|
|
124
|
+
expect(err.messageIds).toEqual(['MSGID'])
|
|
125
|
+
|
|
126
|
+
it 'ignores checksum errors if computeChecksums is false', ->
|
|
127
|
+
output = payload('foo', '000', 'MSGID')
|
|
128
|
+
sqs.config.computeChecksums = false
|
|
129
|
+
checksumValidate 'receiveMessage', {}, output, true, (err, data) ->
|
|
130
|
+
expect(data.Messages[0].MD5OfBody).not.toEqual(md5)
|