aws-sdk-core 3.240.0 → 3.241.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfea66796a6586854e469946701deeb09f2b344e82967f505262052efea4c972
4
- data.tar.gz: 98d0d7a3da929b82b7b14098d0041532d94ec0f88bfa04e74c5bcf8286e090b3
3
+ metadata.gz: 523acda999896709fbdf9cc01dd8b2118562458c0b53e7630bf668840ae7d2f7
4
+ data.tar.gz: 8243e904b358bb297810c58fd3038044f8d89835aa4bc49ce8e767b8cba235d7
5
5
  SHA512:
6
- metadata.gz: 65092f9f2795f01ee929393ccdbb06ca55d2e0ea420ac7004c0d24fe6bfd9e3b155cd2d4869b96a6deb64e65c8d4fd0e917e8834ea0cac3602a9289df6de4c4f
7
- data.tar.gz: 806b5e412f3a25b956d607f948e957e71241b25fdea11306d43a9752570d5daa80e33740c543bc499d74412d63db8325c9c9bf39ae4738c971e318ac33503b47
6
+ metadata.gz: 2513bbcb56a3aebebc25793ce65baec8931987fdf99481a6b2e4745c57e0b14fddd003e5c87aa3e59b542f5da8f811d864bfd47f6063999a4bd554dc126d66bf
7
+ data.tar.gz: 6b75f7e235c7153fe1a7f0f2b9b4e6b7e877ae88baaf67ce9dedc4e718450b2743201efa695985abaf6386be28cfd72ab53dff09ee05957aecf1b2ca28c6bf3c
data/CHANGELOG.md CHANGED
@@ -1,6 +1,11 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 3.241.0 (2026-01-05)
5
+ ------------------
6
+
7
+ * Feature - Improved memory efficiency when calculating request checksums.
8
+
4
9
  3.240.0 (2025-12-16)
5
10
  ------------------
6
11
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.240.0
1
+ 3.241.0
@@ -4,7 +4,8 @@ module Aws
4
4
  module Plugins
5
5
  # @api private
6
6
  class ChecksumAlgorithm < Seahorse::Client::Plugin
7
- CHUNK_SIZE = 1 * 1024 * 1024 # one MB
7
+ CHECKSUM_CHUNK_SIZE = 1 * 1024 * 1024 # one MB
8
+ DEFAULT_TRAILER_CHUNK_SIZE = 16_384 # 16 KB
8
9
 
9
10
  # determine the set of supported client side checksum algorithms
10
11
  # CRC32c requires aws-crt (optional sdk dependency) for support
@@ -21,6 +22,7 @@ module Aws
21
22
  end.freeze
22
23
 
23
24
  CRT_ALGORITHMS = %w[CRC32C CRC64NVME].freeze
25
+ DEFAULT_CHECKSUM = 'CRC32'
24
26
 
25
27
  # Priority order of checksum algorithms to validate responses against.
26
28
  # Remove any algorithms not supported by client (ie, depending on CRT availability).
@@ -37,8 +39,6 @@ module Aws
37
39
  'SHA256' => 44 + 1
38
40
  }.freeze
39
41
 
