aws-sdk-core 3.105.0 → 3.130.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1304 -0
  3. data/LICENSE.txt +202 -0
  4. data/VERSION +1 -1
  5. data/lib/aws-defaults/default_configuration.rb +153 -0
  6. data/lib/aws-defaults/defaults_mode_config_resolver.rb +107 -0
  7. data/lib/aws-defaults.rb +3 -0
  8. data/lib/aws-sdk-core/arn.rb +13 -0
  9. data/lib/aws-sdk-core/assume_role_credentials.rb +20 -1
  10. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +9 -4
  11. data/lib/aws-sdk-core/client_stubs.rb +5 -1
  12. data/lib/aws-sdk-core/credential_provider_chain.rb +2 -1
  13. data/lib/aws-sdk-core/ec2_metadata.rb +238 -0
  14. data/lib/aws-sdk-core/ecs_credentials.rb +5 -0
  15. data/lib/aws-sdk-core/errors.rb +6 -2
  16. data/lib/aws-sdk-core/instance_profile_credentials.rb +119 -18
  17. data/lib/aws-sdk-core/json/json_engine.rb +10 -8
  18. data/lib/aws-sdk-core/json/oj_engine.rb +33 -6
  19. data/lib/aws-sdk-core/json/parser.rb +8 -0
  20. data/lib/aws-sdk-core/json.rb +8 -26
  21. data/lib/aws-sdk-core/log/formatter.rb +1 -1
  22. data/lib/aws-sdk-core/log/param_filter.rb +9 -1
  23. data/lib/aws-sdk-core/pageable_response.rb +72 -26
  24. data/lib/aws-sdk-core/pager.rb +3 -0
  25. data/lib/aws-sdk-core/param_validator.rb +29 -0
  26. data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +340 -0
  27. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +3 -1
  28. data/lib/aws-sdk-core/plugins/defaults_mode.rb +40 -0
  29. data/lib/aws-sdk-core/plugins/endpoint_pattern.rb +6 -6
  30. data/lib/aws-sdk-core/plugins/http_checksum.rb +8 -1
  31. data/lib/aws-sdk-core/plugins/protocols/api_gateway.rb +17 -0
  32. data/lib/aws-sdk-core/plugins/protocols/rest_json.rb +16 -1
  33. data/lib/aws-sdk-core/plugins/recursion_detection.rb +27 -0
  34. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +48 -2
  35. data/lib/aws-sdk-core/plugins/response_paging.rb +1 -1
  36. data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +5 -3
  37. data/lib/aws-sdk-core/plugins/retry_errors.rb +25 -8
  38. data/lib/aws-sdk-core/plugins/signature_v4.rb +15 -24
  39. data/lib/aws-sdk-core/plugins/stub_responses.rb +5 -1
  40. data/lib/aws-sdk-core/process_credentials.rb +3 -2
  41. data/lib/aws-sdk-core/refreshing_credentials.rb +42 -11
  42. data/lib/aws-sdk-core/rest/request/body.rb +19 -1
  43. data/lib/aws-sdk-core/rest/request/headers.rb +18 -6
  44. data/lib/aws-sdk-core/rest/response/headers.rb +3 -1
  45. data/lib/aws-sdk-core/shared_config.rb +28 -8
  46. data/lib/aws-sdk-core/shared_credentials.rb +7 -1
  47. data/lib/aws-sdk-core/sso_credentials.rb +35 -10
  48. data/lib/aws-sdk-core/structure.rb +10 -1
  49. data/lib/aws-sdk-core/stubbing/protocols/json.rb +1 -1
  50. data/lib/aws-sdk-core/stubbing/protocols/rest_json.rb +1 -1
  51. data/lib/aws-sdk-core/stubbing/protocols/rest_xml.rb +0 -2
  52. data/lib/aws-sdk-core/xml/builder.rb +2 -2
  53. data/lib/aws-sdk-core/xml/doc_builder.rb +6 -1
  54. data/lib/aws-sdk-core/xml/parser/engines/ox.rb +1 -1
  55. data/lib/aws-sdk-core/xml/parser/frame.rb +23 -0
  56. data/lib/aws-sdk-core/xml/parser.rb +5 -0
  57. data/lib/aws-sdk-core.rb +11 -3
  58. data/lib/aws-sdk-sso/client.rb +28 -6
  59. data/lib/aws-sdk-sso/client_api.rb +1 -1
  60. data/lib/aws-sdk-sso/errors.rb +1 -1
  61. data/lib/aws-sdk-sso/resource.rb +1 -1
  62. data/lib/aws-sdk-sso/types.rb +1 -1
  63. data/lib/aws-sdk-sso.rb +7 -4
  64. data/lib/aws-sdk-sts/client.rb +515 -429
  65. data/lib/aws-sdk-sts/client_api.rb +7 -1
  66. data/lib/aws-sdk-sts/errors.rb +1 -1
  67. data/lib/aws-sdk-sts/plugins/sts_regional_endpoints.rb +5 -1
  68. data/lib/aws-sdk-sts/presigner.rb +7 -1
  69. data/lib/aws-sdk-sts/resource.rb +1 -1
  70. data/lib/aws-sdk-sts/types.rb +332 -193
  71. data/lib/aws-sdk-sts.rb +7 -2
  72. data/lib/seahorse/client/configuration.rb +4 -0
  73. data/lib/seahorse/client/h2/connection.rb +15 -13
  74. data/lib/seahorse/client/h2/handler.rb +4 -5
  75. data/lib/seahorse/client/net_http/connection_pool.rb +7 -0
  76. data/lib/seahorse/client/net_http/handler.rb +17 -8
  77. data/lib/seahorse/client/net_http/patches.rb +13 -84
  78. data/lib/seahorse/client/plugins/content_length.rb +11 -5
  79. data/lib/seahorse/client/plugins/h2.rb +4 -1
  80. data/lib/seahorse/client/plugins/net_http.rb +37 -3
  81. data/lib/seahorse/client/plugins/response_target.rb +0 -1
  82. data/lib/seahorse/model/operation.rb +3 -0
  83. data/lib/seahorse/model/shapes.rb +25 -0
  84. data/lib/seahorse/util.rb +6 -1
  85. metadata +17 -10
  86. data/lib/aws-sdk-sso/plugins/content_type.rb +0 -25
