aws-sdk-core 3.192.1 → 3.197.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +61 -0
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-core/binary/decode_handler.rb +0 -5
  5. data/lib/aws-sdk-core/binary/event_builder.rb +34 -37
  6. data/lib/aws-sdk-core/event_emitter.rb +0 -16
  7. data/lib/aws-sdk-core/lru_cache.rb +75 -0
  8. data/lib/aws-sdk-core/pageable_response.rb +1 -1
  9. data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +14 -2
  10. data/lib/aws-sdk-core/plugins/invocation_id.rb +1 -11
  11. data/lib/aws-sdk-core/plugins/request_compression.rb +10 -1
  12. data/lib/aws-sdk-core/plugins/retry_errors.rb +10 -2
  13. data/lib/aws-sdk-core/plugins/sign.rb +8 -3
  14. data/lib/aws-sdk-core/plugins/user_agent.rb +61 -26
  15. data/lib/aws-sdk-core/query/ec2_param_builder.rb +5 -7
  16. data/lib/aws-sdk-core/rest/request/content_type.rb +13 -4
  17. data/lib/aws-sdk-core/util.rb +4 -4
  18. data/lib/aws-sdk-core/waiters/poller.rb +1 -1
  19. data/lib/aws-sdk-core.rb +1 -0
  20. data/lib/aws-sdk-sso/client.rb +73 -48
  21. data/lib/aws-sdk-sso.rb +1 -1
  22. data/lib/aws-sdk-ssooidc/client.rb +123 -50
  23. data/lib/aws-sdk-ssooidc/client_api.rb +22 -0
  24. data/lib/aws-sdk-ssooidc/errors.rb +21 -0
  25. data/lib/aws-sdk-ssooidc/types.rb +77 -9
  26. data/lib/aws-sdk-ssooidc.rb +1 -1
  27. data/lib/aws-sdk-sts/client.rb +73 -48
  28. data/lib/aws-sdk-sts.rb +1 -1
  29. data/lib/seahorse/client/async_base.rb +1 -1
  30. data/lib/seahorse/client/async_response.rb +19 -0
  31. data/lib/seahorse/client/base.rb +1 -0
  32. data/lib/seahorse/client/h2/handler.rb +1 -0
  33. data/lib/seahorse/client/net_http/connection_pool.rb +3 -9
  34. data/lib/seahorse/client/plugins/net_http.rb +48 -16
  35. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2395902c0987473cd133d100c6a95ed688e6a08c60f5b1111a2da1dc0b4c8a6d
4
- data.tar.gz: 30a8dde25eff270571c9516ba6b94fa36220862fbd9f2849bd0cd89ec9a386db
3
+ metadata.gz: 2126c3d8e997ce7f62c9c4d66f5eeef1b3ca33dbe07963cee7ab64af41e3bea3
4
+ data.tar.gz: c8e520892d84cfe2afb40aae3c2064c2f9aed5c291b4346d3a45a2f61df6175d
5
5
  SHA512:
