aws-sdk-core 3.171.1 → 3.234.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.
Files changed (199) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +787 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-defaults/default_configuration.rb +5 -6
  5. data/lib/aws-defaults.rb +4 -1
  6. data/lib/aws-sdk-core/arn.rb +1 -3
  7. data/lib/aws-sdk-core/assume_role_credentials.rb +21 -13
  8. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +16 -9
  9. data/lib/aws-sdk-core/binary/decode_handler.rb +3 -9
  10. data/lib/aws-sdk-core/binary/encode_handler.rb +1 -1
  11. data/lib/aws-sdk-core/binary/event_builder.rb +34 -37
  12. data/lib/aws-sdk-core/binary/event_stream_decoder.rb +1 -0
  13. data/lib/aws-sdk-core/binary/event_stream_encoder.rb +4 -3
  14. data/lib/aws-sdk-core/cbor/decoder.rb +308 -0
  15. data/lib/aws-sdk-core/cbor/encoder.rb +243 -0
  16. data/lib/aws-sdk-core/cbor.rb +53 -0
  17. data/lib/aws-sdk-core/client_side_monitoring.rb +9 -0
  18. data/lib/aws-sdk-core/client_stubs.rb +33 -55
  19. data/lib/aws-sdk-core/credential_provider.rb +8 -1
  20. data/lib/aws-sdk-core/credential_provider_chain.rb +74 -25
  21. data/lib/aws-sdk-core/credentials.rb +19 -6
  22. data/lib/aws-sdk-core/ec2_metadata.rb +1 -1
  23. data/lib/aws-sdk-core/ecs_credentials.rb +92 -24
  24. data/lib/aws-sdk-core/endpoints/endpoint.rb +3 -1
  25. data/lib/aws-sdk-core/endpoints/matchers.rb +21 -19
  26. data/lib/aws-sdk-core/endpoints.rb +106 -22
  27. data/lib/aws-sdk-core/error_handler.rb +46 -0
  28. data/lib/aws-sdk-core/errors.rb +14 -5
  29. data/lib/aws-sdk-core/event_emitter.rb +1 -17
  30. data/lib/aws-sdk-core/ini_parser.rb +7 -0
  31. data/lib/aws-sdk-core/instance_profile_credentials.rb +168 -155
  32. data/lib/aws-sdk-core/json/builder.rb +8 -1
  33. data/lib/aws-sdk-core/json/error_handler.rb +29 -13
  34. data/lib/aws-sdk-core/json/handler.rb +13 -6
  35. data/lib/aws-sdk-core/json/json_engine.rb +3 -1
  36. data/lib/aws-sdk-core/json/oj_engine.rb +7 -1
  37. data/lib/aws-sdk-core/json/parser.rb +33 -3
  38. data/lib/aws-sdk-core/json.rb +43 -14
  39. data/lib/aws-sdk-core/log/formatter.rb +6 -0
  40. data/lib/aws-sdk-core/log/param_filter.rb +2 -2
  41. data/lib/aws-sdk-core/log/param_formatter.rb +7 -3
  42. data/lib/aws-sdk-core/log.rb +10 -0
  43. data/lib/aws-sdk-core/lru_cache.rb +75 -0
  44. data/lib/aws-sdk-core/pageable_response.rb +3 -1
  45. data/lib/aws-sdk-core/param_validator.rb +9 -4
  46. data/lib/aws-sdk-core/plugins/bearer_authorization.rb +2 -0
  47. data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +348 -169
  48. data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +1 -1
  49. data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +14 -2
  50. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +78 -56
  51. data/lib/aws-sdk-core/plugins/endpoint_pattern.rb +40 -32
  52. data/lib/aws-sdk-core/plugins/global_configuration.rb +8 -9
  53. data/lib/aws-sdk-core/plugins/http_checksum.rb +3 -8
  54. data/lib/aws-sdk-core/plugins/invocation_id.rb +1 -11
  55. data/lib/aws-sdk-core/plugins/logging.rb +2 -0
  56. data/lib/aws-sdk-core/plugins/protocols/api_gateway.rb +3 -1
  57. data/lib/aws-sdk-core/plugins/protocols/ec2.rb +2 -24
  58. data/lib/aws-sdk-core/plugins/protocols/json_rpc.rb +6 -8
  59. data/lib/aws-sdk-core/plugins/protocols/query.rb +4 -2
  60. data/lib/aws-sdk-core/plugins/protocols/rest_json.rb +3 -15
  61. data/lib/aws-sdk-core/plugins/protocols/rest_xml.rb +3 -0
  62. data/lib/aws-sdk-core/plugins/protocols/rpc_v2.rb +17 -0
  63. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +162 -37
  64. data/lib/aws-sdk-core/plugins/request_compression.rb +226 -0
  65. data/lib/aws-sdk-core/plugins/retry_errors.rb +12 -3
  66. data/lib/aws-sdk-core/plugins/sign.rb +55 -33
  67. data/lib/aws-sdk-core/plugins/signature_v2.rb +2 -1
  68. data/lib/aws-sdk-core/plugins/signature_v4.rb +2 -1
  69. data/lib/aws-sdk-core/plugins/stub_responses.rb +59 -9
  70. data/lib/aws-sdk-core/plugins/telemetry.rb +75 -0
  71. data/lib/aws-sdk-core/plugins/transfer_encoding.rb +16 -9
  72. data/lib/aws-sdk-core/plugins/user_agent.rb +192 -14
  73. data/lib/aws-sdk-core/plugins.rb +39 -0
  74. data/lib/aws-sdk-core/process_credentials.rb +48 -29
  75. data/lib/aws-sdk-core/query/ec2_handler.rb +27 -0
  76. data/lib/aws-sdk-core/query/ec2_param_builder.rb +5 -7
  77. data/lib/aws-sdk-core/query/handler.rb +4 -4
  78. data/lib/aws-sdk-core/query/param_builder.rb +2 -2
  79. data/lib/aws-sdk-core/query.rb +2 -1
  80. data/lib/aws-sdk-core/refreshing_credentials.rb +20 -23
  81. data/lib/aws-sdk-core/resources.rb +8 -0
  82. data/lib/aws-sdk-core/rest/content_type_handler.rb +60 -0
  83. data/lib/aws-sdk-core/rest/handler.rb +3 -4
  84. data/lib/aws-sdk-core/rest/request/body.rb +32 -5
  85. data/lib/aws-sdk-core/rest/request/endpoint.rb +24 -4
  86. data/lib/aws-sdk-core/rest/request/headers.rb +15 -7
  87. data/lib/aws-sdk-core/rest/request/querystring_builder.rb +62 -36
  88. data/lib/aws-sdk-core/rest/response/body.rb +15 -1
  89. data/lib/aws-sdk-core/rest/response/header_list_parser.rb +79 -0
  90. data/lib/aws-sdk-core/rest/response/headers.rb +8 -3
  91. data/lib/aws-sdk-core/rest.rb +1 -0
  92. data/lib/aws-sdk-core/rpc_v2/builder.rb +62 -0
  93. data/lib/aws-sdk-core/rpc_v2/cbor_engine.rb +18 -0
  94. data/lib/aws-sdk-core/rpc_v2/content_type_handler.rb +47 -0
  95. data/lib/aws-sdk-core/rpc_v2/error_handler.rb +95 -0
  96. data/lib/aws-sdk-core/rpc_v2/handler.rb +79 -0
  97. data/lib/aws-sdk-core/rpc_v2/parser.rb +98 -0
  98. data/lib/aws-sdk-core/rpc_v2.rb +69 -0
  99. data/lib/aws-sdk-core/shared_config.rb +135 -39
  100. data/lib/aws-sdk-core/shared_credentials.rb +1 -7
  101. data/lib/aws-sdk-core/sso_credentials.rb +6 -3
  102. data/lib/aws-sdk-core/static_token_provider.rb +1 -2
  103. data/lib/aws-sdk-core/stubbing/protocols/ec2.rb +12 -11
  104. data/lib/aws-sdk-core/stubbing/protocols/json.rb +11 -10
  105. data/lib/aws-sdk-core/stubbing/protocols/query.rb +7 -6
  106. data/lib/aws-sdk-core/stubbing/protocols/rest.rb +2 -1
  107. data/lib/aws-sdk-core/stubbing/protocols/rest_json.rb +9 -8
  108. data/lib/aws-sdk-core/stubbing/protocols/rest_xml.rb +6 -5
  109. data/lib/aws-sdk-core/stubbing/protocols/rpc_v2.rb +39 -0
  110. data/lib/aws-sdk-core/stubbing/stub_data.rb +11 -0
  111. data/lib/aws-sdk-core/stubbing.rb +22 -0
  112. data/lib/aws-sdk-core/telemetry/base.rb +177 -0
  113. data/lib/aws-sdk-core/telemetry/no_op.rb +70 -0
  114. data/lib/aws-sdk-core/telemetry/otel.rb +235 -0
  115. data/lib/aws-sdk-core/telemetry/span_kind.rb +22 -0
  116. data/lib/aws-sdk-core/telemetry/span_status.rb +59 -0
  117. data/lib/aws-sdk-core/telemetry.rb +78 -0
  118. data/lib/aws-sdk-core/token.rb +3 -3
  119. data/lib/aws-sdk-core/token_provider.rb +4 -0
  120. data/lib/aws-sdk-core/token_provider_chain.rb +2 -6
  121. data/lib/aws-sdk-core/util.rb +41 -1
  122. data/lib/aws-sdk-core/waiters/poller.rb +12 -5
  123. data/lib/aws-sdk-core/xml/builder.rb +17 -9
  124. data/lib/aws-sdk-core/xml/error_handler.rb +35 -43
  125. data/lib/aws-sdk-core/xml/parser/frame.rb +4 -20
  126. data/lib/aws-sdk-core/xml/parser/stack.rb +2 -0
  127. data/lib/aws-sdk-core/xml/parser.rb +2 -6
  128. data/lib/aws-sdk-core.rb +82 -107
  129. data/lib/aws-sdk-sso/client.rb +205 -92
  130. data/lib/aws-sdk-sso/client_api.rb +7 -0
  131. data/lib/aws-sdk-sso/endpoint_parameters.rb +9 -6
  132. data/lib/aws-sdk-sso/endpoint_provider.rb +30 -28
  133. data/lib/aws-sdk-sso/endpoints.rb +3 -54
  134. data/lib/aws-sdk-sso/plugins/endpoints.rb +23 -22
  135. data/lib/aws-sdk-sso/types.rb +1 -0
  136. data/lib/aws-sdk-sso.rb +15 -11
  137. data/lib/aws-sdk-ssooidc/client.rb +625 -125
  138. data/lib/aws-sdk-ssooidc/client_api.rb +94 -1
  139. data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +9 -6
  140. data/lib/aws-sdk-ssooidc/endpoint_provider.rb +30 -28
  141. data/lib/aws-sdk-ssooidc/endpoints.rb +3 -40
  142. data/lib/aws-sdk-ssooidc/errors.rb +62 -0
  143. data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +23 -20
  144. data/lib/aws-sdk-ssooidc/types.rb +419 -53
  145. data/lib/aws-sdk-ssooidc.rb +15 -11
  146. data/lib/aws-sdk-sts/client.rb +526 -243
  147. data/lib/aws-sdk-sts/client_api.rb +48 -9
  148. data/lib/aws-sdk-sts/customizations.rb +5 -2
  149. data/lib/aws-sdk-sts/endpoint_parameters.rb +10 -9
  150. data/lib/aws-sdk-sts/endpoint_provider.rb +82 -84
  151. data/lib/aws-sdk-sts/endpoints.rb +3 -118
  152. data/lib/aws-sdk-sts/errors.rb +15 -0
  153. data/lib/aws-sdk-sts/plugins/endpoints.rb +23 -30
  154. data/lib/aws-sdk-sts/presigner.rb +3 -7
  155. data/lib/aws-sdk-sts/types.rb +217 -36
  156. data/lib/aws-sdk-sts.rb +15 -11
  157. data/lib/seahorse/client/async_base.rb +4 -5
  158. data/lib/seahorse/client/async_response.rb +19 -0
  159. data/lib/seahorse/client/base.rb +18 -21
  160. data/lib/seahorse/client/configuration.rb +0 -4
  161. data/lib/seahorse/client/h2/connection.rb +18 -28
  162. data/lib/seahorse/client/h2/handler.rb +14 -3
  163. data/lib/seahorse/client/handler.rb +1 -1
  164. data/lib/seahorse/client/http/response.rb +1 -1
  165. data/lib/seahorse/client/net_http/connection_pool.rb +15 -12
  166. data/lib/seahorse/client/net_http/handler.rb +21 -9
  167. data/lib/seahorse/client/net_http/patches.rb +1 -4
  168. data/lib/seahorse/client/networking_error.rb +1 -1
  169. data/lib/seahorse/client/plugin.rb +9 -0
  170. data/lib/seahorse/client/plugins/endpoint.rb +0 -1
  171. data/lib/seahorse/client/plugins/h2.rb +4 -4
  172. data/lib/seahorse/client/plugins/net_http.rb +57 -16
  173. data/lib/seahorse/client/plugins/request_callback.rb +31 -0
  174. data/lib/seahorse/client/request_context.rb +9 -2
  175. data/lib/seahorse/client/response.rb +8 -0
  176. data/lib/seahorse/model/operation.rb +3 -0
  177. data/lib/seahorse/model/shapes.rb +2 -2
  178. data/lib/seahorse/util.rb +2 -1
  179. data/sig/aws-sdk-core/async_client_stubs.rbs +21 -0
  180. data/sig/aws-sdk-core/client_stubs.rbs +10 -0
  181. data/sig/aws-sdk-core/errors.rbs +22 -0
  182. data/sig/aws-sdk-core/resources/collection.rbs +21 -0
  183. data/sig/aws-sdk-core/structure.rbs +4 -0
  184. data/sig/aws-sdk-core/telemetry/base.rbs +46 -0
  185. data/sig/aws-sdk-core/telemetry/otel.rbs +22 -0
  186. data/sig/aws-sdk-core/telemetry/span_kind.rbs +15 -0
  187. data/sig/aws-sdk-core/telemetry/span_status.rbs +24 -0
  188. data/sig/aws-sdk-core/waiters/errors.rbs +20 -0
  189. data/sig/aws-sdk-core.rbs +7 -0
  190. data/sig/seahorse/client/async_base.rbs +18 -0
  191. data/sig/seahorse/client/base.rbs +25 -0
  192. data/sig/seahorse/client/handler_builder.rbs +16 -0
  193. data/sig/seahorse/client/response.rbs +61 -0
  194. metadata +106 -23
  195. /data/lib/aws-sdk-core/xml/parser/{engines/libxml.rb → libxml_engine.rb} +0 -0
  196. /data/lib/aws-sdk-core/xml/parser/{engines/nokogiri.rb → nokogiri_engine.rb} +0 -0
  197. /data/lib/aws-sdk-core/xml/parser/{engines/oga.rb → oga_engine.rb} +0 -0
  198. /data/lib/aws-sdk-core/xml/parser/{engines/ox.rb → ox_engine.rb} +0 -0
  199. /data/lib/aws-sdk-core/xml/parser/{engines/rexml.rb → rexml_engine.rb} +0 -0