@@ -26,7 +26,8 @@ module Aws
26
26
 
27
27
  def filter(values, type)
28
28
  case values
29
- when Struct, Hash then filter_hash(values, type)
29
+ when Struct then filter_struct(values, type)
30
+ when Hash then filter_hash(values, type)
30
31
  when Array then filter_array(values, type)
31
32
  else values
32
33
  end
@@ -34,6 +35,13 @@ module Aws
34
35
 
35
36
  private
36
37
 
38
+ def filter_struct(values, type)
39
+ if values.class.include? Aws::Structure::Union
40
+ values = { values.member => values.value }
41
+ end
42
+ filter_hash(values, type)
43
+ end
44
+
37
45
  def filter_hash(values, type)
38
46
  if type.const_defined?('SENSITIVE')
39
47
  filters = type::SENSITIVE + @additional_filters
@@ -48,11 +48,11 @@ module Aws
48
48
  #
49
49
  module PageableResponse
50
50
 
51
- def self.extended(base)
52
- base.send(:extend, Enumerable)
53
- base.send(:extend, UnsafeEnumerableMethods)
54
- base.instance_variable_set("@last_page", nil)
55
- base.instance_variable_set("@more_results", nil)
51
+ def self.apply(base)
52
+ base.extend Extension
53
+ base.instance_variable_set(:@last_page, nil)
54
+ base.instance_variable_set(:@more_results, nil)
55
+ base
56
56
  end
57
57
 
58
58
  # @return [Paging::Pager]
@@ -62,39 +62,26 @@ module Aws
62
62
  # when this method returns `false` will raise an error.
63
63
  # @return [Boolean]
64
64
  def last_page?
