aws-sdk-core 3.210.0 → 3.217.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-defaults/default_configuration.rb +1 -2
  5. data/lib/aws-sdk-core/arn.rb +1 -3
  6. data/lib/aws-sdk-core/cbor/decoder.rb +0 -2
  7. data/lib/aws-sdk-core/cbor/encoder.rb +2 -2
  8. data/lib/aws-sdk-core/cbor.rb +3 -56
  9. data/lib/aws-sdk-core/client_stubs.rb +7 -7
  10. data/lib/aws-sdk-core/json/error_handler.rb +2 -1
  11. data/lib/aws-sdk-core/json/handler.rb +1 -0
  12. data/lib/aws-sdk-core/log/param_formatter.rb +7 -3
  13. data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +332 -170
  14. data/lib/aws-sdk-core/plugins/http_checksum.rb +2 -8
  15. data/lib/aws-sdk-core/plugins/sign.rb +1 -1
  16. data/lib/aws-sdk-core/plugins/user_agent.rb +10 -1
  17. data/lib/aws-sdk-core/rest/request/headers.rb +2 -2
  18. data/lib/aws-sdk-core/rpc_v2/builder.rb +1 -1
  19. data/lib/aws-sdk-core/{cbor → rpc_v2}/cbor_engine.rb +4 -5
  20. data/lib/aws-sdk-core/rpc_v2/content_type_handler.rb +3 -1
  21. data/lib/aws-sdk-core/rpc_v2/error_handler.rb +3 -2
  22. data/lib/aws-sdk-core/rpc_v2/handler.rb +2 -1
  23. data/lib/aws-sdk-core/rpc_v2/parser.rb +1 -1
  24. data/lib/aws-sdk-core/rpc_v2.rb +65 -2
  25. data/lib/aws-sdk-core/shared_config.rb +2 -0
  26. data/lib/aws-sdk-core/stubbing/protocols/ec2.rb +12 -11
  27. data/lib/aws-sdk-core/stubbing/protocols/json.rb +11 -10
  28. data/lib/aws-sdk-core/stubbing/protocols/query.rb +7 -6
  29. data/lib/aws-sdk-core/stubbing/protocols/rest.rb +2 -1
  30. data/lib/aws-sdk-core/stubbing/protocols/rest_json.rb +9 -8
  31. data/lib/aws-sdk-core/stubbing/protocols/rest_xml.rb +6 -5
  32. data/lib/aws-sdk-core/stubbing/protocols/rpc_v2.rb +13 -15
  33. data/lib/aws-sdk-core/stubbing.rb +2 -2
  34. data/lib/aws-sdk-sso/client.rb +24 -1
  35. data/lib/aws-sdk-sso.rb +1 -1
  36. data/lib/aws-sdk-ssooidc/client.rb +48 -19
  37. data/lib/aws-sdk-ssooidc/types.rb +20 -15
  38. data/lib/aws-sdk-ssooidc.rb +1 -1
  39. data/lib/aws-sdk-sts/client.rb +231 -52
  40. data/lib/aws-sdk-sts/client_api.rb +23 -0
  41. data/lib/aws-sdk-sts/types.rb +170 -28
  42. data/lib/aws-sdk-sts.rb +1 -1
  43. data/lib/seahorse/client/response.rb +2 -0
  44. metadata +3 -3
@@ -13,34 +13,131 @@ module Aws
13
13
  begin
14
14
  require 'aws-crt'
15
15
  supported << 'CRC32C'
16
+ supported << 'CRC64NVME' if Aws::Crt::GEM_VERSION >= '0.3.0'
16
17
  rescue LoadError
18
+ # Ignored
17
19
  end
18
20
  supported
19
21
  end.freeze
20
22
 
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
23
+ CRT_ALGORITHMS = %w[CRC32C CRC64NVME].freeze
24
+
25
+ # Priority order of checksum algorithms to validate responses against.
26
+ # Remove any algorithms not supported by client (ie, depending on CRT availability).
27
+ # This list was chosen based on average performance.
28
+ CHECKSUM_ALGORITHM_PRIORITIES = %w[CRC32 CRC32C CRC64NVME SHA1 SHA256] & CLIENT_ALGORITHMS
24
29
 
