aws-sdk-s3 1.209.0 → 1.211.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: 96d905ca855eb2dbe7fc73b47740d9b107cd13d54248e50cd04c42c9b1cbec06
4
- data.tar.gz: f47c0a2b631896eb327368850ba7b2d8e57cbfb4b31ac910b197488bc699deda
3
+ metadata.gz: fa1488f27a1edbfe2321ab130e7d8ddd5581c06fd3ba103221733aa2ee008d6a
4
+ data.tar.gz: 7b01a193c82e92c9afe687cda125e983c1b135f3916db8b673970c674428961a
5
5
  SHA512:
6
- metadata.gz: 491de1ec6c39f3a6b85fe3da244ad15f30865e44ca357289a8edbeffefe08eeb3794626827293c45e0c5365864db4eebcbec64b757ea287c3176feb5b69299ac
7
- data.tar.gz: cb89af8f3d16403d37cbcab90b9b51de1c859bfe8eb689eededbbfd8efdbffc580acd16f2a7594bf75916497cac959325436562bcb2f5b90ec1a600f40765cf1
6
+ metadata.gz: 84dd3e14781c28f0a96c1caed87829e874b6ec18e0dc66e8d33a887951aba8e1ba48c399ed11495a05de2433cacf5c04bfa31f301b7861fd830e4f924e79dacb
7
+ data.tar.gz: 5aa7fcabbcc7027e0d7ebc14e80fe80c5ce78433e4af090a6a9d73b5ee7c2af75031a0fb796a96dcc0e83a113d7565910ed3c93eae7ec8e41b3d966f26fe0241
data/CHANGELOG.md CHANGED
@@ -1,6 +1,27 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 1.211.0 (2026-01-08)
5
+ ------------------
6
+
7
+ * Feature - Code Generated Changes, see `./build_tools` or `aws-sdk-core`'s CHANGELOG.md for details.
8
+
9
+ * Issue - Falls back to header request checksums when using custom endpoints or endpoint providers for PutObject and UploadPart operations.
10
+
11
+ 1.210.1 (2026-01-06)
12
+ ------------------
13
+
14
+ * Issue - Normalize response encoding to UTF-8 for proper XML error parsing in HTTP 200 responses.
15
+
16
+ 1.210.0 (2026-01-05)
17
+ ------------------
18
+
19
+ * Feature - Code Generated Changes, see `./build_tools` or `aws-sdk-core`'s CHANGELOG.md for details.
20
+
21
+ * Feature - Added `:http_chunk_size` parameter to `TransferManager#upload_file` to control the buffer size when streaming request bodies over HTTP. Larger chunk sizes may improve network throughput at the cost of higher memory usage (Ruby MRI only).
22
+
23
+ * Feature - Improved memory efficiency when calculating request checksums for large file uploads (Ruby MRI only).
24
+
4
25
  1.209.0 (2025-12-23)
5
26
  ------------------
6
27
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.209.0
1
+ 1.211.0
@@ -17659,7 +17659,7 @@ module Aws::S3
17659
17659
  # [3]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-using-rest-api.html
17660
17660
  # [4]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html
17661
17661
  #
17662
- # @option params [String, StringIO, File] :body
17662
+ # @option params [String, IO] :body
17663
17663
  # Object data.
17664
17664
  #
17665
17665
  # @option params [required, String] :bucket
@@ -20968,7 +20968,7 @@ module Aws::S3
20968
20968
  # [16]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html
20969
20969
  # [17]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html
20970
20970
  #
20971
- # @option params [String, StringIO, File] :body
20971
+ # @option params [String, IO] :body
20972
20972
  # Object data.
20973
20973
  #
20974
20974
  # @option params [required, String] :bucket
@@ -22283,7 +22283,7 @@ module Aws::S3
22283
22283
  tracer: tracer
22284
22284
  )
22285
22285
  context[:gem_name] = 'aws-sdk-s3'
22286
- context[:gem_version] = '1.209.0'
22286
+ context[:gem_version] = '1.211.0'
22287
22287
  Seahorse::Client::Request.new(handlers, context)
22288
22288
  end
22289
22289
 
@@ -4121,6 +4121,7 @@ module Aws::S3
4121
4121
  "requestAlgorithmMember" => "checksum_algorithm",
4122
4122
  "requestChecksumRequired" => false,
4123
4123
  }
4124
+ o['unsignedPayload'] = true
4124
4125
  o.input = Shapes::ShapeRef.new(shape: PutObjectRequest)
4125
4126
  o.output = Shapes::ShapeRef.new(shape: PutObjectOutput)