65
- if @last_page.nil?
66
- @last_page = !@pager.truncated?(self)
67
- end
68
- @last_page
65
+ # Actual implementation is in PageableResponse::Extension
69
66
  end
70
67
 
71
68
  # Returns `true` if there are more results. Calling {#next_page} will
72
69
  # return the next response.
73
70
  # @return [Boolean]
74
71
  def next_page?
75
- !last_page?
72
+ # Actual implementation is in PageableResponse::Extension
76
73
  end
77
74
 
78
75
  # @return [Seahorse::Client::Response]
79
76
  def next_page(params = {})
80
- if last_page?
81
- raise LastPageError.new(self)
82
- else
83
- next_response(params)
84
- end
77
+ # Actual implementation is in PageableResponse::Extension
85
78
  end
86
79
 
87
80
  # Yields the current and each following response to the given block.
88
81
  # @yieldparam [Response] response
89
82
  # @return [Enumerable,nil] Returns a new Enumerable if no block is given.
90
83
  def each(&block)
91
- return enum_for(:each_page) unless block_given?
92
- response = self
93
- yield(response)
94
- until response.last_page?
95
- response = response.next_page
96
- yield(response)
97
- end
84
+ # Actual implementation is in PageableResponse::Extension
98
85
  end
99
86
  alias each_page each
100
87
 
@@ -105,9 +92,7 @@ module Aws
105
92
  # @return [Seahorse::Client::Response] Returns the next page of
106
93
  # results.
107
94
  def next_response(params)
108
- params = next_page_params(params)
109
- request = context.client.build_request(context.operation_name, params)
110
- request.send_request
95
+ # Actual implementation is in PageableResponse::Extension
111
96
  end
112
97
 
113
98
  # @param [Hash] params A hash of additional request params to
@@ -115,7 +100,7 @@ module Aws
115
100
  # @return [Hash] Returns the hash of request parameters for the
116
101
  # next page, merging any given params.
117
102
  def next_page_params(params)
118
- context[:original_params].merge(@pager.next_tokens(self).merge(params))
103
+ # Actual implementation is in PageableResponse::Extension
119
104
  end
120
105
 
121
106
  # Raised when calling {PageableResponse#next_page} on a pager that
@@ -162,5 +147,66 @@ module Aws
162
147
  end
163
148
 
164
149
  end
150
+
151
+ # The actual decorator module implementation. It is in a distinct module
152
+ # so that it can be used to extend objects without busting Ruby's constant cache.
153
+ # object.extend(mod) bust the constant cache only if `mod` contains constants of its own.
154
+ # @api private
155
+ module Extension
156
+
157
+ include Enumerable
158
+ include UnsafeEnumerableMethods
159
+
160
+ attr_accessor :pager
161
+
162
+ def last_page?
163
+ if @last_page.nil?
164
+ @last_page = !@pager.truncated?(self)
165
+ end
166
+ @last_page
167
+ end
168
+
169
+ def next_page?
170
+ !last_page?
171
+ end
172
+
173
+ def next_page(params = {})
174
+ if last_page?
175
+ raise LastPageError.new(self)
176
+ else
177
+ next_response(params)
178
+ end
179
+ end
180
+
181
+ def each(&block)
182
+ return enum_for(:each_page) unless block_given?
183
+ response = self
184
+ yield(response)
185
+ until response.last_page?
186
+ response = response.next_page
187
+ yield(response)
188
+ end
189
+ end
190
+ alias each_page each
191
+
192
+ private
193
+
194
+ def next_response(params)
195
+ params = next_page_params(params)
196
+ request = context.client.build_request(context.operation_name, params)
197
+ request.send_request
198
+ end
199
+
200
+ def next_page_params(params)
201
+ # Remove all previous tokens from original params
202
+ # Sometimes a token can be nil and merge would not include it.
203
+ tokens = @pager.tokens.values.map(&:to_sym)
204
+
205
+ params_without_tokens = context[:original_params].reject { |k, _v| tokens.include?(k) }
206
+ params_without_tokens.merge!(@pager.next_tokens(self).merge(params))
207
+ params_without_tokens
208
+ end
209
+
210
+ end
165
211
  end