25
30
  # byte size of checksums, used in computing the trailer length
26
31
  CHECKSUM_SIZE = {
27
- 'CRC32' => 16,
28
- 'CRC32C' => 16,
29
- 'SHA1' => 36,
30
- 'SHA256' => 52
31
- }
32
+ 'CRC32' => 9,
33
+ 'CRC32C' => 9,
34
+ 'CRC64NVME' => 13,
35
+ # SHA functions need 1 byte padding because of how they are encoded
36
+ 'SHA1' => 28 + 1,
37
+ 'SHA256' => 44 + 1
38
+ }.freeze
39
+
40
+ DEFAULT_CHECKSUM = 'CRC32'
41
+
42
+ option(:request_checksum_calculation,
43
+ doc_default: 'when_supported',
44
+ doc_type: 'String',
45
+ docstring: <<~DOCS) do |cfg|
46
+ Determines when a checksum will be calculated for request payloads. Values are:
47
+
48
+ * `when_supported` - (default) When set, a checksum will be
49
+ calculated for all request payloads of operations modeled with the
50
+ `httpChecksum` trait where `requestChecksumRequired` is `true` and/or a
51
+ `requestAlgorithmMember` is modeled.
52
+ * `when_required` - When set, a checksum will only be calculated for
53
+ request payloads of operations modeled with the `httpChecksum` trait where
54
+ `requestChecksumRequired` is `true` or where a `requestAlgorithmMember`
55
+ is modeled and supplied.
56
+ DOCS
57
+ resolve_request_checksum_calculation(cfg)
58
+ end
32
59
 
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
60
+ option(:response_checksum_validation,
61
+ doc_default: 'when_supported',
62
+ doc_type: 'String',
63
+ docstring: <<~DOCS) do |cfg|
64
+ Determines when checksum validation will be performed on response payloads. Values are:
65
+
66
+ * `when_supported` - (default) When set, checksum validation is performed on all
67
+ response payloads of operations modeled with the `httpChecksum` trait where
68
+ `responseAlgorithms` is modeled, except when no modeled checksum algorithms
69
+ are supported.
70
+ * `when_required` - When set, checksum validation is not performed on
71
+ response payloads of operations unless the checksum algorithm is supported and
72
+ the `requestValidationModeMember` member is set to `ENABLED`.
73
+ DOCS
74
+ resolve_response_checksum_validation(cfg)
75
+ end
38
76
 
39
- attr_reader :value
77
+ class << self
78
+ def digest_for_algorithm(algorithm)
79
+ case algorithm
80
+ when 'CRC32'
81
+ Digest.new(Zlib.method(:crc32), 'N')
82
+ when 'CRC32C'
83
+ Digest.new(Aws::Crt::Checksums.method(:crc32c), 'N')
84
+ when 'CRC64NVME'
85
+ Digest.new(Aws::Crt::Checksums.method(:crc64nvme), 'Q>')
86
+ when 'SHA1'
87
+ ::Digest::SHA1.new
88
+ when 'SHA256'
89
+ ::Digest::SHA256.new
90
+ else
91
+ raise ArgumentError,
92
+ "#{algorithm} is not a supported checksum algorithm."
93
+ end
94
+ end
95
+
96
+ # The trailer size (in bytes) is the overhead (0, \r, \n) + the trailer
97
+ # name + the bytesize of the base64 encoded checksum.
98
+ def trailer_length(algorithm, location_name)
99
+ 7 + location_name.size + CHECKSUM_SIZE[algorithm]
100
+ end
40
101
 