@@ -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,123 +146,237 @@ 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[: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}"
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)
127
192
  }
128
-
129
- calculate_request_checksum(context, request_checksum_property)
193
+ context[:http_checksum][:request_algorithm] = request_algorithm
194
+ calculate_request_checksum(context, request_algorithm)
130
195
  end
131
196
 
132
197
  if should_verify_response_checksum?(context)
133
198
  add_verify_response_checksum_handlers(context)
134
199
  end
135
200
 
136
- @handler.call(context)
201
+ with_metrics(context.config, algorithm) { @handler.call(context) }
137
202
  end
138
203
 
139
204
  private
140
205
 
206
+ def with_metrics(config, algorithm, &block)
207
+ metrics = []
208
+ add_request_config_metric(config, metrics)
209
+ add_response_config_metric(config, metrics)
210
+ add_request_checksum_metrics(algorithm, metrics)
211
+ Aws::Plugins::UserAgent.metric(*metrics, &block)
212
+ end
213
+
214
+ def add_request_config_metric(config, metrics)
215
+ case config.request_checksum_calculation
216
+ when 'when_supported'
217
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED'
218
+ when 'when_required'
219
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED'
220
+ end
221
+ end
222
+
223
+ def add_response_config_metric(config, metrics)
224
+ case config.response_checksum_validation
225
+ when 'when_supported'
226
+ metrics << 'FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED'
227
+ when 'when_required'
228
+ metrics << 'FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED'
229
+ end
230
+ end
231
+
232
+ def add_request_checksum_metrics(algorithm, metrics)
233
+ case algorithm
234
+ when 'CRC32'
235
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_CRC32'
236
+ when 'CRC32C'
237
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_CRC32C'
238
+ when 'CRC64NVME'
239
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_CRC64'
240
+ when 'SHA1'
241
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_SHA1'
242
+ when 'SHA256'
243
+ metrics << 'FLEXIBLE_CHECKSUMS_REQ_SHA256'
244
+ end
245
+ end
246
+
247
+ def request_algorithm_selection(context)
248
+ return unless context.operation.http_checksum
249
+
250
+ input_member = context.operation.http_checksum['requestAlgorithmMember']
251
+
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_provided_as_header?(headers)
275
+ headers.any? { |k, _| k.start_with?('x-amz-checksum-') }
276
+ end
277
+
278
+ # Determines whether a request checksum should be calculated.
279
+ # 1. **No existing checksum in header**: Skips if checksum header already present
280
+ # 2. **Operation support**: Considers model, client configuration and user input.
141
281
  def should_calculate_request_checksum?(context)