166
212
  end
@@ -18,6 +18,9 @@ module Aws
18
18
  # @return [Symbol, nil]
19
19
  attr_reader :limit_key
20
20
 
21
+ # @return [Hash, nil]
22
+ attr_reader :tokens
23
+
21
24
  # @param [Seahorse::Client::Response] response
22
25
  # @return [Hash]
23
26
  def next_tokens(response)
@@ -70,6 +70,14 @@ module Aws
70
70
  end
71
71
  end
72
72
 
73
+ if @validate_required && shape.union
74
+ if values.length > 1
75
+ errors << "multiple values provided to union at #{context} - must contain exactly one of the supported types: #{shape.member_names.join(', ')}"
76
+ elsif values.length == 0
77
+ errors << "No values provided to union at #{context} - must contain exactly one of the supported types: #{shape.member_names.join(', ')}"
78
+ end
79
+ end
80
+
73
81
  # validate non-nil members
74
82
  values.each_pair do |name, value|
75
83
  unless value.nil?
@@ -117,11 +125,32 @@ module Aws
117
125
  end
118
126
  end
119
127
 
128
+ def document(ref, value, errors, context)
129
+ document_types = [Hash, Array, Numeric, String, TrueClass, FalseClass, NilClass]
130
+ unless document_types.any? { |t| value.is_a?(t) }
131
+ errors << expected_got(context, "one of #{document_types.join(', ')}", value)
132
+ end
133
+
134
+ # recursively validate types for aggregated types
135
+ case value
136
+ when Hash
137
+ value.each do |k, v|
138
+ document(ref, v, errors, context + "[#{k}]")
139
+ end
140
+ when Array
141
+ value.each do |v|
142
+ document(ref, v, errors, context)
143
+ end
144
+ end
145
+
146
+ end
147
+
120
148
  def shape(ref, value, errors, context)
121
149
  case ref.shape
122
150
  when StructureShape then structure(ref, value, errors, context)
123
151
  when ListShape then list(ref, value, errors, context)
124
152
  when MapShape then map(ref, value, errors, context)
153
+ when DocumentShape then document(ref, value, errors, context)
125
154
  when StringShape
126
155
  unless value.is_a?(String)
127
156
  errors << expected_got(context, "a String", value)