41
- # @param [Object] digest_fn
42
- def initialize(digest_fn)
102
+ private
103
+
104
+ def resolve_request_checksum_calculation(cfg)
105
+ mode = ENV['AWS_REQUEST_CHECKSUM_CALCULATION'] ||
106
+ Aws.shared_config.request_checksum_calculation(profile: cfg.profile) ||
107
+ 'when_supported'
108
+ mode = mode.downcase
109
+ unless %w[when_supported when_required].include?(mode)
110
+ raise ArgumentError,
111
+ 'expected :request_checksum_calculation or' \
112
+ " ENV['AWS_REQUEST_CHECKSUM_CALCULATION'] to be " \
113
+ '`when_supported` or `when_required`.'
114
+ end
115
+ mode
116
+ end
117
+
118
+ def resolve_response_checksum_validation(cfg)
119
+ mode = ENV['AWS_RESPONSE_CHECKSUM_VALIDATION'] ||
120
+ Aws.shared_config.response_checksum_validation(profile: cfg.profile) ||
121
+ 'when_supported'
122
+ mode = mode.downcase
123
+ unless %w[when_supported when_required].include?(mode)
124
+ raise ArgumentError,
125
+ 'expected :response_checksum_validation or' \
126
+ " ENV['AWS_RESPONSE_CHECKSUM_VALIDATION'] to be " \
127
+ '`when_supported` or `when_required`.'
128
+ end
129
+ mode
130
+ end
131
+ end
132
+
133
+ # Interface for computing digests on request/response bodies
134
+ # which may be files, strings or IO like objects.
135
+ # Applies only to digest functions that produce 32 or 64 bit
136
+ # integer checksums (eg CRC32 or CRC64).
137
+ class Digest
138
+ def initialize(digest_fn, directive)
43
139
  @digest_fn = digest_fn
140
+ @directive = directive
44
141
  @value = 0
45
142
  end
46
143
 
@@ -49,125 +146,223 @@ module Aws
49
146
  end
50
147
 
51
148
  def base64digest
52
- Base64.encode64([@value].pack('N')).chomp
149
+ Base64.encode64([@value].pack(@directive)).chomp
53
150
  end
54
151
  end
55
152
 
56
153
  def add_handlers(handlers, _config)
57
154
  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
155
+ # Priority is set low to ensure the checksum is computed AFTER the
156
+ # request is built but before it is signed.
60
157
  handlers.add(ChecksumHandler, priority: 15, step: :build)
61
158
  end
62
159
 
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
160
  class OptionHandler < Seahorse::Client::Handler
88
161
  def call(context)
89
162
  context[:http_checksum] ||= {}
90
163
 
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
164
+ # Set validation mode to enabled when supported.
165
+ if context.config.response_checksum_validation == 'when_supported'
166
+ enable_request_validation_mode(context)
109
167
  end
110
168
 
111
169
  @handler.call(context)
112
170
  end
171
+
172
+ private
173
+
174
+ def enable_request_validation_mode(context)
175
+ return unless context.operation.http_checksum
176
+
177
+ input_member = context.operation.http_checksum['requestValidationModeMember']
178
+ context.params[input_member.to_sym] ||= 'ENABLED' if input_member
179
+ end
113
180
  end
114
181
 
115
- # @api private
116
182
  class ChecksumHandler < Seahorse::Client::Handler
117
-
118
183
  def call(context)
184
+ algorithm = nil
119
185
  if should_calculate_request_checksum?(context)
