aws-sdk-s3 1.114.0 → 1.119.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-s3/bucket.rb +1 -1
  5. data/lib/aws-sdk-s3/client.rb +169 -152
  6. data/lib/aws-sdk-s3/client_api.rb +189 -189
  7. data/lib/aws-sdk-s3/customizations/bucket.rb +20 -46
  8. data/lib/aws-sdk-s3/customizations/object.rb +4 -1
  9. data/lib/aws-sdk-s3/endpoint_parameters.rb +142 -0
  10. data/lib/aws-sdk-s3/endpoint_provider.rb +733 -0
  11. data/lib/aws-sdk-s3/endpoints.rb +2149 -0
  12. data/lib/aws-sdk-s3/multipart_stream_uploader.rb +36 -10
  13. data/lib/aws-sdk-s3/object_multipart_copier.rb +11 -5
  14. data/lib/aws-sdk-s3/plugins/accelerate.rb +3 -50
  15. data/lib/aws-sdk-s3/plugins/arn.rb +0 -184
  16. data/lib/aws-sdk-s3/plugins/bucket_dns.rb +3 -39
  17. data/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb +1 -6
  18. data/lib/aws-sdk-s3/plugins/dualstack.rb +1 -49
  19. data/lib/aws-sdk-s3/plugins/endpoints.rb +262 -0
  20. data/lib/aws-sdk-s3/plugins/expect_100_continue.rb +2 -1
  21. data/lib/aws-sdk-s3/plugins/iad_regional_endpoint.rb +0 -29
  22. data/lib/aws-sdk-s3/plugins/s3_signer.rb +27 -123
  23. data/lib/aws-sdk-s3/presigned_post.rb +9 -16
  24. data/lib/aws-sdk-s3/presigner.rb +20 -33
  25. data/lib/aws-sdk-s3/resource.rb +1 -1
  26. data/lib/aws-sdk-s3/types.rb +0 -3636
  27. data/lib/aws-sdk-s3.rb +5 -1
  28. metadata +8 -9
  29. data/lib/aws-sdk-s3/arn/access_point_arn.rb +0 -69
  30. data/lib/aws-sdk-s3/arn/multi_region_access_point_arn.rb +0 -68
  31. data/lib/aws-sdk-s3/arn/object_lambda_arn.rb +0 -69
  32. data/lib/aws-sdk-s3/arn/outpost_access_point_arn.rb +0 -74
  33. data/lib/aws-sdk-s3/plugins/object_lambda_endpoint.rb +0 -25
@@ -26,6 +26,10 @@ module Aws
26
26
  UPLOAD_PART_OPTIONS =
27
27
  Set.new(Client.api.operation(:upload_part).input.shape.member_names)
28
28
 
29
+ # @api private
30
+ COMPLETE_UPLOAD_OPTIONS =
31
+ Set.new(Client.api.operation(:complete_multipart_upload).input.shape.member_names)
32
+
29
33
  # @option options [Client] :client
30
34
  def initialize(options = {})
31
35
  @client = options[:client] || Client.new
@@ -39,7 +43,7 @@ module Aws
39
43
 
40
44
  # @option options [required,String] :bucket
41
45
  # @option options [required,String] :key
42
- # @return [void]
46
+ # @return [Seahorse::Client::Response] - the CompleteMultipartUploadResponse
43
47
  def upload(options = {}, &block)
44
48
  upload_id = initiate_upload(options)
45
49
  parts = upload_parts(upload_id, options, &block)
@@ -54,17 +58,22 @@ module Aws
54
58
 
55
59
  def complete_upload(upload_id, parts, options)
56
60
  @client.complete_multipart_upload(
57
- bucket: options[:bucket],
58
- key: options[:key],
59
- upload_id: upload_id,
60
- multipart_upload: { parts: parts })
61
+ **complete_opts(options).merge(
62
+ upload_id: upload_id,
63
+ multipart_upload: { parts: parts }
64
+ )
65
+ )
61
66
  end
62
67
 
63
68
  def upload_parts(upload_id, options, &block)
64
69
  completed = Queue.new