4126
4127
  o.errors << Shapes::ShapeRef.new(shape: InvalidRequest)
@@ -4309,6 +4310,7 @@ module Aws::S3
4309
4310
  "requestAlgorithmMember" => "checksum_algorithm",
4310
4311
  "requestChecksumRequired" => false,
4311
4312
  }
4313
+ o['unsignedPayload'] = true
4312
4314
  o.input = Shapes::ShapeRef.new(shape: UploadPartRequest)
4313
4315
  o.output = Shapes::ShapeRef.new(shape: UploadPartOutput)
4314
4316
  end)
@@ -15,6 +15,7 @@ module Aws
15
15
  def initialize(options = {})
16
16
  @client = options[:client] || Client.new
17
17
  @executor = options[:executor]
18
+ @http_chunk_size = options[:http_chunk_size]
18
19
  @multipart_threshold = options[:multipart_threshold] || DEFAULT_MULTIPART_THRESHOLD
19
20
  end
20
21
 
@@ -37,7 +38,11 @@ module Aws
37
38
  def upload(source, options = {})
38
39
  Aws::Plugins::UserAgent.metric('S3_TRANSFER') do
39
40
  if File.size(source) >= @multipart_threshold
40
- MultipartFileUploader.new(client: @client, executor: @executor).upload(source, options)
41
+ MultipartFileUploader.new(
42
+ client: @client,
43
+ executor: @executor,
44
+ http_chunk_size: @http_chunk_size
45
+ ).upload(source, options)
41
46
  else
42
47
  put_object(source, options)
43
48
  end
@@ -59,7 +64,10 @@ module Aws
59
64
  options[:on_chunk_sent] = single_part_progress(callback)
60
65
  end
61
66
  open_file(source) do |file|
67
+ Thread.current[:net_http_override_body_stream_chunk] = @http_chunk_size if @http_chunk_size
62
68
  @client.put_object(options.merge(body: file))
69
+ ensure
70
+ Thread.current[:net_http_override_body_stream_chunk] = nil
63
71
  end
64
72
  end
65
73
 
@@ -22,6 +22,7 @@ module Aws
22
22
  def initialize(options = {})
23
23
  @client = options[:client] || Client.new
24
24
  @executor = options[:executor]
25
+ @http_chunk_size = options[:http_chunk_size]
25
26
  end
26
27
 
27
28
  # @return [Client]
@@ -78,7 +79,7 @@ module Aws
78
79
  rescue MultipartUploadError => e
79
80
  raise e
80
81
  rescue StandardError => e
81
- msg = "failed to abort multipart upload: #{e.message}. " \
82
+ msg = "failed to abort multipart upload: #{e&.message}. " \
82
83
  "Multipart upload failed: #{errors.map(&:message).join('; ')}"
83
84
  raise MultipartUploadError.new(msg, errors + [e])
84
85
  end
@@ -150,6 +151,7 @@ module Aws
150
151
 
151
152
  upload_attempts += 1
152
153
  @executor.post(part) do |p|
154
+ Thread.current[:net_http_override_body_stream_chunk] = @http_chunk_size if @http_chunk_size
153
155
  update_progress(progress, p)
154
156
  resp = @client.upload_part(p)
155
157
  p[:body].close
@@ -160,6 +162,7 @@ module Aws
160
162
  abort_upload = true
161
163
  errors << e
162
164
  ensure
165
+ Thread.current[:net_http_override_body_stream_chunk] = nil if @http_chunk_size
163
166
  completion_queue << :done
164
167
  end
165
168
  end
@@ -18,12 +18,25 @@ module Aws
18
18
  end
19
19
  end
20
20
 
21
+ # Handler to disable trailer checksums for S3-compatible services
22
+ # that don't support STREAMING-UNSIGNED-PAYLOAD-TRAILER
23
+ # See: https://github.com/aws/aws-sdk-ruby/issues/3338
24
+ class SkipTrailerChecksumsHandler < Seahorse::Client::Handler
25
+ def call(context)
26
+ context[:skip_trailer_checksums] = true if custom_endpoint?(context.config)
27
+ @handler.call(context)
28
+ end
29
+
30
+ private
31
+
32
+ def custom_endpoint?(config)
33
+ !config.regional_endpoint || !config.endpoint_provider.instance_of?(Aws::S3::EndpointProvider)
34
+ end
35
+ end
36
+
21
37
  def add_handlers(handlers, _config)