142
- context.operation.http_checksum &&
143
- ChecksumAlgorithm.request_algorithm_selection(context)
282
+ !checksum_provided_as_header?(context.http_request.headers) &&
283
+ checksum_applicable?(context)
144
284
  end
145
285
 
146
- def should_verify_response_checksum?(context)
147
- context[:http_checksum][:validation_list] && !context[:http_checksum][:validation_list].empty?
286
+ # Checks if checksum calculation should proceed based on operation requirements and client settings.
287
+ # Returns true when any of these conditions are met:
288
+ # 1. http checksum's requestChecksumRequired is true
289
+ # 2. Config for request_checksum_calculation is "when_supported"
290
+ # 3. Config for request_checksum_calculation is "when_required" AND user provided checksum algorithm
291
+ def checksum_applicable?(context)
292
+ http_checksum = context.operation.http_checksum
293
+ return false unless http_checksum
294
+
295
+ return true if http_checksum['requestChecksumRequired']
296
+
297
+ return false unless (algorithm_member = http_checksum['requestAlgorithmMember'])
298
+
299
+ case context.config.request_checksum_calculation
300
+ when 'when_supported'
301
+ true
302
+ when 'when_required'
303
+ !context.params[algorithm_member.to_sym].nil?
304
+ else
305
+ false
306
+ end
307
+ end
308
+
309
+ def choose_request_algorithm!(context)
310
+ algorithm = request_algorithm_selection(context).upcase
311
+ return algorithm if CLIENT_ALGORITHMS.include?(algorithm)
312
+
313
+ if CRT_ALGORITHMS.include?(algorithm)
314
+ raise ArgumentError,
315
+ 'CRC32C and CRC64NVME requires CRT support ' \
316
+ '- install the aws-crt gem'
317
+ end
318
+
319
+ raise ArgumentError,
320
+ "#{algorithm} is not a supported checksum algorithm."
321
+ end
322
+
323
+ def checksum_request_in(context)
324
+ if context.operation['unsignedPayload'] ||
325
+ context.operation['authtype'] == 'v4-unsigned-body'
326
+ 'trailer'
327
+ else
328
+ 'header'
329
+ end
148
330
  end