40
- DEFAULT_CHECKSUM = 'CRC32'
41
-
42
42
  option(:request_checksum_calculation,
43
43
  doc_default: 'when_supported',
44
44
  doc_type: 'String',
@@ -162,9 +162,7 @@ module Aws
162
162
  context[:http_checksum] ||= {}
163
163
 
164
164
  # Set validation mode to enabled when supported.
165
- if context.config.response_checksum_validation == 'when_supported'
166
- enable_request_validation_mode(context)
167
- end
165
+ enable_request_validation_mode(context) if context.config.response_checksum_validation == 'when_supported'
168
166
 
169
167
  @handler.call(context)
170
168
  end
@@ -194,9 +192,7 @@ module Aws
194
192
  calculate_request_checksum(context, request_algorithm)
195
193
  end
196
194
 
197
- if should_verify_response_checksum?(context)
198
- add_verify_response_checksum_handlers(context)
199
- end
195
+ add_verify_response_checksum_handlers(context) if should_verify_response_checksum?(context)
200
196
 
201
197
  with_metrics(context.config, algorithm) { @handler.call(context) }
202
198
  end
@@ -334,6 +330,13 @@ module Aws
334
330
  if (algorithm_header = checksum_properties[:request_algorithm_header])
335
331
  headers[algorithm_header] = checksum_properties[:algorithm]
336
332
  end
333
+
334
+ # Trailer implementation within Mac/JRUBY environment is facing some
335
+ # network issues that will need further investigation:
336
+ # * https://github.com/jruby/jruby-openssl/issues/271
337
+ # * https://github.com/jruby/jruby-openssl/issues/317
338
+ return apply_request_checksum(context, headers, checksum_properties) if defined?(JRUBY_VERSION)
339
+
337
340
  case checksum_properties[:in]
338
341
  when 'header'
339
342
  apply_request_checksum(context, headers, checksum_properties)
@@ -346,17 +349,18 @@ module Aws
346
349
 
347
350
  def apply_request_checksum(context, headers, checksum_properties)
348
351
  header_name = checksum_properties[:name]
349
- body = context.http_request.body_contents
350
352
  headers[header_name] = calculate_checksum(
351
353
  checksum_properties[:algorithm],
352
- body
354
+ context.http_request.body
353
355
  )
354
356
  end
355
357
 
356
358
  def calculate_checksum(algorithm, body)
357
359
  digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
358
360
  if body.respond_to?(:read)
361
+ body.rewind
359
362
  update_in_chunks(digest, body)
363
+ body.rewind
360
364
  else
361
365
  digest.update(body)
362
366
  end
@@ -365,7 +369,7 @@ module Aws
365
369
 
366
370
  def update_in_chunks(digest, io)
367
371
  loop do
368
- chunk = io.read(CHUNK_SIZE)
372
+ chunk = io.read(CHECKSUM_CHUNK_SIZE)
369
373
  break unless chunk
370
374
 
371
375
  digest.update(chunk)
@@ -388,13 +392,14 @@ module Aws
388
392
  unless context.http_request.body.respond_to?(:size)
389
393
  raise Aws::Errors::ChecksumError, 'Could not determine length of the body'
390
394
  end
391
- headers['X-Amz-Decoded-Content-Length'] = context.http_request.body.size
392
395
 
393
- context.http_request.body = AwsChunkedTrailerDigestIO.new(
394
- context.http_request.body,
395
- checksum_properties[:algorithm],
396
- location_name
397
- )
396
+ headers['X-Amz-Decoded-Content-Length'] = context.http_request.body.size
397
+ context.http_request.body =
398
+ AwsChunkedTrailerDigestIO.new(
399
+ io: context.http_request.body,
400
+ algorithm: checksum_properties[:algorithm],
401
+ location_name: location_name
402
+ )
398
403
  end
399
404
 
400
405
  def should_verify_response_checksum?(context)
@@ -417,10 +422,7 @@ module Aws
417
422
  context[:http_checksum][:validation_list] = validation_list
418
423
 
419
424
  context.http_response.on_headers do |_status, headers|
420
- header_name, algorithm = response_header_to_verify(
421
- headers,
422
- validation_list
423
- )
425
+ header_name, algorithm = response_header_to_verify(headers, validation_list)
424
426
  next unless header_name
425
427
 
426
428
  expected = headers[header_name]
@@ -466,52 +468,94 @@ module Aws
466
468
  # Wrapper for request body that implements application-layer
467
469
  # chunking with Digest computed on chunks + added as a trailer
468
470
  class AwsChunkedTrailerDigestIO
469
- CHUNK_SIZE = 16_384
471
+ CHUNK_OVERHEAD = 4 # "\r\n\r\n"
472
+ HEX_BASE = 16
470
473
 
471
- def initialize(io, algorithm, location_name)
472
- @io = io
473
- @location_name = location_name
474
- @algorithm = algorithm
475
- @digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
476
- @trailer_io = nil
474
+ def initialize(options = {})
475
+ @io = options.delete(:io)
476
+ @location_name = options.delete(:location_name)
477
+ @algorithm = options.delete(:algorithm)
478
+ @digest = ChecksumAlgorithm.digest_for_algorithm(@algorithm)
479
+ @chunk_size = Thread.current[:net_http_override_body_stream_chunk] || DEFAULT_TRAILER_CHUNK_SIZE
480
+ @overhead_bytes = calculate_overhead(@chunk_size)
481
+ @base_chunk_size = @chunk_size - @overhead_bytes
482
+ @encoded_buffer = +''
483
+ @eof = false
477
484
  end
478
485
 
479
486
  # the size of the application layer aws-chunked + trailer body
480
487
  def size
481
- # compute the number of chunks
482
- # a full chunk has 4 + 4 bytes overhead, a partial chunk is len.to_s(16).size + 4
483
488
  orig_body_size = @io.size
484
- n_full_chunks = orig_body_size / CHUNK_SIZE
485
- partial_bytes = orig_body_size % CHUNK_SIZE
486
- chunked_body_size = n_full_chunks * (CHUNK_SIZE + 8)
487
- chunked_body_size += partial_bytes.to_s(16).size + partial_bytes + 4 unless partial_bytes.zero?
489
+ n_full_chunks = orig_body_size / @base_chunk_size
490
+ partial_bytes = orig_body_size % @base_chunk_size
491
+
492
+ full_chunk_overhead = @base_chunk_size.to_s(HEX_BASE).size + CHUNK_OVERHEAD
493
+ chunked_body_size = n_full_chunks * (@base_chunk_size + full_chunk_overhead)
494
+ unless partial_bytes.zero?
495
+ chunked_body_size += partial_bytes.to_s(HEX_BASE).size + partial_bytes + CHUNK_OVERHEAD
496
+ end
488
497
  trailer_size = ChecksumAlgorithm.trailer_length(@algorithm, @location_name)
489
498
  chunked_body_size + trailer_size
490
499
  end
491
500
 
492
501
  def rewind
493
502
  @io.rewind
503
+ @encoded_buffer = +''
504
+ @eof = false
505
+ @digest = ChecksumAlgorithm.digest_for_algorithm(@algorithm)
494
506
  end
495
507
 
496
- def read(length, buf = nil)
497
- # account for possible leftover bytes at the end, if we have trailer bytes, send them
498
- if @trailer_io
499
- return @trailer_io.read(length, buf)
500
- end
508
+ def read(length = nil, buf = nil)
509
+ return '' if length&.zero?
510
+ return if eof?
511
+
512
+ buf&.clear
513
+ output_buffer = buf || +''
514
+
515
+ fill_encoded_buffer(length)
501
516
 
502
- chunk = @io.read(length)
503
- if chunk
504
- @digest.update(chunk)
505
- application_chunked = "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
506
- return StringIO.new(application_chunked).read(application_chunked.size, buf)
517
+ if length
518
+ output_buffer << @encoded_buffer.slice!(0, length)
507
519
  else
508
- trailers = {}
509
- trailers[@location_name] = @digest.base64digest
510
- trailers = trailers.map { |k,v| "#{k}:#{v}" }.join("\r\n")
511
- @trailer_io = StringIO.new("0\r\n#{trailers}\r\n\r\n")
512
- chunk = @trailer_io.read(length, buf)
520
+ output_buffer << @encoded_buffer
521
+ @encoded_buffer.clear
513
522
  end
514
- chunk
523
+
524
+ output_buffer.empty? && eof? ? nil : output_buffer
525
+ end
526
+
527
+ def eof?
528
+ @eof && @encoded_buffer.empty?
529
+ end
530
+
531
+ private
532
+
533
+ def calculate_overhead(chunk_size)
534
+ chunk_size.to_s(HEX_BASE).size + CHUNK_OVERHEAD
535
+ end
536
+
537
+ def fill_encoded_buffer(required_length)
538
+ return if required_length && @encoded_buffer.bytesize >= required_length
539
+
540
+ while !@eof && fill_data?(required_length)
541
+ chunk = @io.read(@base_chunk_size)
542
+ if chunk && !chunk.empty?
543
+ @digest.update(chunk)
544
+ @encoded_buffer << "#{chunk.bytesize.to_s(HEX_BASE)}\r\n#{chunk}\r\n"
545
+ else
546
+ @encoded_buffer << "0\r\n#{trailer_string}\r\n\r\n"
547
+ @eof = true
548
+ end
549
+ end
550
+ end
551
+
552
+ def trailer_string
553
+ { @location_name => @digest.base64digest }.map { |k, v| "#{k}:#{v}" }.join("\r\n")
554
+ end
555
+
556
+ # Returns true if more data needs to be read into the buffer
557
+ def fill_data?(length)
558
+ length.nil? || @encoded_buffer.bytesize < length
515
559
  end
516
560
  end
517
561
  end
@@ -579,7 +579,7 @@ module Aws::Signin
579
579
  tracer: tracer
580
580
  )