22
- handlers.add(
23
- SkipWholeMultipartGetChecksumsHandler,
24
- step: :initialize,
25
- operations: [:get_object]
26
- )
38
+ handlers.add(SkipWholeMultipartGetChecksumsHandler, step: :initialize, operations: [:get_object])
39
+ handlers.add(SkipTrailerChecksumsHandler, step: :build, priority: 16, operations: %i[put_object upload_part])
27
40
  end
28
41
  end
29
42
  end
@@ -3,15 +3,28 @@
3
3
  module Aws
4
4
  module S3
5
5
  module Plugins
6
-
7
6
  # A handful of Amazon S3 operations will respond with a 200 status
8
7
  # code but will send an error in the response body. This plugin
9
8
  # injects a handler that will parse 200 response bodies for potential
10
9
  # errors, allowing them to be retried.
11
10
  # @api private
12
11
  class Http200Errors < Seahorse::Client::Plugin
13
-
14
12
  class Handler < Seahorse::Client::Handler
13
+ # A regular expression to match error codes in the response body
14
+ CODE_PATTERN = %r{<Code>(.+?)</Code>}.freeze
15
+ private_constant :CODE_PATTERN
16
+
17
+ # A list of encodings we force into UTF-8
18
+ ENCODINGS_TO_FIX = [Encoding::US_ASCII, Encoding::ASCII_8BIT].freeze
19
+ private_constant :ENCODINGS_TO_FIX
20
+
21
+ # A regular expression to match detect errors in the response body
22
+ ERROR_PATTERN = /<\?xml\s[^>]*\?>\s*<Error>/.freeze
23
+ private_constant :ERROR_PATTERN
24
+
25
+ # A regular expression to match an error message in the response body
26
+ MESSAGE_PATTERN = %r{<Message>(.+?)</Message>}.freeze
27
+ private_constant :MESSAGE_PATTERN
15
28
 
16
29
  def call(context)
17
30
  @handler.call(context).on(200) do |response|
@@ -28,29 +41,37 @@ module Aws
28
41
 
29
42
  private
30
43
 
31
- # Streaming outputs are not subject to 200 errors.
32
- def streaming_output?(output)
33
- if (payload = output[:payload_member])
34
- # checking ref and shape
35
- payload['streaming'] || payload.shape['streaming'] ||
36
- payload.eventstream
37
- else
38
- false
44
+ def build_error(context, code, message)
45
+ S3::Errors.error_class(code).new(context, message)
46
+ end
47
+
48
+ def check_for_error(context)
49
+ xml = normalize_encoding(context.http_response.body_contents)
50
+
51
+ if xml.match?(ERROR_PATTERN)
52
+ error_code = xml.match(CODE_PATTERN)[1]
53
+ error_message = xml.match(MESSAGE_PATTERN)[1]
54
+ build_error(context, error_code, error_message)
55
+ elsif incomplete_xml_body?(xml, context.operation.output)
56
+ Seahorse::Client::NetworkingError.new(
57
+ build_error(context, 'InternalError', 'Empty or incomplete response body')
58
+ )
39
59
  end
40
60
  end
41
61
 
62
+ # Must have a member in the body and have the start of an XML Tag.
63
+ # Other incomplete xml bodies will result in an XML ParsingError.
64
+ def incomplete_xml_body?(xml, output)
65
+ members_in_body?(output) && !xml.match(/<\w/)
66
+ end
67
+
42
68
  # Checks if the output shape is a structure shape and has members that
43
69
  # are in the body for the case of a payload and a normal structure. A
44
70
  # non-structure shape will not have members in the body. In the case
45
71
  # of a string or blob, the body contents would have been checked first
46
72
  # before this method is called in incomplete_xml_body?.
47
73
  def members_in_body?(output)
48
- shape =
49
- if output[:payload_member]
50
- output[:payload_member].shape
51
- else
52
- output.shape
53
- end
74
+ shape = resolve_shape(output)
54
75
 
55
76
  if structure_shape?(shape)
56
77
  shape.members.any? { |_, k| k.location.nil? }
@@ -59,30 +80,33 @@ module Aws
59
80
  end
60
81
  end
61
82
 
62
- def structure_shape?(shape)
63
- shape.is_a?(Seahorse::Model::Shapes::StructureShape)
83
+ # Fixes encoding issues when S3 returns UTF-8 content with missing charset in Content-Type header or omits
84
+ # Content-Type header entirely. Net::HTTP defaults to US-ASCII or ASCII-8BIT when charset is unspecified.
85
+ def normalize_encoding(xml)
86
+ return xml unless xml.is_a?(String) && ENCODINGS_TO_FIX.include?(xml.encoding)
87
+
88
+ xml.force_encoding('UTF-8')
64
89
  end
65
90
 