6
- metadata.gz: 784eb0e07984d63bde357870ce1347a9abe540ecd4c9888d36a71832a66ac24ca6f422084866dc9471b0296e5b96e30d8a552ac61da4b72329af9227f8096ffd
7
- data.tar.gz: 7aebcc71d316b70de8980e853a623be34c71ea7efd57c6c2bbf1234350b1ddfe7a99a27bb05d32884cd33d63b7eb54698e837836e63e7dd4f4fdd94bc4d46d1b
6
+ metadata.gz: 33e18c7d668078ac612c1c77324c86fc4a102e6d4f752211ca1b6ca9cec91ae098e1261c3ae1ec03dfe2c57d16925608feef5f89cb76a32203d04cb9d790b135
7
+ data.tar.gz: 459028118688f266b87f788388ffbb5a7cc6e32931b8bc6ffdbad86dfc00818adc7d394ffee4aa672cb5a4003bfdf2046bfbda5e729582a7022c2d0c835df634
data/CHANGELOG.md CHANGED
@@ -1,6 +1,67 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 3.197.0 (2024-06-05)
5
+ ------------------
6
+
7
+ * Issue - Ensure no UTC offset when deserializing `iso8601` timestamp format values.
8
+
9
+ * Feature - Bump User Agent to version 2.1 to track business metrics. This changes the User Agent plugin order to be just before sending.
10
+
11
+ 3.196.1 (2024-05-14)
12
+ ------------------
13
+
14
+ * Issue - Fix `ConnectionPool` for `.empty!` and `.clear!` since it prevented adding a new key from being added to the pool (#3020).
15
+
16
+ 3.196.0 (2024-05-13)
17
+ ------------------
18
+
19
+ * Feature - Updated Aws::STS::Client with the latest API changes.
20
+
21
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
22
+
23
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
24
+
25
+ 3.195.0 (2024-05-10)
26
+ ------------------
27
+
28
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
29
+
30
+ * Feature - Updated request parameters for PKCE support.
31
+
32
+ 3.194.2 (2024-05-07)
33
+ ------------------
34
+
35
+ * Issue - Fix issue where `ConnectionPool` size iteration would prevent a new key from being added to the pool.
36
+
37
+ 3.194.1 (2024-05-03)
38
+ ------------------
39
+
40
+ * Issue - Update EC2 protocol to not serialize empty lists.
41
+
42
+ 3.194.0 (2024-04-30)
43
+ ------------------
44
+
45
+ * Feature - Add an API private cache for S3 Express and Access Grants.
46
+
47
+ 3.193.0 (2024-04-25)
48
+ ------------------
49
+
50
+ * Feature - Updated Aws::STS::Client with the latest API changes.
51
+
52
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
53
+
54
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
55
+
56
+ * Issue - Update event stream documentation.
57
+ * Issue - Move `InvocationId` plugin to all clients.
58
+ * Issue - Handle event streaming content-sha256 header in the signer plugin.
59
+ * Issue - Add the event stream content type to initial requests.
60
+ * Issue - Fix `standard` and `adaptive` retry mode for event streams.
61
+ * Issue - Add `authority` to http2 headers.
62
+ * Issue - Do not treat single members in event stream structures as implicit payloads.
63
+ * Issue - Do not wait for initial response headers to start sending input events.
64
+
4
65
  3.192.1 (2024-04-18)
5
66
  ------------------
6
67
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.192.1
1
+ 3.197.0
@@ -33,11 +33,6 @@ module Aws
33
33
  context.operation.errors,
34
34
  context.http_response.body,
35
35
  output_handler)
36
- if input_emitter = context[:input_event_emitter]
37
- # #emit will be blocked until 200 success
38
- # see Aws::EventEmitter#emit
39
- input_emitter.signal_queue << "ready"
40
- end
41
36
  end
42
37
 
43
38
  context.http_response.on_success(200) do
@@ -42,41 +42,39 @@ module Aws
42
42
  end
43
43
  end
44
44
 
45
- # implict payload
46
- if !explicit_payload && !implicit_payload_members.empty?
47
- if implicit_payload_members.size > 1
48
- payload_shape = Shapes::StructureShape.new
49
- implicit_payload_members.each do |m_name, m_ref|
50
- payload_shape.add_member(m_name, m_ref)
51
- end
52
- payload_ref = Shapes::ShapeRef.new(shape: payload_shape)
53
-
54
- payload = build_payload_members(payload_ref, params)
55
- else
56
- m_name, m_ref = implicit_payload_members.first
57
- streaming, content_type = _content_type(m_ref.shape)
58
-
59
- es_headers[":content-type"] = Aws::EventStream::HeaderValue.new(
60
- type: "string", value: content_type)
61
- payload = _build_payload(streaming, m_ref, params[m_name])
62
- end
63
- end
64
-
65
-
45
+ # handle header members for all cases
66
46
  event_ref.shape.members.each do |member_name, member_ref|
67
47
  if member_ref.eventheader && params[member_name]
68
48
  header_value = params[member_name]
69
49
  es_headers[member_ref.shape.name] = Aws::EventStream::HeaderValue.new(
70
- type: _header_value_type(member_ref.shape, header_value),
50
+ type: header_value_type(member_ref.shape, header_value),
71
51
  value: header_value
72
52
  )
