From 0f435006b5e74aaea3c6f858879eddc5dfa40293 Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 11:26:18 -0800 Subject: [PATCH 01/10] Add to check http scheme --- .../plugins/checksum_algorithm.rb | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb index c172ef678d0..1bbcd3a783a 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb @@ -331,22 +331,32 @@ def calculate_request_checksum(context, checksum_properties) headers[algorithm_header] = checksum_properties[:algorithm] end - # Trailer implementation within Mac/JRUBY environment is facing some - # network issues that will need further investigation: - # * https://github.com/jruby/jruby-openssl/issues/271 - # * https://github.com/jruby/jruby-openssl/issues/317 - return apply_request_checksum(context, headers, checksum_properties) if defined?(JRUBY_VERSION) - case checksum_properties[:in] when 'header' apply_request_checksum(context, headers, checksum_properties) when 'trailer' + return apply_request_checksum(context, headers, checksum_properties) if fallback_to_header?(context) + apply_request_trailer_checksum(context, headers, checksum_properties) else # nothing end end + def fallback_to_header?(context) + # Trailer implementation within Mac/JRUBY environment is facing some + # network issues that will need further investigation: + # * https://github.com/jruby/jruby-openssl/issues/271 + # * https://github.com/jruby/jruby-openssl/issues/317 + return true if defined?(JRUBY_VERSION) + + # trailer implementation only applies to https + return true if context.http_request.endpoint.scheme == 'http' + + false + end + + def apply_request_checksum(context, headers, checksum_properties) header_name = checksum_properties[:name] headers[header_name] = calculate_checksum( From 66629dee1ab30a66703bccefb984a3239c5c1495 Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 11:49:48 -0800 Subject: [PATCH 02/10] Update to handle http scheme correctly --- .../aws-sdk-s3/spec/plugins/checksum_algorithm_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gems/aws-sdk-s3/spec/plugins/checksum_algorithm_spec.rb b/gems/aws-sdk-s3/spec/plugins/checksum_algorithm_spec.rb index d3452c6e462..526dfa11562 100644 --- a/gems/aws-sdk-s3/spec/plugins/checksum_algorithm_spec.rb +++ b/gems/aws-sdk-s3/spec/plugins/checksum_algorithm_spec.rb @@ -112,6 +112,16 @@ module Plugins end context 'request trailer checksum', skip: defined?(JRUBY_VERSION) do + it 'falls back to header checksums when endpoint scheme is http' do + client = Aws::S3::Client.new(stub_responses: true, endpoint: 'http://example.com') + + resp = client.put_object(bucket: bucket, key: key, body: body, content_encoding: 'gzip') + expect(resp.context.http_request.headers['X-Amz-Content-Sha256']) + .not_to eq('STREAMING-UNSIGNED-PAYLOAD-TRAILER') + expect(resp.context.http_request.headers['Content-Encoding']) + .not_to eq('aws-chunked') + end + it 'sets aws-chunked when no existing Content-Encoding header' do resp = client.put_object(bucket: bucket, key: key, body: body) expect(resp.context.http_request.headers['Content-Encoding']).to eq('aws-chunked') From dc2f855b4c1121daa949aad510e97bb98d447f14 Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 12:09:28 -0800 Subject: [PATCH 03/10] Add possible fix --- .../plugins/checksum_algorithm.rb | 5 ++-- .../aws-sdk-s3/plugins/checksum_algorithm.rb | 23 +++++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb index 1bbcd3a783a..075e2864fa7 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb @@ -353,6 +353,8 @@ def fallback_to_header?(context) # trailer implementation only applies to https return true if context.http_request.endpoint.scheme == 'http' + return true if context[:skip_trailer_checksums] + false end @@ -432,8 +434,7 @@ def add_verify_response_checksum_handlers(context) end def add_verify_response_headers_handler(context, checksum_context) - validation_list = CHECKSUM_ALGORITHM_PRIORITIES & - operation_response_algorithms(context) + validation_list = CHECKSUM_ALGORITHM_PRIORITIES & operation_response_algorithms(context) context[:http_checksum][:validation_list] = validation_list context.http_response.on_headers do |_status, headers| diff --git a/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb b/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb index c8a5ed4ba70..0a253e5a3d2 100644 --- a/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb @@ -18,12 +18,25 @@ def call(context) end end + # Handler to disable trailer checksums for S3-compatible services + # that don't support STREAMING-UNSIGNED-PAYLOAD-TRAILER + class SkipTrailerChecksumsHandler < Seahorse::Client::Handler + def call(context) + context[:skip_trailer_checksums] = true if custom_endpoint?(context.config) + @handler.call(context) + end + + private + + def custom_endpoint?(config) + !config.regional_endpoint || !config.endpoint_provider.instance_of?(Aws::S3::EndpointProvider) + end + end + + def add_handlers(handlers, _config) - handlers.add( - SkipWholeMultipartGetChecksumsHandler, - step: :initialize, - operations: [:get_object] - ) + handlers.add(SkipWholeMultipartGetChecksumsHandler, step: :initialize, operations: [:get_object]) + handlers.add(SkipTrailerChecksumsHandler, step: :build, priority: 16, operations: %i[put_object upload_part]) end end end From 25f6d04bc3cdd05b90188203e5c549cd21f94ba5 Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 12:48:34 -0800 Subject: [PATCH 04/10] Handle custom endpoints and providers --- .../plugins/checksum_algorithm.rb | 4 +-- .../aws-sdk-s3/plugins/checksum_algorithm.rb | 1 + .../spec/plugins/checksum_algorithm_spec.rb | 25 +++++++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb index 075e2864fa7..3b8d4f9e454 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb @@ -353,9 +353,7 @@ def fallback_to_header?(context) # trailer implementation only applies to https return true if context.http_request.endpoint.scheme == 'http' - return true if context[:skip_trailer_checksums] - - false + context[:skip_trailer_checksums] end diff --git a/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb b/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb index 0a253e5a3d2..dcb976c8411 100644 --- a/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb @@ -20,6 +20,7 @@ def call(context) # Handler to disable trailer checksums for S3-compatible services # that don't support STREAMING-UNSIGNED-PAYLOAD-TRAILER + # See: https://github.com/aws/aws-sdk-ruby/issues/3338 class SkipTrailerChecksumsHandler < Seahorse::Client::Handler def call(context) context[:skip_trailer_checksums] = true if custom_endpoint?(context.config) diff --git a/gems/aws-sdk-s3/spec/plugins/checksum_algorithm_spec.rb b/gems/aws-sdk-s3/spec/plugins/checksum_algorithm_spec.rb index 526dfa11562..08a0b03f674 100644 --- a/gems/aws-sdk-s3/spec/plugins/checksum_algorithm_spec.rb +++ b/gems/aws-sdk-s3/spec/plugins/checksum_algorithm_spec.rb @@ -13,7 +13,7 @@ module Plugins let(:body) { 'hello world' } let(:digest) { 'DUoRhQ==' } - let(:body_part_1) { 'hello '} + let(:body_part_1) { 'hello ' } let(:digest_part_1) { '7YH59g==' } it 'validates the checksum on an Object GET' do @@ -116,10 +116,25 @@ module Plugins client = Aws::S3::Client.new(stub_responses: true, endpoint: 'http://example.com') resp = client.put_object(bucket: bucket, key: key, body: body, content_encoding: 'gzip') - expect(resp.context.http_request.headers['X-Amz-Content-Sha256']) - .not_to eq('STREAMING-UNSIGNED-PAYLOAD-TRAILER') - expect(resp.context.http_request.headers['Content-Encoding']) - .not_to eq('aws-chunked') + expect(resp.context.http_request.headers['X-Amz-Content-Sha256']).not_to eq('STREAMING-UNSIGNED-PAYLOAD-TRAILER') + expect(resp.context.http_request.headers['Content-Encoding']).not_to include('aws-chunked') + end + + it 'falls back to header checksums for custom endpoint URLs' do + client = Aws::S3::Client.new(stub_responses: true, endpoint: 'https://example.com') + + resp = client.put_object(bucket: bucket, key: key, body: body, content_encoding: 'gzip') + expect(resp.context.http_request.headers['X-Amz-Content-Sha256']).not_to eq('STREAMING-UNSIGNED-PAYLOAD-TRAILER') + expect(resp.context.http_request.headers['Content-Encoding']).not_to include('aws-chunked') + end + + it 'falls back to header checksums for custom endpoint providers' do + custom_endpoint_provider = Class.new(Aws::S3::EndpointProvider).new + client = Aws::S3::Client.new(stub_responses: true, endpoint_provider: custom_endpoint_provider) + + resp = client.put_object(bucket: bucket, key: key, body: body, content_encoding: 'gzip') + expect(resp.context.http_request.headers['X-Amz-Content-Sha256']).not_to eq('STREAMING-UNSIGNED-PAYLOAD-TRAILER') + expect(resp.context.http_request.headers['Content-Encoding']).not_to include('aws-chunked') end it 'sets aws-chunked when no existing Content-Encoding header' do From 42db12fc085a55d76b30ef8208981b8a38e10947 Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 12:56:54 -0800 Subject: [PATCH 05/10] Add changelog entries --- gems/aws-sdk-core/CHANGELOG.md | 2 ++ gems/aws-sdk-s3/CHANGELOG.md | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/gems/aws-sdk-core/CHANGELOG.md b/gems/aws-sdk-core/CHANGELOG.md index 4facff7a145..5eb2de0e0fb 100644 --- a/gems/aws-sdk-core/CHANGELOG.md +++ b/gems/aws-sdk-core/CHANGELOG.md @@ -1,6 +1,8 @@ Unreleased Changes ------------------ +* Issue - Disable request trailer checksums when using non-HTTPs endpoints. + 3.241.2 (2026-01-07) ------------------ diff --git a/gems/aws-sdk-s3/CHANGELOG.md b/gems/aws-sdk-s3/CHANGELOG.md index 92271206fca..559001b2b15 100644 --- a/gems/aws-sdk-s3/CHANGELOG.md +++ b/gems/aws-sdk-s3/CHANGELOG.md @@ -1,7 +1,9 @@ Unreleased Changes ------------------ -1.210.1 (2026-01-06) +* Issue - Falls back to header request checksums when using custom endpoints or endpoint providers for PutObject and UploadPart operations. + +* 1.210.1 (2026-01-06) ------------------ * Issue - Normalize response encoding to UTF-8 for proper XML error parsing in HTTP 200 responses. From ee879595917b1e621b1a57c121f8c36f242022f4 Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 12:58:00 -0800 Subject: [PATCH 06/10] Bump min core --- build_tools/services.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_tools/services.rb b/build_tools/services.rb index d95b7938193..d91ae467fbd 100644 --- a/build_tools/services.rb +++ b/build_tools/services.rb @@ -9,10 +9,10 @@ class ServiceEnumerator MANIFEST_PATH = File.expand_path('../../services.json', __FILE__) # Minimum `aws-sdk-core` version for new gem builds - MINIMUM_CORE_VERSION = "3.241.0" + MINIMUM_CORE_VERSION = "3.241.3" # Minimum `aws-sdk-core` version for new S3 gem builds - MINIMUM_CORE_VERSION_S3 = "3.241.0" + MINIMUM_CORE_VERSION_S3 = "3.241.3" EVENTSTREAM_PLUGIN = "Aws::Plugins::EventStreamConfiguration" From 518ba1d9adf0c594a529cf99e4077d8ba5058173 Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 13:01:01 -0800 Subject: [PATCH 07/10] Minor fixes --- .../aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb | 1 - gems/aws-sdk-s3/CHANGELOG.md | 2 +- gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb index 3b8d4f9e454..0a52fe21da4 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb @@ -356,7 +356,6 @@ def fallback_to_header?(context) context[:skip_trailer_checksums] end - def apply_request_checksum(context, headers, checksum_properties) header_name = checksum_properties[:name] headers[header_name] = calculate_checksum( diff --git a/gems/aws-sdk-s3/CHANGELOG.md b/gems/aws-sdk-s3/CHANGELOG.md index 559001b2b15..0e94a15ac9d 100644 --- a/gems/aws-sdk-s3/CHANGELOG.md +++ b/gems/aws-sdk-s3/CHANGELOG.md @@ -3,7 +3,7 @@ Unreleased Changes * Issue - Falls back to header request checksums when using custom endpoints or endpoint providers for PutObject and UploadPart operations. -* 1.210.1 (2026-01-06) +1.210.1 (2026-01-06) ------------------ * Issue - Normalize response encoding to UTF-8 for proper XML error parsing in HTTP 200 responses. diff --git a/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb b/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb index dcb976c8411..b84e969cfb1 100644 --- a/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-s3/lib/aws-sdk-s3/plugins/checksum_algorithm.rb @@ -34,7 +34,6 @@ def custom_endpoint?(config) end end - def add_handlers(handlers, _config) handlers.add(SkipWholeMultipartGetChecksumsHandler, step: :initialize, operations: [:get_object]) handlers.add(SkipTrailerChecksumsHandler, step: :build, priority: 16, operations: %i[put_object upload_part]) From 345da423b18358547fb9b816397ddd92b93ab794 Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 14:06:25 -0800 Subject: [PATCH 08/10] Update based on feedbacks --- .../plugins/checksum_algorithm.rb | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb index 0a52fe21da4..c6608968574 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb @@ -275,8 +275,7 @@ def checksum_provided_as_header?(headers) # 1. **No existing checksum in header**: Skips if checksum header already present # 2. **Operation support**: Considers model, client configuration and user input. def should_calculate_request_checksum?(context) - !checksum_provided_as_header?(context.http_request.headers) && - checksum_applicable?(context) + !checksum_provided_as_header?(context.http_request.headers) && checksum_applicable?(context) end # Checks if checksum calculation should proceed based on operation requirements and client settings. @@ -317,12 +316,13 @@ def choose_request_algorithm!(context) end def checksum_request_in(context) - if context.operation['unsignedPayload'] || - context.operation['authtype'] == 'v4-unsigned-body' - 'trailer' - else - 'header' - end + return 'header' unless supports_trailer_checksums?(context.operation) + + should_fallback_to_header?(context) ? 'header' : 'trailer' + end + + def supports_trailer_checksums?(operation) + operation['unsignedPayload'] || context.operation['authtype'] == 'v4-unsigned-body' end def calculate_request_checksum(context, checksum_properties) @@ -335,22 +335,20 @@ def calculate_request_checksum(context, checksum_properties) when 'header' apply_request_checksum(context, headers, checksum_properties) when 'trailer' - return apply_request_checksum(context, headers, checksum_properties) if fallback_to_header?(context) - apply_request_trailer_checksum(context, headers, checksum_properties) else # nothing end end - def fallback_to_header?(context) + def should_fallback_to_header?(context) # Trailer implementation within Mac/JRUBY environment is facing some # network issues that will need further investigation: # * https://github.com/jruby/jruby-openssl/issues/271 # * https://github.com/jruby/jruby-openssl/issues/317 return true if defined?(JRUBY_VERSION) - # trailer implementation only applies to https + # AWS chunked streaming with SigV4 signing requires HTTPS return true if context.http_request.endpoint.scheme == 'http' context[:skip_trailer_checksums] From 859d58a1f0e3e22865e059c8a83bcf7b70eed6c9 Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 14:14:27 -0800 Subject: [PATCH 09/10] Fix silly --- .../aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb index c6608968574..b43b102a50f 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb @@ -322,7 +322,7 @@ def checksum_request_in(context) end def supports_trailer_checksums?(operation) - operation['unsignedPayload'] || context.operation['authtype'] == 'v4-unsigned-body' + operation['unsignedPayload'] || operation['authtype'] == 'v4-unsigned-body' end def calculate_request_checksum(context, checksum_properties) From f58f24d957ec5f837c220aa751ed6acff748e2cf Mon Sep 17 00:00:00 2001 From: Juli Tera Date: Wed, 7 Jan 2026 14:20:31 -0800 Subject: [PATCH 10/10] Update commenbt --- .../lib/aws-sdk-core/plugins/checksum_algorithm.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb index b43b102a50f..0bb447e67a3 100644 --- a/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb +++ b/gems/aws-sdk-core/lib/aws-sdk-core/plugins/checksum_algorithm.rb @@ -348,7 +348,8 @@ def should_fallback_to_header?(context) # * https://github.com/jruby/jruby-openssl/issues/317 return true if defined?(JRUBY_VERSION) - # AWS chunked streaming with SigV4 signing requires HTTPS + # Chunked signing is currently not supported + # Https is required for unsigned payload for security return true if context.http_request.endpoint.scheme == 'http' context[:skip_trailer_checksums]