120
- request_algorithm_input = ChecksumAlgorithm.request_algorithm_selection(context) ||
121
- context[:default_request_checksum_algorithm]
122
- context[:checksum_algorithms] = request_algorithm_input
123
-
124
- request_checksum_property = {
125
- 'algorithm' => request_algorithm_input,
126
- 'in' => checksum_request_in(context),
127
- 'name' => "x-amz-checksum-#{request_algorithm_input.downcase}"
186
+ algorithm = choose_request_algorithm!(context)
187
+ request_algorithm = {
188
+ algorithm: algorithm,
189
+ in: checksum_request_in(context),
190
+ name: "x-amz-checksum-#{algorithm.downcase}",
191
+ request_algorithm_header: request_algorithm_header(context)
128
192
  }
129
193
 
130
- calculate_request_checksum(context, request_checksum_property)
194
+ context[:http_checksum][:request_algorithm] = request_algorithm
195
+ calculate_request_checksum(context, request_algorithm)
131
196
  end
132
197
 
133
198
  if should_verify_response_checksum?(context)
134
199
  add_verify_response_checksum_handlers(context)
135
200
  end
136
201
 
137
- @handler.call(context)
202
+ with_metrics(context.config, algorithm) { @handler.call(context) }
138
203
  end
139
204
 
140
205
  private
141
206
 
142
- def should_calculate_request_checksum?(context)
207
+ def with_metrics(config, algorithm, &block)
208
+ metrics = []
209
+ add_request_config_metric(config, metrics)
210
+ add_response_config_metric(config, metrics)
211
+ add_request_checksum_metrics(algorithm, metrics)
212
+ Aws::Plugins::UserAgent.metric(*metrics, &block)
213
+ end
214
+
215
+ def add_request_config_metric(config, metrics)
216
+ case config.request_checksum_calculation
217
+ when 'when_supported'
218
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED'
219
+ when 'when_required'
220
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED'
221
+ end
222
+ end
223
+
224
+ def add_response_config_metric(config, metrics)
225
+ case config.response_checksum_validation
226
+ when 'when_supported'
227
+ metrics << 'FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED'
228
+ when 'when_required'
229
+ metrics << 'FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED'
230
+ end
231
+ end
232
+
233
+ def add_request_checksum_metrics(algorithm, metrics)
234
+ case algorithm
235
+ when 'CRC32'
236
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_CRC32'
237
+ when 'CRC32C'
238
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_CRC32C'
239
+ when 'CRC64NVME'
240
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_CRC64'
241
+ when 'SHA1'
242
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_SHA1'
243
+ when 'SHA256'
244
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_SHA256'
245
+ end
246
+ end
247
+
248
+ def request_algorithm_selection(context)
249
+ return unless context.operation.http_checksum
250
+
251
+ input_member = context.operation.http_checksum['requestAlgorithmMember']
252
+ context.params[input_member.to_sym] ||= DEFAULT_CHECKSUM if input_member
253
+ end
254
+
255
+ def request_algorithm_header(context)
256
+ input_member = context.operation.http_checksum['requestAlgorithmMember']
257
+ shape = context.operation.input.shape.member(input_member)
258
+ shape.location_name if shape && shape.location == 'header'
259
+ end
260
+
261
+ def request_validation_mode(context)
262
+ return unless context.operation.http_checksum
263
+
264
+ input_member = context.operation.http_checksum['requestValidationModeMember']
265
+ context.params[input_member.to_sym] if input_member
266
+ end
267
+
268
+ def operation_response_algorithms(context)
269
+ return unless context.operation.http_checksum
270
+
271
+ context.operation.http_checksum['responseAlgorithms']
272
+ end
273
+
274
+ def checksum_required?(context)
275
+ (http_checksum = context.operation.http_checksum) &&
276
+ (checksum_required = http_checksum['requestChecksumRequired']) &&
277
+ (checksum_required && context.config.request_checksum_calculation == 'when_required')
278
+ end
279
+
280
+ def checksum_optional?(context)
143
281
  context.operation.http_checksum &&
144
- (ChecksumAlgorithm.request_algorithm_selection(context) ||
145
- context[:default_request_checksum_algorithm])
282
+ context.config.request_checksum_calculation != 'when_required'
146
283
  end
147
284
 
148
- def should_verify_response_checksum?(context)
149
- context[:http_checksum][:validation_list] && !context[:http_checksum][:validation_list].empty?
285
+ def checksum_provided_as_header?(headers)
286
+ headers.any? { |k, _| k.start_with?('x-amz-checksum-') }
287
+ end
288
+
289
+ def should_calculate_request_checksum?(context)
290
+ !checksum_provided_as_header?(context.http_request.headers) &&
291
+ request_algorithm_selection(context) &&
292
+ (checksum_required?(context) || checksum_optional?(context))
293
+ end
294
+
295
+ def choose_request_algorithm!(context)
296
+ algorithm = request_algorithm_selection(context).upcase
297
+ return algorithm if CLIENT_ALGORITHMS.include?(algorithm)
298
+
299
+ if CRT_ALGORITHMS.include?(algorithm)
300
+ raise ArgumentError,
301
+ 'CRC32C and CRC64NVME requires CRT support ' \
302
+ '- install the aws-crt gem'
303
+ end
304
+
305
+ raise ArgumentError,
306
+ "#{algorithm} is not a supported checksum algorithm."
307
+ end
308
+
309
+ def checksum_request_in(context)
310
+ if context.operation['unsignedPayload'] ||
311
+ context.operation['authtype'] == 'v4-unsigned-body'
312
+ 'trailer'
313
+ else
314
+ 'header'
315
+ end
150
316
  end
151
317
 
152
318
  def calculate_request_checksum(context, checksum_properties)
153
- case checksum_properties['in']
319
+ headers = context.http_request.headers
320
+ if (algorithm_header = checksum_properties[:request_algorithm_header])
321
+ headers[algorithm_header] = checksum_properties[:algorithm]
322
+ end
323
+ case checksum_properties[:in]
154
324
  when 'header'
155
- header_name = checksum_properties['name']
156
- body = context.http_request.body_contents
157
- if body
158
- context.http_request.headers[header_name] ||=
159
- ChecksumAlgorithm.calculate_checksum(checksum_properties['algorithm'], body)
160
- end
325
+ apply_request_checksum(context, headers, checksum_properties)
161
326
  when 'trailer'
162
- apply_request_trailer_checksum(context, checksum_properties)
327
+ apply_request_trailer_checksum(context, headers, checksum_properties)
328
+ else
329
+ # nothing
330
+ end
331
+ end
332
+
333
+ def apply_request_checksum(context, headers, checksum_properties)
334
+ header_name = checksum_properties[:name]
335
+ body = context.http_request.body_contents
336
+ headers[header_name] = calculate_checksum(
337
+ checksum_properties[:algorithm],
338
+ body
339
+ )
340
+ end
341
+
342
+ def calculate_checksum(algorithm, body)
343
+ digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
344
+ if body.respond_to?(:read)
345
+ update_in_chunks(digest, body)
346
+ else
347
+ digest.update(body)
348
+ end
349
+ digest.base64digest
350
+ end
351
+
352
+ def update_in_chunks(digest, io)
353
+ loop do
354
+ chunk = io.read(CHUNK_SIZE)
355
+ break unless chunk
356
+
357
+ digest.update(chunk)
163
358
  end
359
+ io.rewind
164
360
  end
165
361
 
166
- def apply_request_trailer_checksum(context, checksum_properties)
167
- location_name = checksum_properties['name']
362
+ def apply_request_trailer_checksum(context, headers, checksum_properties)
363
+ location_name = checksum_properties[:name]
168
364
 
169
365
  # set required headers
170
- headers = context.http_request.headers
171
366
  headers['Content-Encoding'] = 'aws-chunked'
172
367
  headers['X-Amz-Content-Sha256'] = 'STREAMING-UNSIGNED-PAYLOAD-TRAILER'
173
368
  headers['X-Amz-Trailer'] = location_name
@@ -176,121 +371,88 @@ module Aws
176
371
  # to set the Content-Length header (set by content_length plugin).
177
372
  # This means we cannot use Transfer-Encoding=chunked
178
373
 
179
- if !context.http_request.body.respond_to?(:size)
374
+ unless context.http_request.body.respond_to?(:size)
180
375
  raise Aws::Errors::ChecksumError, 'Could not determine length of the body'
181
376
  end
182
377
  headers['X-Amz-Decoded-Content-Length'] = context.http_request.body.size
183
378
 
184
379
  context.http_request.body = AwsChunkedTrailerDigestIO.new(
185
380
  context.http_request.body,
186
- checksum_properties['algorithm'],
381
+ checksum_properties[:algorithm],
187
382
  location_name
188
383
  )
189
384
  end
190
385
 
386
+ def should_verify_response_checksum?(context)
387
+ request_validation_mode(context) == 'ENABLED'
388
+ end
389
+
191
390
  # Add events to the http_response to verify the checksum as its read
192
391
  # This prevents the body from being read multiple times
193
392
  # verification is done only once a successful response has completed
194
393
  def add_verify_response_checksum_handlers(context)
195
- http_response = context.http_response
196
- checksum_context = { }
197
- http_response.on_headers do |_status, headers|
198
- header_name, algorithm = response_header_to_verify(headers, context[:http_checksum][:validation_list])
199
- if header_name
200
- expected = headers[header_name]
201
-
202
- unless context[:http_checksum][:skip_on_suffix] && /-[\d]+$/.match(expected)
203
- checksum_context[:algorithm] = algorithm
204
- checksum_context[:header_name] = header_name
205
- checksum_context[:digest] = ChecksumAlgorithm.digest_for_algorithm(algorithm)
206
- checksum_context[:expected] = expected
207
- end
208
- end
209
- end
394
+ checksum_context = {}
395
+ add_verify_response_headers_handler(context, checksum_context)
396
+ add_verify_response_data_handler(context, checksum_context)
397
+ add_verify_response_success_handler(context, checksum_context)
398
+ end
210
399
 
211
- http_response.on_data do |chunk|
212
- checksum_context[:digest].update(chunk) if checksum_context[:digest]
400
+ def add_verify_response_headers_handler(context, checksum_context)
401
+ validation_list = CHECKSUM_ALGORITHM_PRIORITIES &
402
+ operation_response_algorithms(context)
403
+ context[:http_checksum][:validation_list] = validation_list
404
+
405
+ context.http_response.on_headers do |_status, headers|
406
+ header_name, algorithm = response_header_to_verify(
407
+ headers,
408
+ validation_list
409
+ )
410
+ next unless header_name
411
+
412
+ expected = headers[header_name]
413
+ next if context[:http_checksum][:skip_on_suffix] && /-\d+$/.match(expected)
414
+
415
+ checksum_context[:algorithm] = algorithm
416
+ checksum_context[:header_name] = header_name
417
+ checksum_context[:digest] = ChecksumAlgorithm.digest_for_algorithm(algorithm)
418
+ checksum_context[:expected] = expected
213
419
  end
420
+ end
214
421
 
215
- http_response.on_success do
216
- if checksum_context[:digest] &&
217
- (computed = checksum_context[:digest].base64digest)
422
+ def add_verify_response_data_handler(context, checksum_context)
423
+ context.http_response.on_data do |chunk|
424
+ checksum_context[:digest]&.update(chunk)
425
+ end
426
+ end
218
427
 
219
- if computed != checksum_context[:expected]
220
- raise Aws::Errors::ChecksumError,
221
- "Checksum validation failed on #{checksum_context[:header_name]} "\
222
- "computed: #{computed}, expected: #{checksum_context[:expected]}"
223
- end
428
+ def add_verify_response_success_handler(context, checksum_context)
429
+ context.http_response.on_success do
430
+ next unless checksum_context[:digest]
224
431
 
432
+ computed = checksum_context[:digest].base64digest
433
+ if computed == checksum_context[:expected]
225
434
  context[:http_checksum][:validated] = checksum_context[:algorithm]
435
+ else
436
+ raise Aws::Errors::ChecksumError,
437
+ "Checksum validation failed on #{checksum_context[:header_name]} "\
438
+ "computed: #{computed}, expected: #{checksum_context[:expected]}"
226
439
  end
227
440
  end
228
441
  end
229
442
 
230
- # returns nil if no headers to verify
231
443
  def response_header_to_verify(headers, validation_list)
232
444
  validation_list.each do |algorithm|
233
- header_name = "x-amz-checksum-#{algorithm}"
445
+ header_name = "x-amz-checksum-#{algorithm.downcase}"
234
446
  return [header_name, algorithm] if headers[header_name]
235
447
  end
236
448
  nil
237
449
  end
238
-
239
- # determine where (header vs trailer) a request checksum should be added
240
- def checksum_request_in(context)
241
- if context.operation['unsignedPayload'] ||
242
- context.operation['authtype'] == 'v4-unsigned-body'
243
- 'trailer'
244
- else
245
- 'header'
246
- end
247
- end
248
-
249
- end
250
-
251
- def self.calculate_checksum(algorithm, body)
252
- digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
253
- if body.respond_to?(:read)
254
- ChecksumAlgorithm.update_in_chunks(digest, body)
255
- else
256
- digest.update(body)
257
- end
258
- digest.base64digest
259
- end
260
-
261
- def self.digest_for_algorithm(algorithm)
262
- case algorithm
263
- when 'CRC32'
264
- Digest32.new(Zlib.method(:crc32))
265
- when 'CRC32C'
266
- # this will only be used if input algorithm is CRC32C AND client supports it (crt available)
267
- Digest32.new(Aws::Crt::Checksums.method(:crc32c))
268
- when 'SHA1'
269
- Digest::SHA1.new
270
- when 'SHA256'
271
- Digest::SHA256.new
272
- end
273
- end
274
-
275
- # The trailer size (in bytes) is the overhead + the trailer name +
276
- # the length of the base64 encoded checksum
277
- def self.trailer_length(algorithm, location_name)
278
- CHECKSUM_SIZE[algorithm] + location_name.size
279
- end
280
-
281
- def self.update_in_chunks(digest, io)
282
- loop do
283
- chunk = io.read(CHUNK_SIZE)
284
- break unless chunk
285
- digest.update(chunk)
286
- end
287
- io.rewind
288
450
  end
289
451
 
290
452
  # Wrapper for request body that implements application-layer
291
453
  # chunking with Digest computed on chunks + added as a trailer
292
454
  class AwsChunkedTrailerDigestIO
293
- CHUNK_SIZE = 16384
455
+ CHUNK_SIZE = 16_384
294
456
 
295
457
  def initialize(io, algorithm, location_name)
296
458
  @io = io
@@ -331,7 +493,7 @@ module Aws
331
493
  else
332
494
  trailers = {}
333
495
  trailers[@location_name] = @digest.base64digest
334
- trailers = trailers.map { |k,v| "#{k}:#{v}"}.join("\r\n")
496
+ trailers = trailers.map { |k,v| "#{k}:#{v}" }.join("\r\n")
335
497
  @trailer_io = StringIO.new("0\r\n#{trailers}\r\n\r\n")
336
498
  chunk = @trailer_io.read(length, buf)
337
499
  end
@@ -11,8 +11,8 @@ module Aws
11
11
  CHUNK_SIZE = 1 * 1024 * 1024 # one MB
12
12
 
13
13
  def call(context)
14
- if checksum_required?(context) &&
15
- !context[:checksum_algorithms] && # skip in favor of flexible checksum
14
+ if context.operation.http_checksum_required &&
15
+ !context[:http_checksum][:request_algorithm] && # skip in favor of flexible checksum
16
16
  !context[:s3_express_endpoint] # s3 express endpoints do not support md5
17
17
  body = context.http_request.body
18
18
  context.http_request.headers['Content-Md5'] ||= md5(body)
@@ -22,12 +22,6 @@ module Aws
22
22
 
23
23
  private
24
24
 
25
- def checksum_required?(context)
26
- context.operation.http_checksum_required ||
27
- (context.operation.http_checksum &&
28
- context.operation.http_checksum['requestChecksumRequired'])
29
- end
30
-
31
25
  # @param [File, Tempfile, IO#read, String] value
32
26
  # @return [String<MD5>]
33
27
  def md5(value)
@@ -113,7 +113,7 @@ module Aws
113
113
  signing_algorithm: scheme_name.to_sym,
114
114
  uri_escape_path: !!!auth_scheme['disableDoubleEncoding'],
115
115
  normalize_path: !!!auth_scheme['disableNormalizePath'],
116
- unsigned_headers: %w[content-length user-agent x-amzn-trace-id]
116
+ unsigned_headers: %w[content-length user-agent x-amzn-trace-id expect transfer-encoding connection]
117
117
  )
118
118
  rescue Aws::Sigv4::Errors::MissingCredentialsError
119
119
  raise Aws::Errors::MissingCredentialsError
@@ -25,7 +25,16 @@ module Aws
25
25
  "ACCOUNT_ID_MODE_DISABLED": "Q",
26
26
  "ACCOUNT_ID_MODE_REQUIRED": "R",
27
27
  "SIGV4A_SIGNING": "S",
28
- "RESOLVED_ACCOUNT_ID": "T"
28
+ "RESOLVED_ACCOUNT_ID": "T",
29
+ "FLEXIBLE_CHECKSUMS_REQ_CRC32" : "U",
30
+ "FLEXIBLE_CHECKSUMS_REQ_CRC32C" : "V",
31
+ "FLEXIBLE_CHECKSUMS_REQ_CRC64" : "W",
32
+ "FLEXIBLE_CHECKSUMS_REQ_SHA1" : "X",
33
+ "FLEXIBLE_CHECKSUMS_REQ_SHA256" : "Y",
34
+ "FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED" : "Z",
35
+ "FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED" : "a",
36
+ "FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED" : "b",
37
+ "FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED" : "c"
29
38
  }
30
39
  METRICS
31
40