@@ -0,0 +1,340 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Plugins
5
+ # @api private
6
+ class ChecksumAlgorithm < Seahorse::Client::Plugin
7
+ CHUNK_SIZE = 1 * 1024 * 1024 # one MB
8
+
9
+ # determine the set of supported client side checksum algorithms
10
+ # CRC32c requires aws-crt (optional sdk dependency) for support
11
+ CLIENT_ALGORITHMS = begin
12
+ supported = %w[SHA256 SHA1 CRC32]
13
+ begin
14
+ require 'aws-crt'
15
+ supported << 'CRC32C'
16
+ rescue LoadError
17
+ end
18
+ supported
19
+ end.freeze
20
+
21
+ # priority order of checksum algorithms to validate responses against
22
+ # Remove any algorithms not supported by client (ie, depending on CRT availability)
23
+ CHECKSUM_ALGORITHM_PRIORITIES = %w[CRC32C SHA1 CRC32 SHA256] & CLIENT_ALGORITHMS
24
+
25
+ # byte size of checksums, used in computing the trailer length
26
+ CHECKSUM_SIZE = {
27
+ 'CRC32' => 16,
28
+ 'CRC32C' => 16,
29
+ 'SHA1' => 36,
30
+ 'SHA256' => 52
31
+ }
32
+
33
+ # Interface for computing digests on request/response bodies
34
+ # which may be files, strings or IO like objects
35
+ # Applies only to digest functions that produce 32 bit integer checksums
36
+ # (eg CRC32)
37
+ class Digest32
38
+
39
+ attr_reader :value
40
+
41
+ # @param [Object] digest_fn
42
+ def initialize(digest_fn)
43
+ @digest_fn = digest_fn
44
+ @value = 0
45
+ end
46
+
47
+ def update(chunk)
48
+ @value = @digest_fn.call(chunk, @value)
49
+ end
50
+
51
+ def base64digest
52
+ Base64.encode64([@value].pack('N')).chomp
53
+ end
54
+ end
55
+
56
+ def add_handlers(handlers, _config)
57
+ handlers.add(OptionHandler, step: :initialize)
58
+ # priority set low to ensure checksum is computed AFTER the request is
59
+ # built but before it is signed
60
+ handlers.add(ChecksumHandler, priority: 15, step: :build)
61
+ end
62
+
63
+ private
64
+
65
+ def self.request_algorithm_selection(context)
66
+ return unless context.operation.http_checksum
67
+
68
+ input_member = context.operation.http_checksum['requestAlgorithmMember']
69
+ context.params[input_member.to_sym]&.upcase if input_member
70
+ end
71
+
72
+ def self.request_validation_mode(context)
73
+ return unless context.operation.http_checksum
74
+
75
+ input_member = context.operation.http_checksum['requestValidationModeMember']
76
+ context.params[input_member.to_sym] if input_member
77
+ end
78
+
79
+ def self.operation_response_algorithms(context)
80
+ return unless context.operation.http_checksum
81
+
82
+ context.operation.http_checksum['responseAlgorithms']
83
+ end
84
+
85
+
86
+ # @api private
87
+ class OptionHandler < Seahorse::Client::Handler
88
+ def call(context)
89
+ context[:http_checksum] ||= {}
90
+
91
+ # validate request configuration
92
+ if (request_input = ChecksumAlgorithm.request_algorithm_selection(context))
93
+ unless CLIENT_ALGORITHMS.include? request_input
94
+ if (request_input == 'CRC32C')
95
+ raise ArgumentError, "CRC32C requires crt support - install the aws-crt gem for support."
96
+ else
97
+ raise ArgumentError, "#{request_input} is not a supported checksum algorithm."
98
+ end
99
+ end
100
+ end
101
+
102
+ # validate response configuration
103
+ if (ChecksumAlgorithm.request_validation_mode(context))
104
+ # Compute an ordered list as the union between priority supported and the
105
+ # operation's modeled response algorithms.
106
+ validation_list = CHECKSUM_ALGORITHM_PRIORITIES &
107
+ ChecksumAlgorithm.operation_response_algorithms(context)
108
+ context[:http_checksum][:validation_list] = validation_list
109
+ end
110
+
111
+ @handler.call(context)
112
+ end
113
+ end
114
+
115
+ # @api private
116
+ class ChecksumHandler < Seahorse::Client::Handler
117
+
118
+ def call(context)
119
+ if should_calculate_request_checksum?(context)
120
+ request_algorithm_input = ChecksumAlgorithm.request_algorithm_selection(context)
121
+ context[:checksum_algorithms] = request_algorithm_input
122
+
123
+ request_checksum_property = {
124
+ 'algorithm' => request_algorithm_input,
125
+ 'in' => checksum_request_in(context),
126
+ 'name' => "x-amz-checksum-#{request_algorithm_input.downcase}"
127
+ }
128
+
129
+ calculate_request_checksum(context, request_checksum_property)
130
+ end
131
+
132
+ if should_verify_response_checksum?(context)
133
+ add_verify_response_checksum_handlers(context)
134
+ end
135
+
136
+ @handler.call(context)
137
+ end
138
+
139
+ private
140
+
141
+ def should_calculate_request_checksum?(context)
142
+ context.operation.http_checksum &&
143
+ ChecksumAlgorithm.request_algorithm_selection(context)
144
+ end
145
+
146
+ def should_verify_response_checksum?(context)
147
+ context[:http_checksum][:validation_list] && !context[:http_checksum][:validation_list].empty?
148
+ end
149
+
150
+ def calculate_request_checksum(context, checksum_properties)
151
+ case checksum_properties['in']
152
+ when 'header'
153
+ header_name = checksum_properties['name']
154
+ body = context.http_request.body_contents
155
+ if body
156
+ context.http_request.headers[header_name] ||=
157
+ ChecksumAlgorithm.calculate_checksum(checksum_properties['algorithm'], body)
158
+ end
159
+ when 'trailer'
160
+ apply_request_trailer_checksum(context, checksum_properties)
161
+ end
162
+ end
163
+
164
+ def apply_request_trailer_checksum(context, checksum_properties)
165
+ location_name = checksum_properties['name']
166
+
167
+ # set required headers
168
+ headers = context.http_request.headers
169
+ headers['Content-Encoding'] = 'aws-chunked'
170
+ headers['X-Amz-Content-Sha256'] = 'STREAMING-UNSIGNED-PAYLOAD-TRAILER'
171
+ headers['X-Amz-Trailer'] = location_name
172
+
173
+ # We currently always compute the size in the modified body wrapper - allowing us
174
+ # to set the Content-Length header (set by content_length plugin).
175
+ # This means we cannot use Transfer-Encoding=chunked
176
+
177
+ if !context.http_request.body.respond_to?(:size)
178
+ raise Aws::Errors::ChecksumError, 'Could not determine length of the body'
179
+ end
180
+ headers['X-Amz-Decoded-Content-Length'] = context.http_request.body.size
181
+
182
+ context.http_request.body = AwsChunkedTrailerDigestIO.new(
183
+ context.http_request.body,
184
+ checksum_properties['algorithm'],
185
+ location_name
186
+ )
187
+ end
188
+
189
+ # Add events to the http_response to verify the checksum as its read
190
+ # This prevents the body from being read multiple times
191
+ # verification is done only once a successful response has completed
192
+ def add_verify_response_checksum_handlers(context)
193
+ http_response = context.http_response
194
+ checksum_context = { }
195
+ http_response.on_headers do |_status, headers|
196
+ header_name, algorithm = response_header_to_verify(headers, context[:http_checksum][:validation_list])
197
+ if header_name
198
+ expected = headers[header_name]
199
+
200
+ unless context[:http_checksum][:skip_on_suffix] && /-[\d]+$/.match(expected)
201
+ checksum_context[:algorithm] = algorithm
202
+ checksum_context[:header_name] = header_name
203
+ checksum_context[:digest] = ChecksumAlgorithm.digest_for_algorithm(algorithm)
204
+ checksum_context[:expected] = expected
205
+ end
206
+ end
207
+ end
208
+
209
+ http_response.on_data do |chunk|
210
+ checksum_context[:digest].update(chunk) if checksum_context[:digest]
211
+ end
212
+
213
+ http_response.on_success do
214
+ if checksum_context[:digest] &&
215
+ (computed = checksum_context[:digest].base64digest)
216
+
217
+ if computed != checksum_context[:expected]
218
+ raise Aws::Errors::ChecksumError,
219
+ "Checksum validation failed on #{checksum_context[:header_name]} "\
220
+ "computed: #{computed}, expected: #{checksum_context[:expected]}"
221
+ end
222
+
223
+ context[:http_checksum][:validated] = checksum_context[:algorithm]
224
+ end
225
+ end
226
+ end
227
+
228
+ # returns nil if no headers to verify
229
+ def response_header_to_verify(headers, validation_list)
230
+ validation_list.each do |algorithm|
231
+ header_name = "x-amz-checksum-#{algorithm}"
232
+ return [header_name, algorithm] if headers[header_name]
233
+ end
234
+ nil
235
+ end
236
+
237
+ # determine where (header vs trailer) a request checksum should be added
238
+ def checksum_request_in(context)
239
+ if context.operation['authtype'].eql?('v4-unsigned-body')
240
+ 'trailer'
241
+ else
242
+ 'header'
243
+ end
244
+ end
245
+
246
+ end
247
+
248
+ def self.calculate_checksum(algorithm, body)
249
+ digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
250
+ if body.respond_to?(:read)
251
+ ChecksumAlgorithm.update_in_chunks(digest, body)
252
+ else
253
+ digest.update(body)
254
+ end
255
+ digest.base64digest
256
+ end
257
+
258
+ def self.digest_for_algorithm(algorithm)
259
+ case algorithm
260
+ when 'CRC32'
261
+ Digest32.new(Zlib.method(:crc32))
262
+ when 'CRC32C'
263
+ # this will only be used if input algorithm is CRC32C AND client supports it (crt available)
264
+ Digest32.new(Aws::Crt::Checksums.method(:crc32c))
265
+ when 'SHA1'
266
+ Digest::SHA1.new
267
+ when 'SHA256'
268
+ Digest::SHA256.new
269
+ end
270
+ end
271
+
272
+ # The trailer size (in bytes) is the overhead + the trailer name +
273
+ # the length of the base64 encoded checksum
274
+ def self.trailer_length(algorithm, location_name)
275
+ CHECKSUM_SIZE[algorithm] + location_name.size
276
+ end
277
+
278
+ def self.update_in_chunks(digest, io)
279
+ loop do
280
+ chunk = io.read(CHUNK_SIZE)
281
+ break unless chunk
282
+ digest.update(chunk)
283
+ end
284
+ io.rewind
285
+ end
286
+
287
+ # Wrapper for request body that implements application-layer
288
+ # chunking with Digest computed on chunks + added as a trailer
289
+ class AwsChunkedTrailerDigestIO
290
+ CHUNK_SIZE = 16384
291
+
292
+ def initialize(io, algorithm, location_name)
293
+ @io = io
294
+ @location_name = location_name
295
+ @algorithm = algorithm
296
+ @digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
297
+ @trailer_io = nil
298
+ end
299
+
300
+ # the size of the application layer aws-chunked + trailer body
301
+ def size
302
+ # compute the number of chunks
303
+ # a full chunk has 4 + 4 bytes overhead, a partial chunk is len.to_s(16).size + 4
304
+ orig_body_size = @io.size
305
+ n_full_chunks = orig_body_size / CHUNK_SIZE
306
+ partial_bytes = orig_body_size % CHUNK_SIZE
307
+ chunked_body_size = n_full_chunks * (CHUNK_SIZE + 8)
308
+ chunked_body_size += partial_bytes.to_s(16).size + partial_bytes + 4 unless partial_bytes.zero?
309
+ trailer_size = ChecksumAlgorithm.trailer_length(@algorithm, @location_name)
310
+ chunked_body_size + trailer_size
311
+ end
312
+
313
+ def rewind
314
+ @io.rewind
315
+ end
316
+
317
+ def read(length, buf)
318
+ # account for possible leftover bytes at the end, if we have trailer bytes, send them
319
+ if @trailer_io
320
+ return @trailer_io.read(length, buf)
321
+ end
322
+
323
+ chunk = @io.read(length)
324
+ if chunk
325
+ @digest.update(chunk)
326
+ application_chunked = "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
327
+ return StringIO.new(application_chunked).read(application_chunked.size, buf)
328
+ else
329
+ trailers = {}
330
+ trailers[@location_name] = @digest.base64digest
331
+ trailers = trailers.map { |k,v| "#{k}:#{v}"}.join("\r\n")
332
+ @trailer_io = StringIO.new("0\r\n#{trailers}\r\n\r\n")
333
+ chunk = @trailer_io.read(length, buf)
334
+ end
335
+ chunk
336
+ end
337
+ end
338
+ end
339
+ end
340
+ end
@@ -64,7 +64,9 @@ locations will be searched for credentials:
64
64
  * EC2/ECS IMDS instance profile - When used by default, the timeouts