581
581
  context[:gem_name] = 'aws-sdk-core'
582
- context[:gem_version] = '3.240.0'
582
+ context[:gem_version] = '3.241.0'
583
583
  Seahorse::Client::Request.new(handlers, context)
584
584
  end
585
585
 
@@ -56,7 +56,7 @@ module Aws::Signin
56
56
  autoload :EndpointProvider, 'aws-sdk-signin/endpoint_provider'
57
57
  autoload :Endpoints, 'aws-sdk-signin/endpoints'
58
58
 
59
- GEM_VERSION = '3.240.0'
59
+ GEM_VERSION = '3.241.0'
60
60
 
61
61
  end
62
62
 
@@ -698,7 +698,7 @@ module Aws::SSO
698
698
  tracer: tracer
699
699
  )
700
700
  context[:gem_name] = 'aws-sdk-core'
701
- context[:gem_version] = '3.240.0'
701
+ context[:gem_version] = '3.241.0'
702
702
  Seahorse::Client::Request.new(handlers, context)
703
703
  end
704
704
 
data/lib/aws-sdk-sso.rb CHANGED
@@ -56,7 +56,7 @@ module Aws::SSO
56
56
  autoload :EndpointProvider, 'aws-sdk-sso/endpoint_provider'
57
57
  autoload :Endpoints, 'aws-sdk-sso/endpoints'