70
+ thread_errors = []
65
71
  errors = begin
66
72
  IO.pipe do |read_pipe, write_pipe|
67
- threads = upload_in_threads(read_pipe, completed, upload_part_opts(options).merge(upload_id: upload_id))
73
+ threads = upload_in_threads(
74
+ read_pipe, completed,
75
+ upload_part_opts(options).merge(upload_id: upload_id),
76
+ thread_errors)
68
77
  begin
69
78
  block.call(write_pipe)
70
79
  ensure
@@ -74,7 +83,7 @@ module Aws
74
83
  threads.map(&:value).compact
75
84
  end
76
85
  rescue => e
77
- [e]
86
+ thread_errors + [e]
78
87
  end
79
88
 
80
89
  if errors.empty?
@@ -113,6 +122,13 @@ module Aws
113
122
  end
114
123
  end
115
124
 
125
+ def complete_opts(options)
126
+ COMPLETE_UPLOAD_OPTIONS.inject({}) do |hash, key|
127
+ hash[key] = options[key] if options.key?(key)
128
+ hash
129
+ end
130
+ end
131
+
116
132
  def read_to_part_body(read_pipe)
117
133
  return if read_pipe.closed?
118
134
  temp_io = @tempfile ? Tempfile.new(TEMPFILE_PREIX) : StringIO.new(String.new)
@@ -130,7 +146,7 @@ module Aws
130
146
  end
131
147
  end
132
148
 
133
- def upload_in_threads(read_pipe, completed, options)
149
+ def upload_in_threads(read_pipe, completed, options, thread_errors)
134
150
  mutex = Mutex.new
135
151
  part_number = 0
136
152
  @thread_count.times.map do
@@ -147,7 +163,14 @@ module Aws
147
163
  part_number: thread_part_number,
148
164
  )
149
165
  resp = @client.upload_part(part)
150
- completed << {etag: resp.etag, part_number: part[:part_number]}
166
+ completed_part = {etag: resp.etag, part_number: part[:part_number]}
167
+
168
+ # get the requested checksum from the response
169
+ if part[:checksum_algorithm]
170
+ k = "checksum_#{part[:checksum_algorithm].downcase}".to_sym
171
+ completed_part[k] = resp[k]
172
+ end
173
+ completed.push(completed_part)
151
174
  ensure
152
175
  if Tempfile === body
153
176
  body.close
@@ -160,7 +183,10 @@ module Aws
160
183
  nil
161
184
  rescue => error
162
185
  # keep other threads from uploading other parts
163
- mutex.synchronize { read_pipe.close_read unless read_pipe.closed? }
186
+ mutex.synchronize do
187
+ thread_errors.push(error)
188
+ read_pipe.close_read unless read_pipe.closed?
189
+ end
164
190
  error
165
191
  end
166
192
  end
@@ -24,6 +24,9 @@ module Aws
24
24
  @thread_count = options.delete(:thread_count) || 10
25
25
  @min_part_size = options.delete(:min_part_size) || (FIVE_MB * 10)
26
26
  @client = options[:client] || Client.new
27
+ if options[:checksum_algorithm]
28
+ raise ArgumentError, 'Multipart Copy does not support setting :checksum_algorithm'
29
+ end
27
30
  end
28
31
 
29
32
  # @return [Client]
@@ -31,8 +34,9 @@ module Aws
31
34
 
32
35
  # @option (see S3::Client#copy_object)
33
36
  def copy(options = {})
34
- size = source_size(options)
35
- options[:upload_id] = initiate_upload(options)
37
+ metadata = source_metadata(options)
38
+ size = metadata[:content_length]
39
+ options[:upload_id] = initiate_upload(metadata.merge(options))
36
40
  begin
37
41
  parts = copy_parts(size, default_part_size(size), options)
38
42
  complete_upload(parts, options)
@@ -118,8 +122,10 @@ module Aws
118
122
  end
119
123
  end
120
124
 
121
- def source_size(options)
122
- return options.delete(:content_length) if options[:content_length]
125
+ def source_metadata(options)
126
+ if options[:content_length]
127
+ return { content_length: options.delete(:content_length) }
128
+ end
123
129
 
