aws-sdk-core 3.192.1 → 3.197.0

Sign up to get free protection for your applications and to get access to all the features.
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