73
- elsif member_ref.eventpayload && params[member_name]
74
- # explicit payload
75
- streaming, content_type = _content_type(member_ref.shape)
53
+ end
54
+ end
55
+
56
+ # implict payload
57
+ if !explicit_payload && !implicit_payload_members.empty?
58
+ payload_shape = StructureShape.new
59
+ implicit_payload_members.each do |m_name, m_ref|
60
+ payload_shape.add_member(m_name, m_ref)
61
+ end
62
+ payload_ref = ShapeRef.new(shape: payload_shape)
76
63
 
77
- es_headers[":content-type"] = Aws::EventStream::HeaderValue.new(
78
- type: "string", value: content_type)
79
- payload = _build_payload(streaming, member_ref, params[member_name])
64
+ payload = build_payload_members(payload_ref, params)
65
+ .force_encoding(Encoding::BINARY)
66
+
67
+
68
+ es_headers[":content-type"] = Aws::EventStream::HeaderValue.new(
69
+ type: "string", value: content_type(payload_ref.shape))
70
+ else
71
+ # explicit payload, serialize just the payload member
72
+ event_ref.shape.members.each do |member_name, member_ref|
73
+ if member_ref.eventpayload && params[member_name]
74
+ es_headers[":content-type"] = Aws::EventStream::HeaderValue.new(
75
+ type: "string", value: content_type(member_ref.shape))
76
+ payload = params[member_name]
77
+ end
80
78
  end
81
79
  end
82
80
 
@@ -86,15 +84,15 @@ module Aws
86
84
  )
87
85
  end
88
86
 
89
- def _content_type(shape)
87
+ def content_type(shape)
90
88
  case shape
91
- when BlobShape then [true, "application/octet-stream"]
92
- when StringShape then [true, "text/plain"]
89
+ when BlobShape then "application/octet-stream"
90
+ when StringShape then "text/plain"
93
91
  when StructureShape then
94
92
  if @serializer_class.name.include?('Xml')
95
- [false, "text/xml"]
93
+ "text/xml"
96
94
  elsif @serializer_class.name.include?('Json')
97
- [false, "application/json"]
95
+ "application/json"
98
96
  end
99
97
  else