124
130
  client = options[:copy_source_client] || @client
125
131
 
@@ -132,7 +138,7 @@ module Aws
132
138
  key = CGI.unescape(key)
133
139
  opts = { bucket: bucket, key: key }
134
140
  opts[:version_id] = version_id if version_id
135
- client.head_object(opts).content_length
141
+ client.head_object(opts).to_h
136
142
  end
137
143
 
138
144
  def default_part_size(source_size)
@@ -23,73 +23,26 @@ each bucket. [Go here for more information](http://docs.aws.amazon.com/AmazonS3/
23
23
  operations = config.api.operation_names - [
24
24
  :create_bucket, :list_buckets, :delete_bucket
25
25
  ]
26
- # Need 2 handlers so that the context can be set for other plugins
27
- # and to remove :use_accelerate_endpoint from the params.
28
26
  handlers.add(
29
27
  OptionHandler, step: :initialize, operations: operations
30
28
  )
31
- handlers.add(
32
- AccelerateHandler, step: :build, priority: 11, operations: operations
33
- )
34
29
  end
35
30
 
36
31
  # @api private
37
32
  class OptionHandler < Seahorse::Client::Handler
38
33
  def call(context)
39
34
  # Support client configuration and per-operation configuration
35
+ # TODO: move this to an options hash and warn here.
40
36
  if context.params.is_a?(Hash)
41
37
  accelerate = context.params.delete(:use_accelerate_endpoint)
42
38
  end
43
- accelerate = context.config.use_accelerate_endpoint if accelerate.nil?
44
- # Raise if :endpoint and accelerate are both provided
45
- if accelerate && !context.config.regional_endpoint
46
- raise ArgumentError,
47
- 'Cannot use both :use_accelerate_endpoint and :endpoint'
48
- end
49
- # Raise if :use_fips_endpoint and accelerate are both provided
50
- if accelerate && context.config.use_fips_endpoint
51
- raise ArgumentError,
52
- 'Cannot use both :use_accelerate_endpoint and '\
53
- ':use_fips_endpoint'
39
+ if accelerate.nil?
40
+ accelerate = context.config.use_accelerate_endpoint
54
41
  end
55
42
  context[:use_accelerate_endpoint] = accelerate
56
43
  @handler.call(context)
57
44
  end
58
45
  end
59
-
60
- # @api private
61
- class AccelerateHandler < Seahorse::Client::Handler
62
- def call(context)
63
- if context.config.regional_endpoint && context[:use_accelerate_endpoint]
64
- dualstack = !!context[:use_dualstack_endpoint]
65
- use_accelerate_endpoint(context, dualstack)
66
- end
67
- @handler.call(context)
68
- end
69
-
70
- private
71
-
72
- def use_accelerate_endpoint(context, dualstack)
73
- bucket_name = context.params[:bucket]
74
- validate_bucket_name!(bucket_name)
75
- endpoint = URI.parse(context.http_request.endpoint.to_s)
76
- endpoint.scheme = 'https'
77
- endpoint.port = 443
78
- endpoint.host = "#{bucket_name}.s3-accelerate"\
79
- "#{'.dualstack' if dualstack}.amazonaws.com"
80
- context.http_request.endpoint = endpoint.to_s
81
- # s3 accelerate endpoint doesn't work with 'expect' header
82
- context.http_request.headers.delete('expect')
83
- end
84
-
85
- def validate_bucket_name!(bucket_name)
86
- unless BucketDns.dns_compatible?(bucket_name, _ssl = true)
87
- raise ArgumentError,
88
- 'Unable to use `use_accelerate_endpoint: true` on buckets '\
89
- 'with non-DNS compatible names.'
90
- end
91
- end
92
- end
93
46
  end
94
47
  end
95
48
  end
@@ -1,10 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../arn/access_point_arn'
4
- require_relative '../arn/object_lambda_arn'
5
- require_relative '../arn/outpost_access_point_arn'
6
- require_relative '../arn/multi_region_access_point_arn'
7
-
8
3
  module Aws
9
4
  module S3
10
5
  module Plugins
@@ -36,150 +31,9 @@ result in cross region requests.
36
31
  resolve_s3_disable_multiregion_access_points(cfg)
37
32
  end
38
33
 
39
- # param validator is validate:50
40
- # endpoint is build:90 (populates the URI for the first time)
41
- # endpoint pattern is build:10
42
- def add_handlers(handlers, _config)
43
- handlers.add(ARNHandler, step: :validate, priority: 75)
44
- handlers.add(UrlHandler)
45
- end
46
-
47
- # After extracting out any ARN input, resolve a new URL with it.
48
- class UrlHandler < Seahorse::Client::Handler
49
- def call(context)
50
- if context.metadata[:s3_arn]
51
- ARN.resolve_url!(
52
- context.http_request.endpoint,
53
- context.metadata[:s3_arn][:arn],
54
- context.metadata[:s3_arn][:resolved_region],
55
- context.metadata[:s3_arn][:fips],
56
- context.metadata[:s3_arn][:dualstack],
57
- # if regional_endpoint is false, a custom endpoint was provided
58
- # in this case, we want to prefix the endpoint using the ARN
59
- !context.config.regional_endpoint
60
- )
61
- end
62
- @handler.call(context)
63
- end
64
- end
65
-
66
- # This plugin will extract out any ARN input and set context for other
67
- # plugins to use without having to translate the ARN again.
68
- class ARNHandler < Seahorse::Client::Handler
69
- def call(context)
70
- bucket_member = _bucket_member(context.operation.input.shape)
71
- if bucket_member && (bucket = context.params[bucket_member])
72
- resolved_region, arn = ARN.resolve_arn!(
73
- bucket,
74
- context.config.region,
75
- context.config.s3_use_arn_region
76
- )
77
- if arn
78
- validate_config!(context, arn)
79
-
80
- context.metadata[:s3_arn] = {
81
- arn: arn,
82
- resolved_region: resolved_region,
83
- fips: context.config.use_fips_endpoint,
84
- dualstack: extract_dualstack_config!(context)
85
- }
86
- end
87
- end
88
- @handler.call(context)
89
- end
90
-
91
- private
92
-
93
- def _bucket_member(input)
94
- input.members.each do |member, ref|
95
- return member if ref.shape.name == 'BucketName'
96
- end
97
- nil
98
- end
99
-
100
- # other plugins use dualstack so disable it when we're done
101
- def extract_dualstack_config!(context)
102
- dualstack = context[:use_dualstack_endpoint]
103
- context[:use_dualstack_endpoint] = false if dualstack
104
- dualstack
105
- end
106
-
107
- def validate_config!(context, arn)
108
- if context.config.force_path_style
109
- raise ArgumentError,
110
- 'Cannot provide an Access Point ARN when '\
111
- '`:force_path_style` is set to true.'
112
- end
113
-
114
- if context.config.use_accelerate_endpoint
115
- raise ArgumentError,
116
- 'Cannot provide an Access Point ARN when '\
117
- '`:use_accelerate_endpoint` is set to true.'
118
- end
119
-
120
- if !arn.support_dualstack? && context[:use_dualstack_endpoint]
121
- raise ArgumentError,
122
- 'Cannot provide an Outpost Access Point, Object Lambda, '\
123
- 'or Multi-region Access Point ARN'\
124
- ' when `:use_dualstack_endpoint` is set to true.'
125
- end
126
-
127
- if arn.region.empty? && context.config.s3_disable_multiregion_access_points
128
- raise ArgumentError,
129
- 'Cannot provide a Multi-region Access Point ARN with '\
130
- '`:s3_disable_multiregion_access_points` set to true'
131
- end
132
-
133
- if context.config.use_fips_endpoint && !arn.support_fips?
134
- raise ArgumentError,
135
- 'FIPS client regions are not supported for this type '\
136
- 'of ARN.'
137
- end
138
- end
139
- end
140
-
141
34
  class << self
142
- # @api private
143
- def resolve_arn!(member_value, region, use_arn_region)
144
- if Aws::ARNParser.arn?(member_value)
145
- arn = Aws::ARNParser.parse(member_value)
146
- s3_arn = resolve_arn_type!(arn)
147
- s3_arn.validate_arn!
148
- validate_region_config!(s3_arn, region, use_arn_region)
149
- region = s3_arn.region if use_arn_region
150
- [region, s3_arn]
151
- else
152
- [region]
153
- end
154
- end
155
-
156
- # @api private
157
- def resolve_url!(url, arn, region, fips = false, dualstack = false, has_custom_endpoint = false)
158
- custom_endpoint = url.host if has_custom_endpoint
159
- url.host = arn.host_url(region, fips, dualstack, custom_endpoint)
160
- url.path = url_path(url.path, arn)
161
- url
162
- end
163
-
164
35
  private
165
36
 
166
- def resolve_arn_type!(arn)
167
- case arn.service
168
- when 's3'
169
- arn.region.empty? ?
170
- Aws::S3::MultiRegionAccessPointARN.new(arn.to_h) :
171
- Aws::S3::AccessPointARN.new(arn.to_h)
172
- when 's3-outposts'
173
- Aws::S3::OutpostAccessPointARN.new(arn.to_h)
174
- when 's3-object-lambda'
175
- Aws::S3::ObjectLambdaARN.new(arn.to_h)
176
- else
177
- raise ArgumentError,
178
- 'Only Access Point, Outposts, and Object Lambdas ARNs '\
179
- 'are currently supported.'
180
- end
181
- end
182
-
183
37
  def resolve_s3_use_arn_region(cfg)
184
38
  value = ENV['AWS_S3_USE_ARN_REGION'] ||
185
39
  Aws.shared_config.s3_use_arn_region(profile: cfg.profile) ||
@@ -209,44 +63,6 @@ result in cross region requests.
209
63
  end
210
64
  value
211
65
  end
212
-
213
- # Remove ARN from the path because we've already set the new host
214
- def url_path(path, arn)
215
- path = path.sub("/#{Seahorse::Util.uri_escape(arn.to_s)}", '')
216
- .sub("/#{arn}", '')
217
- "/#{path}" unless path =~ /^\//
218
- path
219
- end
220
-
221
- def validate_region_config!(arn, region, use_arn_region)
222
- if ['s3-external-1', 'aws-global'].include?(region)
223
- # These "regions" are not regional endpoints
224
- unless use_arn_region
225
- raise Aws::Errors::InvalidARNRegionError,
226
- 'Configured client region is not a regional endpoint.'
227
- end
228
- # These "regions" are in the AWS partition
229
- # Cannot use ARN region unless it's the same partition
230
- unless arn.partition == 'aws'
231
- raise Aws::Errors::InvalidARNPartitionError
232
- end
233
- else
234
- # use_arn_region does not apply to MRAP (global) arns
235
- unless arn.region.empty?
236
- # Raise if the ARN and client regions are in different partitions
237
- if use_arn_region &&
238
- !Aws::Partitions.partition(arn.partition).region?(region)
239
- raise Aws::Errors::InvalidARNPartitionError
240
- end
241
-
242
- # Raise if regions mismatch
243
- # Either when it's a fips client or not using the ARN region
244
- if !use_arn_region && region != arn.region
245
- raise Aws::Errors::InvalidARNRegionError
246
- end
247
- end
248
- end
249
- end
250
66
  end
251
67
  end
252
68
  end
@@ -23,45 +23,10 @@ When set to `true`, the bucket name is always left in the
23
23
  request URI and never moved to the host as a sub-domain.
24
24
  DOCS
25
25
 
26
- def add_handlers(handlers, config)
27
- handlers.add(Handler, priority: 48) unless config.force_path_style
28
- end
29
-
30
- # @api private
31
- class Handler < Seahorse::Client::Handler
32
-
33
- def call(context)
34
- move_dns_compat_bucket_to_subdomain(context)
35
- @handler.call(context)
36
- end
37
-
38
- private
39
-
40
- def move_dns_compat_bucket_to_subdomain(context)
41
- bucket_name = context.params[:bucket]
42
- endpoint = context.http_request.endpoint
43
- if bucket_name &&
44
- BucketDns.dns_compatible?(bucket_name, https?(endpoint)) &&
45
- context.operation_name.to_s != 'get_bucket_location'
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
-
26
+ # These class methods were originally used in a handler in this plugin.
27
+ # SigV2 legacy signer needs this logic so we keep it here as utility.
28
+ # New endpoint resolution will check this as a matcher.
63
29
  class << self
64
-
65
30
  # @param [String] bucket_name
66
31
  # @param [Boolean] ssl
67
32
  # @return [Boolean]
@@ -81,7 +46,6 @@ request URI and never moved to the host as a sub-domain.
81
46
  bucket_name !~ /(\d+\.){3}\d+/ &&
82
47
  bucket_name !~ /[.-]{2}/
83
48
  end
84
-
85
49
  end
86
50
  end
87
51
  end
@@ -13,12 +13,7 @@ module Aws
13
13
  def call(context)
14
14
  bucket_member = _bucket_member(context.operation.input.shape)
15
15
  if bucket_member && (bucket = context.params[bucket_member])
16
- _resolved_region, arn = ARN.resolve_arn!(
17
- bucket,
18
- context.config.region,
19
- context.config.s3_use_arn_region
20
- )
21
- if !arn && bucket.include?('/')
16
+ if !Aws::ARNParser.arn?(bucket) && bucket.include?('/')
22
17
  raise ArgumentError,
23
18
  'bucket name must not contain a forward-slash (/)'
24
19
  end
@@ -5,9 +5,8 @@ module Aws
5
5
  module Plugins
6
6
  # @api private
7
7
  class Dualstack < Seahorse::Client::Plugin
8
- def add_handlers(handlers, config)
8
+ def add_handlers(handlers, _config)
9
9
  handlers.add(OptionHandler, step: :initialize)
10
- handlers.add(DualstackHandler, step: :build, priority: 49)
11
10
  end
12
11
 
13
12
  # @api private
@@ -18,57 +17,10 @@ module Aws
18
17
  dualstack = context.params.delete(:use_dualstack_endpoint)
19
18
  end
20
19
  dualstack = context.config.use_dualstack_endpoint if dualstack.nil?
21
- # Raise if :endpoint and dualstack are both provided
22
- if dualstack && !context.config.regional_endpoint
23
- raise ArgumentError,
24
- 'Cannot use both :use_dualstack_endpoint and :endpoint'
25
- end
26
20
  context[:use_dualstack_endpoint] = dualstack
27
21
  @handler.call(context)
28
22
  end
29
23
  end
30
-
31
- # @api private
32
- class DualstackHandler < Seahorse::Client::Handler
33
- def call(context)
34
- # only rewrite the endpoint if it's not a custom endpoint
35
- # accelerate/ARN already handle dualstack cases, so ignore these
36
- # check to see if dualstack is on but configured off via operation
37
- if context.config.regional_endpoint &&
38
- use_dualstack_endpoint?(context)
39
- apply_dualstack_endpoint(context)
40
- end
41
- @handler.call(context)
42
- end
43
-
44
- private
45
-
46
- def apply_dualstack_endpoint(context)
47
- new_endpoint = Aws::Partitions::EndpointProvider.resolve(
48
- context.config.region,
49
- 's3',
50
- 'regional',
51
- {
52
- dualstack: context[:use_dualstack_endpoint],
53
- fips: context.config.use_fips_endpoint
54
- }
55
- )
56
- endpoint = URI.parse(context.http_request.endpoint.to_s)
57
- endpoint.host = URI.parse(new_endpoint).host
58
- context.http_request.endpoint = endpoint
59
- end
60
-
61
- def use_dualstack_endpoint?(context)
62
- # case when dualstack is turned off via operation
63
- (context[:use_dualstack_endpoint] ||
64
- context.config.use_dualstack_endpoint) &&
65
- # accelerate plugin already applies dualstack
66
- !context[:use_accelerate_endpoint] &&
67
- # arns handle dualstack
68
- !context.metadata[:s3_arn]
69
- end
70
- end
71
-
72
24
  end
73
25
  end
74
26
  end