149
331
 
150
332
  def calculate_request_checksum(context, checksum_properties)
151
- case checksum_properties['in']
333
+ headers = context.http_request.headers
334
+ if (algorithm_header = checksum_properties[:request_algorithm_header])
335
+ headers[algorithm_header] = checksum_properties[:algorithm]
336
+ end
337
+ case checksum_properties[:in]
152
338
  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
339
+ apply_request_checksum(context, headers, checksum_properties)
159
340
  when 'trailer'
160
- apply_request_trailer_checksum(context, checksum_properties)
341
+ apply_request_trailer_checksum(context, headers, checksum_properties)
342
+ else
343
+ # nothing
344
+ end
345
+ end
346
+
347
+ def apply_request_checksum(context, headers, checksum_properties)
348
+ header_name = checksum_properties[:name]
349
+ body = context.http_request.body_contents
350
+ headers[header_name] = calculate_checksum(
351
+ checksum_properties[:algorithm],
352
+ body
353
+ )
354
+ end
355
+
356
+ def calculate_checksum(algorithm, body)
357
+ digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
358
+ if body.respond_to?(:read)
359
+ update_in_chunks(digest, body)
360
+ else
361
+ digest.update(body)
362
+ end
363
+ digest.base64digest
364
+ end
365
+
366
+ def update_in_chunks(digest, io)
367
+ loop do
368
+ chunk = io.read(CHUNK_SIZE)
369
+ break unless chunk
370
+
371
+ digest.update(chunk)
161
372
  end