66
- # Must have a member in the body and have the start of an XML Tag.
67
- # Other incomplete xml bodies will result in an XML ParsingError.
68
- def incomplete_xml_body?(xml, output)
69
- members_in_body?(output) && !xml.match(/<\w/)
91
+ def resolve_shape(output)
92
+ return output.shape unless output[:payload_member]
93
+
94
+ output[:payload_member].shape
70
95
  end
71
96
 
72
- def check_for_error(context)
73
- xml = context.http_response.body_contents
74
- if xml.match(/<\?xml\s[^>]*\?>\s*<Error>/)
75
- error_code = xml.match(%r{<Code>(.+?)</Code>})[1]
76
- error_message = xml.match(%r{<Message>(.+?)</Message>})[1]
77
- S3::Errors.error_class(error_code).new(context, error_message)
78
- elsif incomplete_xml_body?(xml, context.operation.output)
79
- Seahorse::Client::NetworkingError.new(
80
- S3::Errors
81
- .error_class('InternalError')
82
- .new(context, 'Empty or incomplete response body')
83
- )
97
+ # Streaming outputs are not subject to 200 errors.
98
+ def streaming_output?(output)
99
+ if (payload = output[:payload_member])
100
+ # checking ref and shape
101
+ payload['streaming'] || payload.shape['streaming'] || payload.eventstream
102
+ else
103
+ false
84
104
  end
85
105
  end
106
+
107
+ def structure_shape?(shape)
108
+ shape.is_a?(Seahorse::Model::Shapes::StructureShape)
109
+ end
86
110
  end
87
111
 
88
112
  handler(Handler, step: :sign)
@@ -205,6 +205,11 @@ module Aws
205
205
  # @option options [Integer] :thread_count (10) Customize threads used in the multipart upload.
206
206
  # Only used when no custom executor is provided (creates {DefaultExecutor} with the given thread count).
207
207
  #
208
+ # @option option [Integer] :http_chunk_size (16384) Size in bytes for each chunk when streaming request bodies
209
+ # over HTTP. Controls the buffer size used when sending data to S3. Larger values may improve throughput by
210
+ # reducing the number of network writes, but use more memory. Custom values must be at least 16KB.
211
+ # Only Ruby MRI is supported.
212
+ #
208
213
  # @option options [Proc] :progress_callback (nil)
209
214
  # A Proc that will be called when each chunk of the upload is sent.
210
215
  # It will be invoked with `[bytes_read]` and `[total_sizes]`.
@@ -221,9 +226,22 @@ module Aws
221
226
  # @see Client#upload_part
222
227
  def upload_file(source, bucket:, key:, **options)
223
228
  upload_opts = options.merge(bucket: bucket, key: key)
229
+ http_chunk_size =
230
+ if defined?(JRUBY_VERSION)
231
+ nil
232
+ else
233
+ chunk = upload_opts.delete(:http_chunk_size)
234
+ if chunk && chunk < Aws::Plugins::ChecksumAlgorithm::DEFAULT_TRAILER_CHUNK_SIZE
235
+ raise ArgumentError, ':http_chunk_size must be at least 16384 bytes (16KB)'
236
+ end
237
+
238
+ chunk
239
+ end
240
+
224
241
  executor = @executor || DefaultExecutor.new(max_threads: upload_opts.delete(:thread_count))
225
242
  uploader = FileUploader.new(
226
243
  multipart_threshold: upload_opts.delete(:multipart_threshold),
244
+ http_chunk_size: http_chunk_size,
227
245
  client: @client,
228
246
  executor: executor
229
247
  )
data/lib/aws-sdk-s3.rb CHANGED
@@ -75,7 +75,7 @@ module Aws::S3
75
75
  autoload :ObjectVersion, 'aws-sdk-s3/object_version'
76
76
  autoload :EventStreams, 'aws-sdk-s3/event_streams'
77
77
 
78
- GEM_VERSION = '1.209.0'
78
+ GEM_VERSION = '1.211.0'
79
79
 
80
80
  end
81
81
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-sdk-s3
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.209.0
4
+ version: 1.211.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amazon Web Services
@@ -46,7 +46,7 @@ dependencies:
46
46
  version: '3'
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 3.234.0
49
+ version: 3.241.3
50
50
  type: :runtime
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
@@ -56,7 +56,7 @@ dependencies:
56
56
  version: '3'
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: 3.234.0
59
+ version: 3.241.3
60
60
  description: Official AWS Ruby gem for Amazon Simple Storage Service (Amazon S3).
61
61
  This gem is part of the AWS SDK for Ruby.
62
62
  email: