aws-sdk-s3 1.0.0.rc1

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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/lib/aws-sdk-s3.rb +66 -0
  3. data/lib/aws-sdk-s3/bucket.rb +595 -0
  4. data/lib/aws-sdk-s3/bucket_acl.rb +168 -0
  5. data/lib/aws-sdk-s3/bucket_cors.rb +146 -0
  6. data/lib/aws-sdk-s3/bucket_lifecycle.rb +164 -0
  7. data/lib/aws-sdk-s3/bucket_logging.rb +142 -0
  8. data/lib/aws-sdk-s3/bucket_notification.rb +187 -0
  9. data/lib/aws-sdk-s3/bucket_policy.rb +138 -0
  10. data/lib/aws-sdk-s3/bucket_region_cache.rb +79 -0
  11. data/lib/aws-sdk-s3/bucket_request_payment.rb +128 -0
  12. data/lib/aws-sdk-s3/bucket_tagging.rb +143 -0
  13. data/lib/aws-sdk-s3/bucket_versioning.rb +188 -0
  14. data/lib/aws-sdk-s3/bucket_website.rb +177 -0
  15. data/lib/aws-sdk-s3/client.rb +3171 -0
  16. data/lib/aws-sdk-s3/client_api.rb +1991 -0
  17. data/lib/aws-sdk-s3/customizations.rb +29 -0
  18. data/lib/aws-sdk-s3/customizations/bucket.rb +127 -0
  19. data/lib/aws-sdk-s3/customizations/multipart_upload.rb +42 -0
  20. data/lib/aws-sdk-s3/customizations/object.rb +257 -0
  21. data/lib/aws-sdk-s3/customizations/object_summary.rb +65 -0
  22. data/lib/aws-sdk-s3/customizations/types/list_object_versions_output.rb +11 -0
  23. data/lib/aws-sdk-s3/encryption.rb +19 -0
  24. data/lib/aws-sdk-s3/encryption/client.rb +369 -0
  25. data/lib/aws-sdk-s3/encryption/decrypt_handler.rb +178 -0
  26. data/lib/aws-sdk-s3/encryption/default_cipher_provider.rb +63 -0
  27. data/lib/aws-sdk-s3/encryption/default_key_provider.rb +38 -0
  28. data/lib/aws-sdk-s3/encryption/encrypt_handler.rb +50 -0
  29. data/lib/aws-sdk-s3/encryption/errors.rb +13 -0
  30. data/lib/aws-sdk-s3/encryption/io_auth_decrypter.rb +50 -0
  31. data/lib/aws-sdk-s3/encryption/io_decrypter.rb +29 -0
  32. data/lib/aws-sdk-s3/encryption/io_encrypter.rb +69 -0
  33. data/lib/aws-sdk-s3/encryption/key_provider.rb +29 -0
  34. data/lib/aws-sdk-s3/encryption/kms_cipher_provider.rb +71 -0
  35. data/lib/aws-sdk-s3/encryption/materials.rb +58 -0
  36. data/lib/aws-sdk-s3/encryption/utils.rb +79 -0
  37. data/lib/aws-sdk-s3/errors.rb +23 -0
  38. data/lib/aws-sdk-s3/file_part.rb +75 -0
  39. data/lib/aws-sdk-s3/file_uploader.rb +58 -0
  40. data/lib/aws-sdk-s3/legacy_signer.rb +186 -0
  41. data/lib/aws-sdk-s3/multipart_file_uploader.rb +187 -0
  42. data/lib/aws-sdk-s3/multipart_upload.rb +287 -0
  43. data/lib/aws-sdk-s3/multipart_upload_error.rb +16 -0
  44. data/lib/aws-sdk-s3/multipart_upload_part.rb +314 -0
  45. data/lib/aws-sdk-s3/object.rb +942 -0
  46. data/lib/aws-sdk-s3/object_acl.rb +214 -0
  47. data/lib/aws-sdk-s3/object_copier.rb +99 -0
  48. data/lib/aws-sdk-s3/object_multipart_copier.rb +179 -0
  49. data/lib/aws-sdk-s3/object_summary.rb +794 -0
  50. data/lib/aws-sdk-s3/object_version.rb +406 -0
  51. data/lib/aws-sdk-s3/plugins/accelerate.rb +92 -0
  52. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +89 -0
  53. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +23 -0
  54. data/lib/aws-sdk-s3/plugins/dualstack.rb +70 -0
  55. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +29 -0
  56. data/lib/aws-sdk-s3/plugins/get_bucket_location_fix.rb +23 -0
  57. data/lib/aws-sdk-s3/plugins/http_200_errors.rb +47 -0
  58. data/lib/aws-sdk-s3/plugins/location_constraint.rb +33 -0
  59. data/lib/aws-sdk-s3/plugins/md5s.rb +79 -0
  60. data/lib/aws-sdk-s3/plugins/redirects.rb +41 -0
  61. data/lib/aws-sdk-s3/plugins/s3_signer.rb +208 -0
  62. data/lib/aws-sdk-s3/plugins/sse_cpk.rb +68 -0
  63. data/lib/aws-sdk-s3/plugins/url_encoded_keys.rb +94 -0
  64. data/lib/aws-sdk-s3/presigned_post.rb +647 -0
  65. data/lib/aws-sdk-s3/presigner.rb +160 -0
  66. data/lib/aws-sdk-s3/resource.rb +96 -0
  67. data/lib/aws-sdk-s3/types.rb +5750 -0
  68. data/lib/aws-sdk-s3/waiters.rb +178 -0
  69. metadata +154 -0
@@ -0,0 +1,89 @@
1
+ module Aws
2
+ module S3
3
+ module Plugins
4
+
5
+ # Amazon S3 requires DNS style addressing for buckets outside of
6
+ # the classic region when possible.
7
+ class BucketDns < Seahorse::Client::Plugin
8
+
9
+ # When set to `false` DNS compatible bucket names are moved from
10
+ # the request URI path to the host as a subdomain, unless the request
11
+ # is using SSL and the bucket name contains a dot.
12
+ #
13
+ # When set to `true`, the bucket name is always forced to be part
14
+ # of the request URI path. This will not work with buckets outside
15
+ # the classic region.
16
+ option(:force_path_style,
17
+ default: false,
18
+ doc_type: 'Boolean',
19
+ docstring: <<-DOCS)
20
+ When set to `true`, the bucket name is always left in the
21
+ request URI and never moved to the host as a sub-domain.
22
+ DOCS
23
+
24
+ def add_handlers(handlers, config)
25
+ handlers.add(Handler) unless config.force_path_style
26
+ end
27
+
28
+ # @api private
29
+ class Handler < Seahorse::Client::Handler
30
+
31
+ def call(context)
32
+ move_dns_compat_bucket_to_subdomain(context)
33
+ @handler.call(context)
34
+ end
35
+
36
+ private
37
+
38
+ def move_dns_compat_bucket_to_subdomain(context)
39
+ bucket_name = context.params[:bucket]
40
+ endpoint = context.http_request.endpoint
41
+ if
42
+ bucket_name &&
43
+ BucketDns.dns_compatible?(bucket_name, https?(endpoint)) &&
44
+ context.operation_name != 'get_bucket_location'
45
+ then
46
+ move_bucket_to_subdomain(bucket_name, endpoint)
47
+ end
48
+ end
49
+
50
+ def move_bucket_to_subdomain(bucket_name, endpoint)
51
+ endpoint.host = "#{bucket_name}.#{endpoint.host}"
52
+ path = endpoint.path.sub("/#{bucket_name}", '')
53
+ path = "/#{path}" unless path.match(/^\//)
54
+ endpoint.path = path
55
+ end
56
+
57
+ def https?(uri)
58
+ uri.scheme == 'https'
59
+ end
60
+
61
+ end
62
+
63
+ class << self
64
+
65
+ # @param [String] bucket_name
66
+ # @param [Boolean] ssl
67
+ # @return [Boolean]
68
+ def dns_compatible?(bucket_name, ssl)
69
+ if valid_subdomain?(bucket_name)
70
+ bucket_name.match(/\./) && ssl ? false : true
71
+ else
72
+ false
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def valid_subdomain?(bucket_name)
79
+ bucket_name.size < 64 &&
80
+ bucket_name =~ /^[a-z0-9][a-z0-9.-]+[a-z0-9]$/ &&
81
+ bucket_name !~ /(\d+\.){3}\d+/ &&
82
+ bucket_name !~ /[.-]{2}/
83
+ end
84
+
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,23 @@
1
+ module Aws
2
+ module S3
3
+ module Plugins
4
+ # @api private
5
+ class BucketNameRestrictions < Seahorse::Client::Plugin
6
+ class Handler < Seahorse::Client::Handler
7
+
8
+ def call(context)
9
+ if context.params.key?(:bucket) && context.params[:bucket].include?('/')
10
+ msg = ":bucket option must not contain a forward-slash (/)"
11
+ raise ArgumentError, msg
12
+ end
13
+ @handler.call(context)
14
+ end
15
+
16
+ end
17
+
18
+ handler(Handler)
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,70 @@
1
+ module Aws
2
+ module S3
3
+ module Plugins
4
+ # @api private
5
+ class Dualstack < Seahorse::Client::Plugin
6
+
7
+ option(:use_dualstack_endpoint,
8
+ default: false,
9
+ doc_type: 'Boolean',
10
+ docstring: <<-DOCS)
11
+ When set to `true`, IPv6-compatible bucket endpoints will be used
12
+ for all operations.
13
+ DOCS
14
+
15
+ def add_handlers(handlers, config)
16
+ handlers.add(OptionHandler, step: :initialize)
17
+ handlers.add(DualstackHandler, step: :build, priority: 0)
18
+ end
19
+
20
+ # @api private
21
+ class OptionHandler < Seahorse::Client::Handler
22
+ def call(context)
23
+ dualstack = context.params.delete(:use_dualstack_endpoint)
24
+ dualstack = context.config.use_dualstack_endpoint if dualstack.nil?
25
+ context[:use_dualstack_endpoint] = dualstack
26
+ @handler.call(context)
27
+ end
28
+ end
29
+
30
+ # @api private
31
+ class DualstackHandler < Seahorse::Client::Handler
32
+ def call(context)
33
+ apply_dualstack_endpoint(context) if use_dualstack_endpoint?(context)
34
+ @handler.call(context)
35
+ end
36
+
37
+ private
38
+ def apply_dualstack_endpoint(context)
39
+ bucket_name = context.params[:bucket]
40
+ region = context.config.region
41
+ force_path_style = context.config.force_path_style
42
+ dns_suffix = Aws::Partitions::EndpointProvider.dns_suffix_for(region)
43
+
44
+ if use_bucket_dns?(bucket_name, context)
45
+ host = "#{bucket_name}.s3.dualstack.#{region}.#{dns_suffix}"
46
+ else
47
+ host = "s3.dualstack.#{region}.#{dns_suffix}"
48
+ end
49
+ endpoint = URI.parse(context.http_request.endpoint.to_s)
50
+ endpoint.scheme = context.http_request.endpoint.scheme
51
+ endpoint.port = context.http_request.endpoint.port
52
+ endpoint.host = host
53
+ context.http_request.endpoint = endpoint.to_s
54
+ end
55
+
56
+ def use_bucket_dns?(bucket_name, context)
57
+ ssl = context.http_request.endpoint.scheme == "https"
58
+ bucket_name && BucketDns.dns_compatible?(bucket_name, ssl) &&
59
+ !context.config.force_path_style
60
+ end
61
+
62
+ def use_dualstack_endpoint?(context)
63
+ context[:use_dualstack_endpoint] && !context[:use_accelerate_endpoint]
64
+ end
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,29 @@
1
+ module Aws
2
+ module S3
3
+ module Plugins
4
+ class Expect100Continue < Seahorse::Client::Plugin
5
+
6
+ def add_handlers(handlers, config)
7
+ if config.http_continue_timeout && config.http_continue_timeout > 0
8
+ handlers.add(Handler)
9
+ end
10
+ end
11
+
12
+ # @api private
13
+ class Handler < Seahorse::Client::Handler
14
+
15
+ def call(context)
16
+ if
17
+ context.http_request.body &&
18
+ context.http_request.body.size > 0
19
+ then
20
+ context.http_request.headers['expect'] = '100-continue'
21
+ end
22
+ @handler.call(context)
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ module Aws
2
+ module S3
3
+ module Plugins
4
+ class GetBucketLocationFix < Seahorse::Client::Plugin
5
+
6
+ class Handler < Seahorse::Client::Handler
7
+
8
+ def call(context)
9
+ @handler.call(context).on(200) do |response|
10
+ response.data = S3::Types::GetBucketLocationOutput.new
11
+ xml = context.http_response.body_contents
12
+ matches = xml.match(/>(.+?)<\/LocationConstraint>/)
13
+ response.data[:location_constraint] = matches ? matches[1] : ''
14
+ end
15
+ end
16
+ end
17
+
18
+ handler(Handler, priority: 60, operations: [:get_bucket_location])
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,47 @@
1
+ module Aws
2
+ module S3
3
+ module Plugins
4
+
5
+ # A handful of Amazon S3 operations will respond with a 200 status
6
+ # code but will send an error in the response body. This plugin
7
+ # injects a handler that will parse 200 response bodies for potential
8
+ # errors, allowing them to be retried.
9
+ # @api private
10
+ class Http200Errors < Seahorse::Client::Plugin
11
+
12
+ class Handler < Seahorse::Client::Handler
13
+
14
+ def call(context)
15
+ @handler.call(context).on(200) do |response|
16
+ if error = check_for_error(context)
17
+ context.http_response.status_code = 500
18
+ response.data = nil
19
+ response.error = error
20
+ end
21
+ end
22
+ end
23
+
24
+ def check_for_error(context)
25
+ xml = context.http_response.body_contents
26
+ if xml.match(/<Error>/)
27
+ error_code = xml.match(/<Code>(.+?)<\/Code>/)[1]
28
+ error_message = xml.match(/<Message>(.+?)<\/Message>/)[1]
29
+ S3::Errors.error_class(error_code).new(context, error_message)
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ handler(Handler,
36
+ step: :sign,
37
+ operations: [
38
+ :complete_multipart_upload,
39
+ :copy_object,
40
+ :upload_part_copy,
41
+ ]
42
+ )
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,33 @@
1
+ module Aws
2
+ module S3
3
+ module Plugins
4
+
5
+ # When making calls to {S3::Client#create_bucket} outside the
6
+ # "classic" region, the bucket location constraint must be specified.
7
+ # This plugin auto populates the constraint to the configured region.
8
+ class LocationConstraint < Seahorse::Client::Plugin
9
+
10
+ class Handler < Seahorse::Client::Handler
11
+
12
+ def call(context)
13
+ unless context.config.region == 'us-east-1'
14
+ populate_location_constraint(context.params, context.config.region)
15
+ end
16
+ @handler.call(context)
17
+ end
18
+
19
+ private
20
+
21
+ def populate_location_constraint(params, region)
22
+ params[:create_bucket_configuration] ||= {}
23
+ params[:create_bucket_configuration][:location_constraint] ||= region
24
+ end
25
+
26
+ end
27
+
28
+ handler(Handler, step: :initialize, operations: [:create_bucket])
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,79 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module Aws
5
+ module S3
6
+ module Plugins
7
+ class Md5s < Seahorse::Client::Plugin
8
+
9
+ # Amazon S3 requires these operations to have an MD5 checksum
10
+ REQUIRED_OPERATIONS = [
11
+ :delete_objects,
12
+ :put_bucket_cors,
13
+ :put_bucket_lifecycle,
14
+ :put_bucket_policy,
15
+ :put_bucket_tagging,
16
+ ]
17
+
18
+ # @api private
19
+ class Handler < Seahorse::Client::Handler
20
+
21
+ CHUNK_SIZE = 1 * 1024 * 1024 # one MB
22
+
23
+ def call(context)
24
+ body = context.http_request.body
25
+ if body.size > 0
26
+ context.http_request.headers['Content-Md5'] ||= md5(body)
27
+ end
28
+ @handler.call(context)
29
+ end
30
+
31
+ private
32
+
33
+ # @param [File, Tempfile, IO#read, String] value
34
+ # @return [String<MD5>]
35
+ def md5(value)
36
+ if (File === value || Tempfile === value) && !value.path.nil? && File.exist?(value.path)
37
+ Base64.encode64(OpenSSL::Digest::MD5.file(value).digest).strip
38
+ elsif value.respond_to?(:read)
39
+ md5 = OpenSSL::Digest::MD5.new
40
+ update_in_chunks(md5, value)
41
+ Base64.encode64(md5.digest).strip
42
+ else
43
+ Base64.encode64(OpenSSL::Digest::MD5.digest(value)).strip
44
+ end
45
+ end
46
+
47
+ def update_in_chunks(digest, io)
48
+ while chunk = io.read(CHUNK_SIZE)
49
+ digest.update(chunk)
50
+ end
51
+ io.rewind
52
+ end
53
+
54
+ end
55
+
56
+ option(:compute_checksums,
57
+ default: true,
58
+ doc_type: 'Boolean',
59
+ docstring: <<-DOCS)
60
+ When `true` a MD5 checksum will be computed for every request that
61
+ sends a body. When `false`, MD5 checksums will only be computed
62
+ for operations that require them. Checksum errors returned by Amazon
63
+ S3 are automatically retried up to `:retry_limit` times.
64
+ DOCS
65
+
66
+ def add_handlers(handlers, config)
67
+ # priority set low to ensure md5 is computed AFTER the request is
68
+ # built but before it is signed
69
+ handlers.add(Handler, {
70
+ priority: 10,
71
+ step: :build,
72
+ operations: config.compute_checksums ? nil : REQUIRED_OPERATIONS,
73
+ })
74
+ end
75
+
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,41 @@
1
+ module Aws
2
+ module S3
3
+ module Plugins
4
+ class Redirects < Seahorse::Client::Plugin
5
+
6
+ option(:follow_redirects,
7
+ default: true,
8
+ doc_type: 'Boolean',
9
+ docstring: <<-DOCS)
10
+ When `true`, this client will follow 307 redirects returned
11
+ by Amazon S3.
12
+ DOCS
13
+
14
+ # @api private
15
+ class Handler < Seahorse::Client::Handler
16
+
17
+ def call(context)
18
+ response = @handler.call(context)
19
+ if context.http_response.status_code == 307
20
+ endpoint = context.http_response.headers['location']
21
+ context.http_request.endpoint = endpoint
22
+ context.http_response.body.truncate(0)
23
+ @handler.call(context)
24
+ else
25
+ response
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ def add_handlers(handlers, config)
32
+ if config.follow_redirects
33
+ # we want to re-trigger request signing
34
+ handlers.add(Handler, step: :sign, priority: 90)
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,208 @@
1
+ require 'aws-sigv4'
2
+
3
+ module Aws
4
+ module S3
5
+ module Plugins
6
+ # This plugin is an implementation detail and may be modified.
7
+ # @api private
8
+ class S3Signer < Seahorse::Client::Plugin
9
+
10
+ option(:signature_version, 'v4')
11
+
12
+ option(:sigv4_signer) do |cfg|
13
+ S3Signer.build_v4_signer(
14
+ region: cfg.sigv4_region,
15
+ credentials: cfg.credentials
16
+ )
17
+ end
18
+
19
+ option(:sigv4_region) do |cfg|
20
+ Aws::Partitions::EndpointProvider.signing_region(cfg.region, 's3')
21
+ end
22
+
23
+ def add_handlers(handlers, cfg)
24
+ case cfg.signature_version
25
+ when 'v4' then add_v4_handlers(handlers)
26
+ when 's3' then add_legacy_handler(handlers)
27
+ else
28
+ msg = "unsupported signature version `#{cfg.signature_version}'"
29
+ raise ArgumentError, msg
30
+ end
31
+ end
32
+
33
+ def add_v4_handlers(handlers)
34
+ handlers.add(CachedBucketRegionHandler, step: :sign, priority: 60)
35
+ handlers.add(V4Handler, step: :sign)
36
+ handlers.add(BucketRegionErrorHandler, step: :sign, priority: 40)
37
+ end
38
+
39
+ def add_legacy_handler(handlers)
40
+ handlers.add(LegacyHandler, step: :sign)
41
+ end
42
+
43
+ class LegacyHandler < Seahorse::Client::Handler
44
+ def call(context)
45
+ LegacySigner.sign(context)
46
+ @handler.call(context)
47
+ end
48
+ end
49
+
50
+ class V4Handler < Seahorse::Client::Handler
51
+
52
+ def call(context)
53
+ Aws::Plugins::SignatureV4.apply_signature(
54
+ context: context,
55
+ signer: sigv4_signer(context)
56
+ )
57
+ @handler.call(context)
58
+ end
59
+
60
+ private
61
+
62
+ def sigv4_signer(context)
63
+ # If the client was configured with the wrong region,
64
+ # we have to build a new signer.
65
+ if
66
+ context[:cached_sigv4_region] &&
67
+ context[:cached_sigv4_region] != context.config.sigv4_signer.region
68
+ then
69
+ S3Signer.build_v4_signer(
70
+ region: context[:cached_sigv4_region],
71
+ credentials: context.config.credentials
72
+ )
73
+ else
74
+ context.config.sigv4_signer
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ # This handler will update the http endpoint when the bucket region
81
+ # is known/cached.
82
+ class CachedBucketRegionHandler < Seahorse::Client::Handler
83
+
84
+ def call(context)
85
+ bucket = context.params[:bucket]
86
+ check_for_cached_region(context, bucket) if bucket
87
+ @handler.call(context)
88
+ end
89
+
90
+ private
91
+
92
+ def check_for_cached_region(context, bucket)
93
+ cached_region = S3::BUCKET_REGIONS[bucket]
94
+ if cached_region && cached_region != context.config.region
95
+ context.http_request.endpoint.host = S3Signer.new_hostname(context, cached_region)
96
+ context[:cached_sigv4_region] = cached_region
97
+ end
98
+ end
99
+
100
+ end
101
+
102
+ # This handler detects when a request fails because of a mismatched bucket
103
+ # region. It follows up by making a request to determine the correct
104
+ # region, then finally a version 4 signed request against the correct
105
+ # regional endpoint.
106
+ class BucketRegionErrorHandler < Seahorse::Client::Handler
107
+
108
+ def call(context)
109
+ response = @handler.call(context)
110
+ handle_region_errors(response)
111
+ end
112
+
113
+ private
114
+
115
+ def handle_region_errors(response)
116
+ if wrong_sigv4_region?(response)
117
+ get_region_and_retry(response.context)
118
+ else
119
+ response
120
+ end
121
+ end
122
+
123
+ def get_region_and_retry(context)
124
+ actual_region = context.http_response.headers['x-amz-bucket-region']
125
+ actual_region ||= region_from_body(context.http_response.body_contents)
126
+ update_bucket_cache(context, actual_region)
127
+ log_warning(context, actual_region)
128
+ resign_with_new_region(context, actual_region)
129
+ @handler.call(context)
130
+ end
131
+
132
+ def update_bucket_cache(context, actual_region)
133
+ S3::BUCKET_REGIONS[context.params[:bucket]] = actual_region
134
+ end
135
+
136
+ def wrong_sigv4_region?(resp)
137
+ resp.context.http_response.status_code == 400 &&
138
+ (
139
+ resp.context.http_response.headers['x-amz-bucket-region'] ||
140
+ resp.context.http_response.body_contents.match(/<Region>.+?<\/Region>/)
141
+ )
142
+ end
143
+
144
+ def resign_with_new_region(context, actual_region)
145
+ context.http_response.body.truncate(0)
146
+ context.http_request.endpoint.host = S3Signer.new_hostname(context, actual_region)
147
+ Aws::Plugins::SignatureV4.apply_signature(
148
+ context: context,
149
+ signer: S3Signer.build_v4_signer(
150
+ region: actual_region,
151
+ credentials: context.config.credentials
152
+ )
153
+ )
154
+ end
155
+
156
+ def region_from_body(body)
157
+ region = body.match(/<Region>(.+?)<\/Region>/)[1]
158
+ if region.nil? || region == ""
159
+ raise "couldn't get region from body: #{body}"
160
+ else
161
+ region
162
+ end
163
+ end
164
+
165
+ def log_warning(context, actual_region)
166
+ msg = "S3 client configured for #{context.config.region.inspect} " +
167
+ "but the bucket #{context.params[:bucket].inspect} is in " +
168
+ "#{actual_region.inspect}; Please configure the proper region " +
169
+ "to avoid multiple unnecessary redirects and signing attempts\n"
170
+ if logger = context.config.logger
171
+ logger.warn(msg)
172
+ else
173
+ warn(msg)
174
+ end
175
+ end
176
+
177
+ end
178
+
179
+ class << self
180
+
181
+ # @option options [required, String] :region
182
+ # @option options [required, #credentials] :credentials
183
+ # @api private
184
+ def build_v4_signer(options = {})
185
+ Aws::Sigv4::Signer.new({
186
+ service: 's3',
187
+ region: options[:region],
188
+ credentials_provider: options[:credentials],
189
+ uri_escape_path: false,
190
+ unsigned_headers: ['content-length'],
191
+ })
192
+ end
193
+
194
+ def new_hostname(context, region)
195
+ bucket = context.params[:bucket]
196
+ if region == 'us-east-1'
197
+ "#{bucket}.s3.amazonaws.com"
198
+ else
199
+ endpoint = Aws::Partitions::EndpointProvider.resolve(region, 's3')
200
+ bucket + '.' + URI.parse(endpoint).host
201
+ end
202
+ end
203
+
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end