373
+ io.rewind
162
374
  end
163
375
 
164
- def apply_request_trailer_checksum(context, checksum_properties)
165
- location_name = checksum_properties['name']
376
+ def apply_request_trailer_checksum(context, headers, checksum_properties)
377
+ location_name = checksum_properties[:name]
166
378
 
167
379
  # set required headers
168
- headers = context.http_request.headers
169
380
  headers['Content-Encoding'] = 'aws-chunked'
170
381
  headers['X-Amz-Content-Sha256'] = 'STREAMING-UNSIGNED-PAYLOAD-TRAILER'
171
382
  headers['X-Amz-Trailer'] = location_name
@@ -174,120 +385,88 @@ module Aws
174
385
  # to set the Content-Length header (set by content_length plugin).
175
386
  # This means we cannot use Transfer-Encoding=chunked
176
387
 
177
- if !context.http_request.body.respond_to?(:size)
388
+ unless context.http_request.body.respond_to?(:size)
178
389
  raise Aws::Errors::ChecksumError, 'Could not determine length of the body'
179
390
  end
180
391
  headers['X-Amz-Decoded-Content-Length'] = context.http_request.body.size
181
392
 
182
393
  context.http_request.body = AwsChunkedTrailerDigestIO.new(
183
394
  context.http_request.body,
184
- checksum_properties['algorithm'],
395
+ checksum_properties[:algorithm],
185
396
  location_name
186
397
  )