65
65
  are very aggressive. Construct and pass an instance of
66
66
  `Aws::InstanceProfileCredentails` or `Aws::ECSCredentials` to
67
- enable retries and extended timeouts.
67
+ enable retries and extended timeouts. Instance profile credential
68
+ fetching can be disabled by setting ENV['AWS_EC2_METADATA_DISABLED']
69
+ to true.
68
70
  DOCS
69
71
  ) do |config|
70
72
  CredentialProviderChain.new(config).resolve
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ # @api private
5
+ module Plugins
6
+ # @api private
7
+ class DefaultsMode < Seahorse::Client::Plugin
8
+
9
+ option(:defaults_mode,
10
+ default: 'legacy',
11
+ doc_type: String,
12
+ docstring: <<-DOCS
13
+ See {Aws::DefaultsModeConfiguration} for a list of the
14
+ accepted modes and the configuration defaults that are included.
15
+ DOCS
16
+ ) do |cfg|
17
+ resolve_defaults_mode(cfg)
18
+ end
19
+
20
+ option(:defaults_mode_config_resolver,
21
+ doc_type: 'Aws::DefaultsModeConfigResolver') do |cfg|
22
+ Aws::DefaultsModeConfigResolver.new(
23
+ Aws::DefaultsModeConfiguration::SDK_DEFAULT_CONFIGURATION, cfg)
24
+ end
25
+
26
+ class << self
27
+ private
28
+
29
+ def resolve_defaults_mode(cfg)
30
+ value = ENV['AWS_DEFAULTS_MODE']
31
+ value ||= Aws.shared_config.defaults_mode(
32
+ profile: cfg.profile
33
+ )
34
+ value&.downcase || "legacy"
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -15,17 +15,17 @@ to default service endpoint when available.
15
15
  )