100
98
  raise Aws::Errors::EventStreamBuilderError.new(
@@ -102,7 +100,7 @@ module Aws
102
100
  end
103
101
  end
104
102
 
105
- def _header_value_type(shape, value)
103
+ def header_value_type(shape, value)
106
104
  case shape
107
105
  when StringShape then "string"
108
106
  when IntegerShape then "integer"
@@ -115,10 +113,9 @@ module Aws
115
113
  end
116
114
  end
117
115
 
118
- def _build_payload(streaming, ref, value)
119
- streaming ? value : @serializer_class.new(ref).serialize(value)
116
+ def build_payload_members(payload_ref, params)
117
+ @serializer_class.new(payload_ref).serialize(params)
120
118
  end
121
-
122
119
  end
123
120
  end
124
121
  end
@@ -6,7 +6,6 @@ module Aws
6
6
  def initialize
7
7
  @listeners = {}
8
8
  @validate_event = true
9
- @status = :sleep
10
9
  @signal_queue = Queue.new
11
10
  end
12
11
 
@@ -40,25 +39,10 @@ module Aws
40
39
  Aws::ParamValidator.validate!(
41
40
  @encoder.rules.shape.member(type), params)
42
41
  end
43
- _ready_for_events?
44
42
  @stream.data(
45
43
  @encoder.encode(type, params),
46
44
  end_stream: type == :end_stream
47
45
  )
48
46
  end
49
-
50
- private
51
-
52
- def _ready_for_events?
53
- return true if @status == :ready
54
-
55
- # blocked until once initial 200 response is received
56
- # signal will be available in @signal_queue
57
- # and this check will no longer be blocked
58
- @signal_queue.pop
59
- @status = :ready
60
- true
61
- end
62
-
63
47
  end
64
48
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ # @api private
5
+ # A simple thread safe LRU cache
6
+ class LRUCache
7
+ # @param [Hash] options
8
+ # @option options [Integer] :max_entries (100) Maximum number of entries
9
+ # @option options [Integer] :expiration (nil) Expiration time in seconds
10
+ def initialize(options = {})
11
+ @max_entries = options[:max_entries] || 100
12
+ @expiration = options[:expiration]
13
+ @entries = {}
14
+ @mutex = Mutex.new
15
+ end
16
+
17
+ # @param [String] key
18
+ # @return [Object]
19
+ def [](key)
20
+ @mutex.synchronize do
21
+ value = @entries[key]
22
+ if value
23
+ @entries.delete(key)
24
+ @entries[key] = value unless value.expired?
25
+ end
26
+ @entries[key]&.value
27
+ end
28
+ end
29
+
30
+ # @param [String] key
31
+ # @param [Object] value
32
+ def []=(key, value)
33
+ @mutex.synchronize do
34
+ @entries.shift unless @entries.size < @max_entries
35
+ # delete old value if exists
36
+ @entries.delete(key)
37
+ @entries[key] = Entry.new(value: value, expiration: @expiration)
38
+ @entries[key].value
39
+ end
40
+ end
41
+
42
+ # @param [String] key
43
+ # @return [Boolean]
44
+ def key?(key)
45
+ @mutex.synchronize do
46
+ @entries.delete(key) if @entries.key?(key) && @entries[key].expired?
47
+ @entries.key?(key)
48
+ end
49
+ end
50
+
51
+ def clear
52
+ @mutex.synchronize do
53
+ @entries.clear
54
+ end
55
+ end
56
+
57
+ # @api private
58
+ class Entry
59
+ def initialize(options = {})
60
+ @value = options[:value]
61
+ @expiration = options[:expiration]
62
+ @created_time = Time.now
63
+ end
64
+
65
+ # @return [Object]
66
+ attr_reader :value
67
+
68
+ def expired?
69
+ return false unless @expiration
70
+
71
+ Time.now - @created_time > @expiration
72
+ end
73
+ end
74
+ end
75
+ end
@@ -201,7 +201,7 @@ module Aws
201
201
  def next_response(params)
202
202
  params = next_page_params(params)
203
203
  request = context.client.build_request(context.operation_name, params)
204
- Aws::Plugins::UserAgent.feature('paginator') do
204
+ Aws::Plugins::UserAgent.metric('PAGINATOR') do
205
205
  request.send_request
206
206
  end
207
207
  end
@@ -11,6 +11,8 @@ module Aws
11
11
  # AttemptHandler comes just before we would retry an error.
12
12
  # Or before we would follow redirects.
13
13
  handlers.add(AttemptHandler, step: :sign, priority: 39)
14
+ # ErrorHandler comes after we have parsed an error.
15
+ handlers.add(ErrorHandler, step: :sign, priority: 95)
14
16
  # LatencyHandler is as close to sending as possible.
15
17
  handlers.add(LatencyHandler, step: :sign, priority: 0)
16
18
  end
@@ -62,17 +64,27 @@ module Aws
62
64
  call_attempt.x_amzn_request_id = headers["x-amzn-request-id"]
63
65
  end
64
66
  call_attempt.http_status_code = context.http_response.status_code
65
- if e = resp.error
67
+ context.metadata[:current_call_attempt] = call_attempt
68
+ request_metrics.add_call_attempt(call_attempt)
69
+ resp
70
+ end
71
+ end
72
+
73
+ class ErrorHandler < Seahorse::Client::Handler
74
+ def call(context)
75
+ resp = @handler.call(context)
76
+ call_attempt = context.metadata[:current_call_attempt]
77
+ if (e = resp.error)
66
78
  e_name = _extract_error_name(e)
67
79
  e_msg = e.message
68
80
  call_attempt.aws_exception = "#{e_name}"
69
81
  call_attempt.aws_exception_msg = "#{e_msg}"
70
82
  end
71
- request_metrics.add_call_attempt(call_attempt)
72
83
  resp
73
84
  end
74
85
 
75
86
  private
87
+
76
88
  def _extract_error_name(error)
77
89
  if error.is_a?(Aws::Errors::ServiceError)
78
90
  error.class.code
@@ -12,18 +12,8 @@ module Aws
12
12
  class Handler < Seahorse::Client::Handler
13
13
 
14
14
  def call(context)
15
- apply_invocation_id(context)
16
- @handler.call(context)
17
- end
18
-
19
- private
20
-
21
- def apply_invocation_id(context)
22
15
  context.http_request.headers['amz-sdk-invocation-id'] = SecureRandom.uuid
23
- if context[:input_event_emitter]
24
- # only used for eventstreaming at input
25
- context.http_request.headers['x-amz-content-sha256'] = 'STREAMING-AWS4-HMAC-SHA256-EVENTS'
26
- end
16
+ @handler.call(context)
27
17
  end
28
18
 
29
19
  end
@@ -91,11 +91,20 @@ and 10485780 bytes inclusive.
91
91
  end
92
92
  end
93
93
  end
94
- @handler.call(context)
94
+ with_metric(selected_encoding) { @handler.call(context) }
95
95
  end
96
96
 
97
97
  private
98
98
 
99
+ def with_metric(encoding, &block)
100
+ case encoding
101
+ when 'gzip'
102
+ Aws::Plugins::UserAgent.metric('GZIP_REQUEST_COMPRESSION', &block)
103
+ else
104
+ block.call
105
+ end
106
+ end
107
+
99
108
  def request_encoding_selection(context)
100
109
  encoding_list = context.operation.request_compression['encodings']
101
110
  encoding_list.find { |encoding| RequestCompression::SUPPORTED_ENCODINGS.include?(encoding) }
@@ -235,7 +235,7 @@ a clock skew correction and retry requests with skewed client clocks.
235
235
 
236
236
  get_send_token(config)
237
237
  add_retry_headers(context)
238
- response = @handler.call(context)
238
+ response = with_metric(config.retry_mode) { @handler.call(context) }
239
239
  error_inspector = Retries::ErrorInspector.new(
240
240
  response.error, response.context.http_response.status_code
241
241
  )
@@ -272,6 +272,10 @@ a clock skew correction and retry requests with skewed client clocks.
272
272
 
273
273
  private
274
274
 
275
+ def with_metric(retry_mode, &block)
276
+ Aws::Plugins::UserAgent.metric("RETRY_MODE_#{retry_mode.upcase}", &block)
277
+ end
278
+
275
279
  def get_send_token(config)
276
280
  # either fail fast or block until a token becomes available
277
281
  # must be configurable
@@ -359,7 +363,7 @@ a clock skew correction and retry requests with skewed client clocks.
359
363
  class LegacyHandler < Seahorse::Client::Handler
360
364
 
361
365
  def call(context)
362
- response = @handler.call(context)
366
+ response = with_metric { @handler.call(context) }
363
367
  if response.error
364
368
  error_inspector = Retries::ErrorInspector.new(
365
369
  response.error, response.context.http_response.status_code
@@ -378,6 +382,10 @@ a clock skew correction and retry requests with skewed client clocks.
378
382
 
379
383
  private
380
384
 
385
+ def with_metric(&block)
386
+ Aws::Plugins::UserAgent.metric('RETRY_MODE_LEGACY', &block)
387
+ end
388
+
381
389
  def retry_if_possible(response, error_inspector)
382
390
  context = response.context
383
391
  if should_retry?(context, error_inspector)
@@ -159,9 +159,14 @@ module Aws
159
159
  private
160
160
 
161
161
  def apply_authtype(context, req)
162
- if context.operation['authtype'].eql?('v4-unsigned-body') &&
163
- req.endpoint.scheme.eql?('https')
164
- req.headers['X-Amz-Content-Sha256'] ||= 'UNSIGNED-PAYLOAD'
162
+ # only used for eventstreaming at input
163
+ if context[:input_event_emitter]
164
+ req.headers['X-Amz-Content-Sha256'] = 'STREAMING-AWS4-HMAC-SHA256-EVENTS'
165
+ else
166
+ if context.operation['authtype'].eql?('v4-unsigned-body') &&
167
+ req.endpoint.scheme.eql?('https')
168
+ req.headers['X-Amz-Content-Sha256'] ||= 'UNSIGNED-PAYLOAD'
169
+ end
165
170
  end
166
171
  end
167
172
 
@@ -4,6 +4,23 @@ module Aws
4
4
  module Plugins
5
5
  # @api private
6
6
  class UserAgent < Seahorse::Client::Plugin
7
+ METRICS = Aws::Json.load(<<-METRICS)
8
+ {
9
+ "RESOURCE_MODEL": "A",
10
+ "WAITER": "B",
11
+ "PAGINATOR": "C",
12
+ "RETRY_MODE_LEGACY": "D",
13
+ "RETRY_MODE_STANDARD": "E",
14
+ "RETRY_MODE_ADAPTIVE": "F",
15
+ "S3_TRANSFER": "G",
16
+ "S3_CRYPTO_V1N": "H",
17
+ "S3_CRYPTO_V2": "I",
18
+ "S3_EXPRESS_BUCKET": "J",
19
+ "S3_ACCESS_GRANTS": "K",
20
+ "GZIP_REQUEST_COMPRESSION": "L"
21
+ }
22
+ METRICS
23
+
7
24
  # @api private
8
25
  option(:user_agent_suffix)
9
26
  # @api private
@@ -14,20 +31,29 @@ module Aws
14
31
  doc_type: 'String',
15
32
  docstring: <<-DOCS) do |cfg|
16
33
  A unique and opaque application ID that is appended to the
17
- User-Agent header as app/<sdk_ua_app_id>. It should have a
18
- maximum length of 50.
34
+ User-Agent header as app/sdk_ua_app_id. It should have a
35
+ maximum length of 50. This variable is sourced from environment
36
+ variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
19
37
  DOCS
20
38
  app_id = ENV['AWS_SDK_UA_APP_ID']
21
39
  app_id ||= Aws.shared_config.sdk_ua_app_id(profile: cfg.profile)
22
40
  app_id
23
41
  end
24
42
 
25
- def self.feature(feature, &block)
26
- Thread.current[:aws_sdk_core_user_agent_feature] ||= []
27
- Thread.current[:aws_sdk_core_user_agent_feature] << "ft/#{feature}"
43
+ # Deprecated - must exist for old service gems
44
+ def self.feature(_feature, &block)
45
+ block.call
46
+ end
47
+
48
+ def self.metric(metric, &block)
49
+ Thread.current[:aws_sdk_core_user_agent_metric] ||= []
50
+ Thread.current[:aws_sdk_core_user_agent_metric] << METRICS[metric]
28
51
  block.call
29
52
  ensure
30
- Thread.current[:aws_sdk_core_user_agent_feature].pop
53
+ Thread.current[:aws_sdk_core_user_agent_metric].pop
54
+ if Thread.current[:aws_sdk_core_user_agent_metric].empty?
55
+ Thread.current[:aws_sdk_core_user_agent_metric] = nil
56
+ end
31
57
  end
32
58
 
33
59
  # @api private
@@ -48,15 +74,24 @@ maximum length of 50.
48
74
 
49
75
  def to_s
50
76
  ua = "aws-sdk-ruby3/#{CORE_GEM_VERSION}"
51
- ua += ' ua/2.0'
52
- ua += " #{api_metadata}" if api_metadata
77
+ ua += ' ua/2.1'
78
+ if (api_m = api_metadata)
79
+ ua += " #{api_m}"
80
+ end
53
81
  ua += " #{os_metadata}"
54
82
  ua += " #{language_metadata}"
55
- ua += " #{env_metadata}" if env_metadata
56
- ua += " #{config_metadata}" if config_metadata
57
- ua += " #{app_id}" if app_id
58
- ua += " #{feature_metadata}" if feature_metadata
59
- ua += " #{framework_metadata}" if framework_metadata
83
+ if (env_m = env_metadata)
84
+ ua += " #{env_m}"
85
+ end
86
+ if (app_id_m = app_id_metadata)
87
+ ua += " #{app_id_m}"
88
+ end
89
+ if (framework_m = framework_metadata)
90
+ ua += " #{framework_m}"
91
+ end
92
+ if (metric_m = metric_metadata)
93
+ ua += " #{metric_m}"
94
+ end
60
95
  if @context.config.user_agent_suffix
61
96
  ua += " #{@context.config.user_agent_suffix}"
62
97
  end
@@ -92,7 +127,6 @@ maximum length of 50.
92
127
  local_version = Gem::Platform.local.version
93
128
  metadata += "##{local_version}" if local_version
94
129
  metadata += " md/#{RbConfig::CONFIG['host_cpu']}"
95
- metadata
96
130
  end
97
131
 
98
132
  # Used to be RUBY_ENGINE/RUBY_VERSION
@@ -106,11 +140,7 @@ maximum length of 50.
106
140
  "exec-env/#{execution_env}"
107
141
  end
108
142
 
109
- def config_metadata
110
- "cfg/retry-mode##{@context.config.retry_mode}"
111
- end
112
-
113
- def app_id
143
+ def app_id_metadata
114
144
  return unless (app_id = @context.config.sdk_ua_app_id)
115
145
 
116
146
  # Sanitize and only allow these characters
@@ -118,12 +148,6 @@ maximum length of 50.
118
148
  "app/#{app_id}"
119
149
  end
120
150
 
121
- def feature_metadata
122
- return unless Thread.current[:aws_sdk_core_user_agent_feature]
123
-
124
- Thread.current[:aws_sdk_core_user_agent_feature].join(' ')
125
- end
126
-
127
151
  def framework_metadata
128
152
  if (frameworks_cfg = @context.config.user_agent_frameworks).empty?
129
153
  return
@@ -140,10 +164,21 @@ maximum length of 50.
140
164
  end
141
165
  frameworks.map { |n, v| "lib/#{n}##{v}" }.join(' ')
142
166
  end
167
+
168
+ def metric_metadata
169
+ return unless Thread.current[:aws_sdk_core_user_agent_metric]
170
+
171
+ metrics = Thread.current[:aws_sdk_core_user_agent_metric].join(',')
172
+ # Metric metadata is limited to 1024 bytes
173
+ return "m/#{metrics}" if metrics.bytesize <= 1024
174
+
175
+ # Removes the last unfinished metric
176
+ "m/#{metrics[0...metrics[0..1024].rindex(',')]}"
177
+ end
143
178
  end
144
179
  end
145
180
 
146
- handler(Handler, priority: 1)
181
+ handler(Handler, step: :sign, priority: 97)
147
182
  end
148
183
  end
149
184
  end
@@ -31,13 +31,11 @@ module Aws
31
31
  end
32
32
 
33
33
  def list(ref, values, prefix)
34
- if values.empty?
35
- set(prefix, '')
36
- else
37
- member_ref = ref.shape.member
38
- values.each.with_index do |value, n|
39
- format(member_ref, value, "#{prefix}.#{n+1}")
40
- end
34
+ return if values.empty?
35
+
36
+ member_ref = ref.shape.member
37
+ values.each.with_index do |value, n|
38
+ format(member_ref, value, "#{prefix}.#{n + 1}")
41
39
  end
42
40
  end
43
41
 
@@ -5,9 +5,10 @@ module Aws
5
5
  # NOTE: headers could be already populated if specified on input shape
6
6
  class ContentTypeHandler < Seahorse::Client::Handler
7
7
  def call(context)
8
- body = context.http_request.body
9
-
10
- if (payload = context.operation.input[:payload_member])
8
+ if eventstream?(context)
9
+ context.http_request.headers['Content-Type'] ||=
10
+ 'application/vnd.amazon.eventstream'
11
+ elsif (payload = context.operation.input[:payload_member])
11
12
  case payload.shape
12
13
  when Seahorse::Model::Shapes::BlobShape
13
14
  context.http_request.headers['Content-Type'] ||=
@@ -18,7 +19,8 @@ module Aws
18
19
  else
19
20
  apply_default_content_type(context)
20
21
  end
21
- elsif !body.respond_to?(:size) || non_empty_body?(body)
22
+ elsif (body = context.http_request.body) &&
23
+ (!body.respond_to?(:size) || non_empty_body?(body))
22
24
  apply_default_content_type(context)
23
25
  end
24
26
 
@@ -31,6 +33,13 @@ module Aws
31
33
  body.respond_to?(:size) && body.size.positive?
32
34
  end
33
35
 
36
+ def eventstream?(context)
37
+ context.operation.input.shape.members.each do |_, ref|
38
+ return ref if ref.eventstream
39
+ end
40
+ false
41
+ end
42
+
34
43
  # content-type defaults as noted here:
35
44
  # rest-json: https://smithy.io/2.0/aws/protocols/aws-restxml-protocol.html#content-type
36
45
  # rest-xml: https://smithy.io/2.0/aws/protocols/aws-restxml-protocol.html#content-type