187
398
  end
188
399
 
400
+ def should_verify_response_checksum?(context)
401
+ request_validation_mode(context) == 'ENABLED'
402
+ end
403
+
189
404
  # Add events to the http_response to verify the checksum as its read
190
405
  # This prevents the body from being read multiple times
191
406
  # verification is done only once a successful response has completed
192
407
  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
408
+ checksum_context = {}
409
+ add_verify_response_headers_handler(context, checksum_context)
410
+ add_verify_response_data_handler(context, checksum_context)
411
+ add_verify_response_success_handler(context, checksum_context)
412
+ end
208
413
 
209
- http_response.on_data do |chunk|
210
- checksum_context[:digest].update(chunk) if checksum_context[:digest]
414
+ def add_verify_response_headers_handler(context, checksum_context)
415
+ validation_list = CHECKSUM_ALGORITHM_PRIORITIES &
416
+ operation_response_algorithms(context)
417
+ context[:http_checksum][:validation_list] = validation_list
418
+
419
+ context.http_response.on_headers do |_status, headers|
420
+ header_name, algorithm = response_header_to_verify(
421
+ headers,
422
+ validation_list
423
+ )
424
+ next unless header_name
425
+
426
+ expected = headers[header_name]
427
+ next if context[:http_checksum][:skip_on_suffix] && /-\d+$/.match(expected)
428
+
429
+ checksum_context[:algorithm] = algorithm
430
+ checksum_context[:header_name] = header_name
431
+ checksum_context[:digest] = ChecksumAlgorithm.digest_for_algorithm(algorithm)
432
+ checksum_context[:expected] = expected
211
433
  end