16
16
 
17
17
  def add_handlers(handlers, config)
18
- if config.regional_endpoint && !config.disable_host_prefix_injection
19
- handlers.add(Handler, priority: 90)
20
- end
18
+ handlers.add(Handler, priority: 10)
21
19
  end
22
20
 
23
21
  class Handler < Seahorse::Client::Handler
24
22
 
25
23
  def call(context)
26
- endpoint_trait = context.operation.endpoint_pattern
27
- if endpoint_trait && !endpoint_trait.empty?
28
- _apply_endpoint_trait(context, endpoint_trait)
24
+ if !context.config.disable_host_prefix_injection
25
+ endpoint_trait = context.operation.endpoint_pattern
26
+ if endpoint_trait && !endpoint_trait.empty?
27
+ _apply_endpoint_trait(context, endpoint_trait)
28
+ end
29
29
  end
30
30
  @handler.call(context)
31
31
  end
@@ -11,7 +11,8 @@ module Aws
11
11
  CHUNK_SIZE = 1 * 1024 * 1024 # one MB
12
12
 
13
13
  def call(context)
14
- if context.operation.http_checksum_required
14
+ if checksum_required?(context) &&
15
+ !context[:checksum_algorithms] # skip in favor of flexible checksum
15
16
  body = context.http_request.body