58
58
 
59
- GEM_VERSION = '3.240.0'
59
+ GEM_VERSION = '3.241.0'
60
60
 
61
61
  end
62
62
 
@@ -1081,7 +1081,7 @@ module Aws::SSOOIDC
1081
1081
  tracer: tracer
1082
1082
  )
1083
1083
  context[:gem_name] = 'aws-sdk-core'
1084
- context[:gem_version] = '3.240.0'
1084
+ context[:gem_version] = '3.241.0'
1085
1085
  Seahorse::Client::Request.new(handlers, context)
1086
1086
  end
1087
1087
 
@@ -56,7 +56,7 @@ module Aws::SSOOIDC
56
56
  autoload :EndpointProvider, 'aws-sdk-ssooidc/endpoint_provider'
57
57
  autoload :Endpoints, 'aws-sdk-ssooidc/endpoints'
58
58
 
59
- GEM_VERSION = '3.240.0'
59
+ GEM_VERSION = '3.241.0'
60
60
 
61
61
  end
62
62
 
@@ -2725,7 +2725,7 @@ module Aws::STS
2725
2725
  tracer: tracer
2726
2726
  )
2727
2727
  context[:gem_name] = 'aws-sdk-core'
2728
- context[:gem_version] = '3.240.0'
2728
+ context[:gem_version] = '3.241.0'
2729
2729
  Seahorse::Client::Request.new(handlers, context)
2730
2730
  end
2731
2731
 
data/lib/aws-sdk-sts.rb CHANGED
@@ -56,7 +56,7 @@ module Aws::STS
56
56
  autoload :EndpointProvider, 'aws-sdk-sts/endpoint_provider'
57
57
  autoload :Endpoints, 'aws-sdk-sts/endpoints'
58
58
 
59
- GEM_VERSION = '3.240.0'
59
+ GEM_VERSION = '3.241.0'
60
60
 
61
61
  end
62
62
 
@@ -6,28 +6,61 @@ module Seahorse
6
6
  module Client
7
7
  # @api private
8
8
  module NetHttp
9
-
10
9
  # @api private
11
10
  module Patches
12
-
13
11
  def self.apply!
14
- Net::HTTPGenericRequest.prepend(PatchDefaultContentType)
12
+ Net::HTTPGenericRequest.prepend(RequestPatches)
15
13
  end
16
14
 
17
- # For requests with bodies, Net::HTTP sets a default content type of:
18
- # 'application/x-www-form-urlencoded'
19
- # There are cases where we should not send content type at all.
20
- # Even when no body is supplied, Net::HTTP uses a default empty body
21
- # and sets it anyway. This patch disables the behavior when a Thread
22
- # local variable is set.
23
- module PatchDefaultContentType
15
+ # Patches intended to override Net::HTTP functionality
16
+ module RequestPatches
17
+ # For requests with bodies, Net::HTTP sets a default content type of:
18
+ # 'application/x-www-form-urlencoded'
19
+ # There are cases where we should not send content type at all.
20
+ # Even when no body is supplied, Net::HTTP uses a default empty body
21
+ # and sets it anyway. This patch disables the behavior when a Thread
22
+ # local variable is set.
23
+ # See: https://github.com/ruby/net-http/issues/205
24
24
  def supply_default_content_type
25
25
  return if Thread.current[:net_http_skip_default_content_type]
26
26
 
27
27
  super
28
28
  end
29
- end
30
29
 
30
+ # IO.copy_stream is capped at 16KB buffer so this patch intends to
31
+ # increase its chunk size for better performance.
32
+ # Only intended to use for S3 TM implementation.
33
+ # See: https://github.com/ruby/net-http/blob/master/lib/net/http/generic_request.rb#L292
34
+ def send_request_with_body_stream(sock, ver, path, f)
35
+ return super unless (chunk_size = Thread.current[:net_http_override_body_stream_chunk])
36
+
37
+ unless content_length || chunked?
38
+ raise ArgumentError, 'Content-Length not given and Transfer-Encoding is not `chunked`'
39
+ end
40
+
41
+ supply_default_content_type
42
+ write_header(sock, ver, path)
43
+ wait_for_continue sock, ver if sock.continue_timeout
44
+ if chunked?
45
+ chunker = Chunker.new(sock)
46
+ RequestIO.custom_stream(f, chunker, chunk_size)
47
+ chunker.finish
48
+ else
49
+ RequestIO.custom_stream(f, sock, chunk_size)
50
+ end
51
+ end
52
+
53
+ class RequestIO
54
+ def self.custom_stream(src, dst, chunk_size)
55
+ copied = 0
56
+ while (chunk = src.read(chunk_size))
57
+ dst.write(chunk)
58
+ copied += chunk.bytesize
59
+ end
60
+ copied
61
+ end
62
+ end
63
+ end
31
64
  end
32
65
  end
33
66
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-sdk-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.240.0
4
+ version: 3.241.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amazon Web Services