434
+ end
212
435
 
213
- http_response.on_success do
214
- if checksum_context[:digest] &&
215
- (computed = checksum_context[:digest].base64digest)
436
+ def add_verify_response_data_handler(context, checksum_context)
437
+ context.http_response.on_data do |chunk|
438
+ checksum_context[:digest]&.update(chunk)
439
+ end
440
+ end
216
441
 
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
442
+ def add_verify_response_success_handler(context, checksum_context)
443
+ context.http_response.on_success do
444
+ next unless checksum_context[:digest]
222
445
 
446
+ computed = checksum_context[:digest].base64digest
447
+ if computed == checksum_context[:expected]
223
448
  context[:http_checksum][:validated] = checksum_context[:algorithm]
449
+ else
450
+ raise Aws::Errors::ChecksumError,
451
+ "Checksum validation failed on #{checksum_context[:header_name]} "\
452
+ "computed: #{computed}, expected: #{checksum_context[:expected]}"
224
453
  end
225
454
  end
226
455
  end
227
456
 
228
- # returns nil if no headers to verify
229
457
  def response_header_to_verify(headers, validation_list)
230
458
  validation_list.each do |algorithm|
231
- header_name = "x-amz-checksum-#{algorithm}"
459
+ header_name = "x-amz-checksum-#{algorithm.downcase}"
232
460
  return [header_name, algorithm] if headers[header_name]
233
461
  end
234
462
  nil
235
463
  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
464
  end
286
465
 
287
466
  # Wrapper for request body that implements application-layer
288
467
  # chunking with Digest computed on chunks + added as a trailer
289
468
  class AwsChunkedTrailerDigestIO
290
- CHUNK_SIZE = 16384
469
+ CHUNK_SIZE = 16_384
291
470
 
292
471
  def initialize(io, algorithm, location_name)
293
472
  @io = io
@@ -314,7 +493,7 @@ module Aws
314
493
  @io.rewind
315
494
  end
316
495
 
317
- def read(length, buf)
496
+ def read(length, buf = nil)
318
497
  # account for possible leftover bytes at the end, if we have trailer bytes, send them
319
498
  if @trailer_io
320
499
  return @trailer_io.read(length, buf)
@@ -328,7 +507,7 @@ module Aws
328
507
  else
329
508
  trailers = {}
330
509
  trailers[@location_name] = @digest.base64digest
331
- trailers = trailers.map { |k,v| "#{k}:#{v}"}.join("\r\n")
510
+ trailers = trailers.map { |k,v| "#{k}:#{v}" }.join("\r\n")
332
511
  @trailer_io = StringIO.new("0\r\n#{trailers}\r\n\r\n")
333
512
  chunk = @trailer_io.read(length, buf)
334
513
  end
@@ -40,6 +40,7 @@ side monitoring agent is running on, where client metrics will be published via
40
40
  option(:client_side_monitoring_publisher,
41
41
  default: ClientSideMonitoring::Publisher,
42
42
  doc_type: Aws::ClientSideMonitoring::Publisher,
43
+ rbs_type: 'untyped',
43
44
  docstring: <<-DOCS) do |cfg|
44
45
  Allows you to provide a custom client-side monitoring publisher class. By default,
45
46
  will use the Client Side Monitoring Agent Publisher.
@@ -179,7 +180,6 @@ all generated client side metrics. Defaults to an empty string.
179
180
  complete_opts = {
180
181
  latency: end_time - start_time,
181
182
  attempt_count: context.retries + 1,
182
- user_agent: context.http_request.headers["user-agent"],
183
183
  final_error_retryable: final_error_retryable,
184
184
  final_http_status_code: context.http_response.status_code,
185
185
  final_aws_exception: final_aws_exception,