16
17
  context.http_request.headers['Content-Md5'] ||= md5(body)
17
18
  end
@@ -20,6 +21,12 @@ module Aws
20
21
 
21
22
  private
22
23
 
24
+ def checksum_required?(context)
25
+ context.operation.http_checksum_required ||
26
+ (context.operation.http_checksum &&
27
+ context.operation.http_checksum['requestChecksumRequired'])
28
+ end
29
+
23
30
  # @param [File, Tempfile, IO#read, String] value
24
31
  # @return [String<MD5>]
25
32
  def md5(value)
@@ -4,9 +4,26 @@ module Aws
4
4
  module Plugins
5
5
  module Protocols
6
6
  class ApiGateway < Seahorse::Client::Plugin
7
+
8
+ class ContentTypeHandler < Seahorse::Client::Handler
9
+ def call(context)
10
+ body = context.http_request.body
11
+ # Rest::Handler will set a default JSON body, so size can be checked
12
+ # if this handler is run after serialization.
13
+ if !body.respond_to?(:size) ||
14
+ (body.respond_to?(:size) && body.size > 0)
15
+ context.http_request.headers['Content-Type'] ||=
16
+ 'application/json'
17
+ end
18
+ @handler.call(context)
19
+ end
20
+ end
21
+
7
22
  handler(Rest::Handler)
23
+ handler(ContentTypeHandler, priority: 30)
8
24
  handler(Json::ErrorHandler, step: :sign)
9
25
  end
26
+
10
27
  end
11
28
  end
12
29
  end