aws-sdk-core 3.196.1 → 3.199.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -0
- data/VERSION +1 -1
- data/lib/aws-sdk-core/binary/decode_handler.rb +3 -4
- data/lib/aws-sdk-core/binary/encode_handler.rb +1 -1
- data/lib/aws-sdk-core/binary/event_stream_decoder.rb +1 -0
- data/lib/aws-sdk-core/binary/event_stream_encoder.rb +4 -3
- data/lib/aws-sdk-core/cbor/cbor_engine.rb +19 -0
- data/lib/aws-sdk-core/cbor/decoder.rb +310 -0
- data/lib/aws-sdk-core/cbor/encoder.rb +243 -0
- data/lib/aws-sdk-core/cbor.rb +106 -0
- data/lib/aws-sdk-core/client_stubs.rb +3 -2
- data/lib/aws-sdk-core/endpoints/matchers.rb +5 -1
- data/lib/aws-sdk-core/error_handler.rb +41 -0
- data/lib/aws-sdk-core/json/error_handler.rb +6 -8
- data/lib/aws-sdk-core/json/handler.rb +5 -6
- data/lib/aws-sdk-core/json/json_engine.rb +3 -1
- data/lib/aws-sdk-core/json/oj_engine.rb +7 -1
- data/lib/aws-sdk-core/json/parser.rb +2 -0
- data/lib/aws-sdk-core/json.rb +43 -14
- data/lib/aws-sdk-core/pageable_response.rb +1 -1
- data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +14 -2
- data/lib/aws-sdk-core/plugins/global_configuration.rb +8 -9
- data/lib/aws-sdk-core/plugins/protocols/api_gateway.rb +3 -1
- data/lib/aws-sdk-core/plugins/protocols/ec2.rb +2 -24
- data/lib/aws-sdk-core/plugins/protocols/json_rpc.rb +6 -8
- data/lib/aws-sdk-core/plugins/protocols/query.rb +4 -2
- data/lib/aws-sdk-core/plugins/protocols/rest_json.rb +4 -3
- data/lib/aws-sdk-core/plugins/protocols/rest_xml.rb +5 -1
- data/lib/aws-sdk-core/plugins/protocols/rpc_v2.rb +17 -0
- data/lib/aws-sdk-core/plugins/request_compression.rb +10 -1
- data/lib/aws-sdk-core/plugins/retry_errors.rb +10 -3
- data/lib/aws-sdk-core/plugins/user_agent.rb +58 -24
- data/lib/aws-sdk-core/process_credentials.rb +45 -27
- data/lib/aws-sdk-core/query/ec2_handler.rb +27 -0
- data/lib/aws-sdk-core/query/handler.rb +4 -4
- data/lib/aws-sdk-core/query.rb +2 -1
- data/lib/aws-sdk-core/rest/{request/content_type.rb → content_type_handler.rb} +1 -1
- data/lib/aws-sdk-core/rest/handler.rb +3 -4
- data/lib/aws-sdk-core/rest/request/endpoint.rb +3 -1
- data/lib/aws-sdk-core/rest.rb +1 -1
- data/lib/aws-sdk-core/rpc_v2/builder.rb +62 -0
- data/lib/aws-sdk-core/rpc_v2/content_type_handler.rb +45 -0
- data/lib/aws-sdk-core/rpc_v2/error_handler.rb +84 -0
- data/lib/aws-sdk-core/rpc_v2/handler.rb +74 -0
- data/lib/aws-sdk-core/rpc_v2/parser.rb +90 -0
- data/lib/aws-sdk-core/rpc_v2.rb +6 -0
- data/lib/aws-sdk-core/stubbing/protocols/rpc_v2.rb +41 -0
- data/lib/aws-sdk-core/util.rb +4 -4
- data/lib/aws-sdk-core/waiters/poller.rb +1 -1
- data/lib/aws-sdk-core/xml/error_handler.rb +11 -37
- data/lib/aws-sdk-core/xml/parser.rb +2 -6
- data/lib/aws-sdk-core.rb +6 -2
- data/lib/aws-sdk-sso/client.rb +6 -3
- data/lib/aws-sdk-sso.rb +1 -1
- data/lib/aws-sdk-ssooidc/client.rb +6 -3
- data/lib/aws-sdk-ssooidc.rb +1 -1
- data/lib/aws-sdk-sts/client.rb +6 -3
- data/lib/aws-sdk-sts.rb +1 -1
- data/lib/seahorse/client/base.rb +17 -7
- data/lib/seahorse/client/handler.rb +1 -1
- data/lib/seahorse/client/plugins/endpoint.rb +0 -1
- metadata +22 -8
- /data/lib/aws-sdk-core/xml/parser/{engines/libxml.rb → libxml_engine.rb} +0 -0
- /data/lib/aws-sdk-core/xml/parser/{engines/nokogiri.rb → nokogiri_engine.rb} +0 -0
- /data/lib/aws-sdk-core/xml/parser/{engines/oga.rb → oga_engine.rb} +0 -0
- /data/lib/aws-sdk-core/xml/parser/{engines/ox.rb → ox_engine.rb} +0 -0
- /data/lib/aws-sdk-core/xml/parser/{engines/rexml.rb → rexml_engine.rb} +0 -0
@@ -113,7 +113,6 @@ Specifies which retry algorithm to use. Values are:
|
|
113
113
|
functionality of `standard` mode along with automatic client side
|
114
114
|
throttling. This is a provisional mode that may change behavior
|
115
115
|
in the future.
|
116
|
-
|
117
116
|
DOCS
|
118
117
|
resolve_retry_mode(cfg)
|
119
118
|
end
|
@@ -235,7 +234,7 @@ a clock skew correction and retry requests with skewed client clocks.
|
|
235
234
|
|
236
235
|
get_send_token(config)
|
237
236
|
add_retry_headers(context)
|
238
|
-
response = @handler.call(context)
|
237
|
+
response = with_metric(config.retry_mode) { @handler.call(context) }
|
239
238
|
error_inspector = Retries::ErrorInspector.new(
|
240
239
|
response.error, response.context.http_response.status_code
|
241
240
|
)
|
@@ -272,6 +271,10 @@ a clock skew correction and retry requests with skewed client clocks.
|
|
272
271
|
|
273
272
|
private
|
274
273
|
|
274
|
+
def with_metric(retry_mode, &block)
|
275
|
+
Aws::Plugins::UserAgent.metric("RETRY_MODE_#{retry_mode.upcase}", &block)
|
276
|
+
end
|
277
|
+
|
275
278
|
def get_send_token(config)
|
276
279
|
# either fail fast or block until a token becomes available
|
277
280
|
# must be configurable
|
@@ -359,7 +362,7 @@ a clock skew correction and retry requests with skewed client clocks.
|
|
359
362
|
class LegacyHandler < Seahorse::Client::Handler
|
360
363
|
|
361
364
|
def call(context)
|
362
|
-
response = @handler.call(context)
|
365
|
+
response = with_metric { @handler.call(context) }
|
363
366
|
if response.error
|
364
367
|
error_inspector = Retries::ErrorInspector.new(
|
365
368
|
response.error, response.context.http_response.status_code
|
@@ -378,6 +381,10 @@ a clock skew correction and retry requests with skewed client clocks.
|
|
378
381
|
|
379
382
|
private
|
380
383
|
|
384
|
+
def with_metric(&block)
|
385
|
+
Aws::Plugins::UserAgent.metric('RETRY_MODE_LEGACY', &block)
|
386
|
+
end
|
387
|
+
|
381
388
|
def retry_if_possible(response, error_inspector)
|
382
389
|
context = response.context
|
383
390
|
if should_retry?(context, error_inspector)
|
@@ -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
|
@@ -23,12 +40,20 @@ variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
|
|
23
40
|
app_id
|
24
41
|
end
|
25
42
|
|
26
|
-
|
27
|
-
|
28
|
-
|
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]
|
29
51
|
block.call
|
30
52
|
ensure
|
31
|
-
Thread.current[:
|
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
|
32
57
|
end
|
33
58
|
|
34
59
|
# @api private
|
@@ -49,15 +74,24 @@ variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
|
|
49
74
|
|
50
75
|
def to_s
|
51
76
|
ua = "aws-sdk-ruby3/#{CORE_GEM_VERSION}"
|
52
|
-
ua += ' ua/2.
|
53
|
-
|
77
|
+
ua += ' ua/2.1'
|
78
|
+
if (api_m = api_metadata)
|
79
|
+
ua += " #{api_m}"
|
80
|
+
end
|
54
81
|
ua += " #{os_metadata}"
|
55
82
|
ua += " #{language_metadata}"
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
61
95
|
if @context.config.user_agent_suffix
|
62
96
|
ua += " #{@context.config.user_agent_suffix}"
|
63
97
|
end
|
@@ -93,7 +127,6 @@ variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
|
|
93
127
|
local_version = Gem::Platform.local.version
|
94
128
|
metadata += "##{local_version}" if local_version
|
95
129
|
metadata += " md/#{RbConfig::CONFIG['host_cpu']}"
|
96
|
-
metadata
|
97
130
|
end
|
98
131
|
|
99
132
|
# Used to be RUBY_ENGINE/RUBY_VERSION
|
@@ -107,11 +140,7 @@ variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
|
|
107
140
|
"exec-env/#{execution_env}"
|
108
141
|
end
|
109
142
|
|
110
|
-
def
|
111
|
-
"cfg/retry-mode##{@context.config.retry_mode}"
|
112
|
-
end
|
113
|
-
|
114
|
-
def app_id
|
143
|
+
def app_id_metadata
|
115
144
|
return unless (app_id = @context.config.sdk_ua_app_id)
|
116
145
|
|
117
146
|
# Sanitize and only allow these characters
|
@@ -119,12 +148,6 @@ variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
|
|
119
148
|
"app/#{app_id}"
|
120
149
|
end
|
121
150
|
|
122
|
-
def feature_metadata
|
123
|
-
return unless Thread.current[:aws_sdk_core_user_agent_feature]
|
124
|
-
|
125
|
-
Thread.current[:aws_sdk_core_user_agent_feature].join(' ')
|
126
|
-
end
|
127
|
-
|
128
151
|
def framework_metadata
|
129
152
|
if (frameworks_cfg = @context.config.user_agent_frameworks).empty?
|
130
153
|
return
|
@@ -141,10 +164,21 @@ variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
|
|
141
164
|
end
|
142
165
|
frameworks.map { |n, v| "lib/#{n}##{v}" }.join(' ')
|
143
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
|
144
178
|
end
|
145
179
|
end
|
146
180
|
|
147
|
-
handler(Handler, priority:
|
181
|
+
handler(Handler, step: :sign, priority: 97)
|
148
182
|
end
|
149
183
|
end
|
150
184
|
end
|
@@ -2,9 +2,15 @@
|
|
2
2
|
|
3
3
|
module Aws
|
4
4
|
# A credential provider that executes a given process and attempts
|
5
|
-
# to read its stdout to
|
5
|
+
# to read its stdout to receive a JSON payload containing the credentials.
|
6
6
|
#
|
7
|
-
# credentials = Aws::ProcessCredentials.new('/usr/bin/credential_proc')
|
7
|
+
# credentials = Aws::ProcessCredentials.new(['/usr/bin/credential_proc'])
|
8
|
+
# ec2 = Aws::EC2::Client.new(credentials: credentials)
|
9
|
+
#
|
10
|
+
# Arguments should be provided as strings in the array, for example:
|
11
|
+
#
|
12
|
+
# process = ['/usr/bin/credential_proc', 'arg1', 'arg2']
|
13
|
+
# credentials = Aws::ProcessCredentials.new(process)
|
8
14
|
# ec2 = Aws::EC2::Client.new(credentials: credentials)
|
9
15
|
#
|
10
16
|
# Automatically handles refreshing credentials if an Expiration time is
|
@@ -19,40 +25,49 @@ module Aws
|
|
19
25
|
# Creates a new ProcessCredentials object, which allows an
|
20
26
|
# external process to be used as a credential provider.
|
21
27
|
#
|
22
|
-
# @param [String] process
|
23
|
-
#
|
28
|
+
# @param [Array<String>, String] process An array of strings including
|
29
|
+
# the process name and its arguments to execute, or a single string to be
|
30
|
+
# executed by the shell (deprecated and insecure).
|
24
31
|
def initialize(process)
|
32
|
+
if process.is_a?(String)
|
33
|
+
warn('Passing a single string to Aws::ProcessCredentials.new '\
|
34
|
+
'is insecure, please use use an array of system arguments instead')
|
35
|
+
end
|
25
36
|
@process = process
|
26
|
-
@credentials = credentials_from_process
|
37
|
+
@credentials = credentials_from_process
|
27
38
|
@async_refresh = false
|
28
39
|
|
29
40
|
super
|
30
41
|
end
|
31
42
|
|
32
43
|
private
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
44
|
+
|
45
|
+
def credentials_from_process
|
46
|
+
r, w = IO.pipe
|
47
|
+
success = system(*@process, out: w)
|
48
|
+
w.close
|
49
|
+
raw_out = r.read
|
50
|
+
r.close
|
51
|
+
|
52
|
+
unless success
|
53
|
+
raise Errors::InvalidProcessCredentialsPayload.new(
|
54
|
+
'credential_process provider failure, the credential process had '\
|
55
|
+
'non zero exit status and failed to provide credentials'
|
56
|
+
)
|
39
57
|
end
|
40
58
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
raise Errors::InvalidProcessCredentialsPayload.new("Invalid JSON response")
|
46
|
-
end
|
47
|
-
payload_version = creds_json['Version']
|
48
|
-
if payload_version == 1
|
49
|
-
_parse_payload_format_v1(creds_json)
|
50
|
-
else
|
51
|
-
raise Errors::InvalidProcessCredentialsPayload.new("Invalid version #{payload_version} for credentials payload")
|
52
|
-
end
|
53
|
-
else
|
54
|
-
raise Errors::InvalidProcessCredentialsPayload.new('credential_process provider failure, the credential process had non zero exit status and failed to provide credentials')
|
59
|
+
begin
|
60
|
+
creds_json = Aws::Json.load(raw_out)
|
61
|
+
rescue Aws::Json::ParseError
|
62
|
+
raise Errors::InvalidProcessCredentialsPayload.new('Invalid JSON response')
|
55
63
|
end
|
64
|
+
|
65
|
+
payload_version = creds_json['Version']
|
66
|
+
return _parse_payload_format_v1(creds_json) if payload_version == 1
|
67
|
+
|
68
|
+
raise Errors::InvalidProcessCredentialsPayload.new(
|
69
|
+
"Invalid version #{payload_version} for credentials payload"
|
70
|
+
)
|
56
71
|
end
|
57
72
|
|
58
73
|
def _parse_payload_format_v1(creds_json)
|
@@ -64,11 +79,14 @@ module Aws
|
|
64
79
|
|
65
80
|
@expiration = creds_json['Expiration'] ? Time.iso8601(creds_json['Expiration']) : nil
|
66
81
|
return creds if creds.set?
|
67
|
-
|
82
|
+
|
83
|
+
raise Errors::InvalidProcessCredentialsPayload.new(
|
84
|
+
'Invalid payload for JSON credentials version 1'
|
85
|
+
)
|
68
86
|
end
|
69
87
|
|
70
88
|
def refresh
|
71
|
-
@credentials = credentials_from_process
|
89
|
+
@credentials = credentials_from_process
|
72
90
|
end
|
73
91
|
|
74
92
|
def near_expiration?(expiration_length)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
# @api private
|
5
|
+
module Query
|
6
|
+
class EC2Handler < Aws::Query::Handler
|
7
|
+
|
8
|
+
def apply_params(param_list, params, rules)
|
9
|
+
Aws::Query::EC2ParamBuilder.new(param_list).apply(rules, params)
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse_xml(context)
|
13
|
+
if (rules = context.operation.output)
|
14
|
+
parser = Xml::Parser.new(rules)
|
15
|
+
parser.parse(xml(context)) do |path, value|
|
16
|
+
if path.size == 2 && path.last == 'requestId'
|
17
|
+
context.metadata[:request_id] = value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
else
|
21
|
+
EmptyStructure.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -27,13 +27,13 @@ module Aws
|
|
27
27
|
# @return [Seahorse::Client::Response]
|
28
28
|
def call(context)
|
29
29
|
build_request(context)
|
30
|
-
@handler.call(context).on_success do |
|
31
|
-
|
30
|
+
@handler.call(context).on_success do |resp|
|
31
|
+
resp.error = nil
|
32
32
|
parsed = parse_xml(context)
|
33
33
|
if parsed.nil? || parsed == EmptyStructure
|
34
|
-
|
34
|
+
resp.data = EmptyStructure.new
|
35
35
|
else
|
36
|
-
|
36
|
+
resp.data = parsed
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
data/lib/aws-sdk-core/query.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'query/ec2_param_builder'
|
4
3
|
require_relative 'query/handler'
|
4
|
+
require_relative 'query/ec2_handler'
|
5
5
|
require_relative 'query/param'
|
6
6
|
require_relative 'query/param_builder'
|
7
|
+
require_relative 'query/ec2_param_builder'
|
7
8
|
require_relative 'query/param_list'
|
@@ -7,10 +7,9 @@ module Aws
|
|
7
7
|
|
8
8
|
def call(context)
|
9
9
|
Rest::Request::Builder.new.apply(context)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
resp
|
10
|
+
response = @handler.call(context)
|
11
|
+
response.on(200..299) { |resp| Response::Parser.new.apply(resp) }
|
12
|
+
response.on(200..599) { |_resp| apply_request_id(context) }
|
14
13
|
end
|
15
14
|
|
16
15
|
private
|
@@ -30,7 +30,9 @@ module Aws
|
|
30
30
|
private
|
31
31
|
|
32
32
|
def apply_path_params(uri, params)
|
33
|
-
path = uri.path.sub(%r{/$}, '')
|
33
|
+
path = uri.path.sub(%r{/$}, '')
|
34
|
+
# handle trailing slash
|
35
|
+
path += @path_pattern.split('?')[0] if path.empty? || @path_pattern != '/'
|
34
36
|
uri.path = path.gsub(/{.+?}/) do |placeholder|
|
35
37
|
param_value_for_placeholder(placeholder, params)
|
36
38
|
end
|
data/lib/aws-sdk-core/rest.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'rest/handler'
|
4
|
+
require_relative 'rest/content_type_handler'
|
4
5
|
require_relative 'rest/request/body'
|
5
6
|
require_relative 'rest/request/builder'
|
6
7
|
require_relative 'rest/request/endpoint'
|
7
8
|
require_relative 'rest/request/headers'
|
8
9
|
require_relative 'rest/request/querystring_builder'
|
9
|
-
require_relative 'rest/request/content_type'
|
10
10
|
require_relative 'rest/response/body'
|
11
11
|
require_relative 'rest/response/headers'
|
12
12
|
require_relative 'rest/response/parser'
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module Aws
|
6
|
+
module RpcV2
|
7
|
+
class Builder
|
8
|
+
include Seahorse::Model::Shapes
|
9
|
+
|
10
|
+
def initialize(rules, _options = {})
|
11
|
+
@rules = rules
|
12
|
+
end
|
13
|
+
|
14
|
+
def serialize(params)
|
15
|
+
# If the input shape is empty, do not set a body. This is
|
16
|
+
# different than if the input shape is a structure with no members.
|
17
|
+
return nil if @rules.shape.struct_class == EmptyStructure
|
18
|
+
|
19
|
+
Cbor.encode(format(@rules, params))
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def structure(ref, values)
|
25
|
+
shape = ref.shape
|
26
|
+
values.each_pair.with_object({}) do |(key, value), data|
|
27
|
+
if shape.member?(key) && !value.nil?
|
28
|
+
member_ref = shape.member(key)
|
29
|
+
member_name = member_ref.location_name || key
|
30
|
+
data[member_name] = format(member_ref, value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def list(ref, values)
|
36
|
+
member_ref = ref.shape.member
|
37
|
+
values.collect { |value| format(member_ref, value) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def map(ref, values)
|
41
|
+
value_ref = ref.shape.value
|
42
|
+
values.each.with_object({}) do |(key, value), data|
|
43
|
+
data[key] = format(value_ref, value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def blob(value)
|
48
|
+
(String === value ? value : value.read).force_encoding(Encoding::BINARY)
|
49
|
+
end
|
50
|
+
|
51
|
+
def format(ref, value)
|
52
|
+
case ref.shape
|
53
|
+
when StructureShape then structure(ref, value)
|
54
|
+
when ListShape then list(ref, value)
|
55
|
+
when MapShape then map(ref, value)
|
56
|
+
when BlobShape then blob(value)
|
57
|
+
else value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module RpcV2
|
5
|
+
class ContentTypeHandler < Seahorse::Client::Handler
|
6
|
+
def call(context)
|
7
|
+
content_type =
|
8
|
+
if eventstream_input?(context)
|
9
|
+
'application/vnd.amazon.eventstream'
|
10
|
+
elsif !empty_input_structure?(context)
|
11
|
+
'application/cbor'
|
12
|
+
end
|
13
|
+
accept =
|
14
|
+
if eventstream_output?(context)
|
15
|
+
'application/vnd.amazon.eventstream'
|
16
|
+
end
|
17
|
+
|
18
|
+
headers = context.http_request.headers
|
19
|
+
headers['Content-Type'] ||= content_type if content_type
|
20
|
+
headers['Accept'] ||= accept if accept
|
21
|
+
@handler.call(context)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def eventstream_input?(context)
|
27
|
+
context.operation.input.shape.members.each do |_, ref|
|
28
|
+
return true if ref.eventstream
|
29
|
+
end
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
def eventstream_output?(context)
|
34
|
+
context.operation.output.shape.members.each do |_, ref|
|
35
|
+
return true if ref.eventstream
|
36
|
+
end
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
def empty_input_structure?(context)
|
41
|
+
context.operation.input.shape.struct_class == EmptyStructure
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module RpcV2
|
5
|
+
class ErrorHandler < Aws::ErrorHandler
|
6
|
+
|
7
|
+
def call(context)
|
8
|
+
# Malformed responses should throw an http based error, so we check
|
9
|
+
# 200 range for error handling only for this case.
|
10
|
+
@handler.call(context).on(200..599) do |response|
|
11
|
+
if !valid_response?(context)
|
12
|
+
code, message, data = http_status_error(context)
|
13
|
+
response.error = build_error(context, code, message, data)
|
14
|
+
elsif (300..599).cover?(context.http_response.status_code)
|
15
|
+
response.error = error(context)
|
16
|
+
end
|
17
|
+
response.data = nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def valid_response?(context)
|
24
|
+
req_header = context.http_request.headers['smithy-protocol']
|
25
|
+
resp_header = context.http_response.headers['smithy-protocol']
|
26
|
+
req_header == resp_header
|
27
|
+
end
|
28
|
+
|
29
|
+
def extract_error(body, context)
|
30
|
+
data = Cbor.decode(body)
|
31
|
+
code = error_code(data, context)
|
32
|
+
message = data['message']
|
33
|
+
data = parse_error_data(context, body, code)
|
34
|
+
[code, message, data]
|
35
|
+
rescue Cbor::Error
|
36
|
+
[http_status_error_code(context), '', EmptyStructure.new]
|
37
|
+
end
|
38
|
+
|
39
|
+
def error_code(data, context)
|
40
|
+
code =
|
41
|
+
if aws_query_error?(context)
|
42
|
+
error = context.http_response.headers['x-amzn-query-error'].split(';')[0]
|
43
|
+
remove_prefix(error, context)
|
44
|
+
else
|
45
|
+
data['__type']
|
46
|
+
end
|
47
|
+
if code
|
48
|
+
code.split('#').last
|
49
|
+
else
|
50
|
+
http_status_error_code(context)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_error_data(context, body, code)
|
55
|
+
data = EmptyStructure.new
|
56
|
+
if (error_rules = context.operation.errors)
|
57
|
+
error_rules.each do |rule|
|
58
|
+
# match modeled shape name with the type(code) only
|
59
|
+
# some type(code) might contains invalid characters
|
60
|
+
# such as ':' (efs) etc
|
61
|
+
match = rule.shape.name == code.gsub(/[^^a-zA-Z0-9]/, '')
|
62
|
+
next unless match && rule.shape.members.any?
|
63
|
+
|
64
|
+
data = Parser.new(rule).parse(body)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
data
|
68
|
+
end
|
69
|
+
|
70
|
+
def aws_query_error?(context)
|
71
|
+
context.config.api.metadata['awsQueryCompatible'] &&
|
72
|
+
context.http_response.headers['x-amzn-query-error']
|
73
|
+
end
|
74
|
+
|
75
|
+
def remove_prefix(error_code, context)
|
76
|
+
if (prefix = context.config.api.metadata['errorPrefix'])
|
77
|
+
error_code.sub(/^#{prefix}/, '')
|
78
|
+
else
|
79
|
+
error_code
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module RpcV2
|
5
|
+
class Handler < Seahorse::Client::Handler
|
6
|
+
# @param [Seahorse::Client::RequestContext] context
|
7
|
+
# @return [Seahorse::Client::Response]
|
8
|
+
def call(context)
|
9
|
+
build_request(context)
|
10
|
+
response = @handler.call(context)
|
11
|
+
response.on(200..299) { |resp| resp.data = parse_body(context) }
|
12
|
+
response.on(200..599) { |_resp| apply_request_id(context) }
|
13
|
+
response
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def build_request(context)
|
19
|
+
context.http_request.headers['smithy-protocol'] = 'rpc-v2-cbor'
|
20
|
+
context.http_request.http_method = 'POST'
|
21
|
+
context.http_request.body = build_body(context)
|
22
|
+
build_url(context)
|
23
|
+
end
|
24
|
+
|
25
|
+
def build_url(context)
|
26
|
+
base = context.http_request.endpoint
|
27
|
+
service_name = context.config.api.metadata['targetPrefix']
|
28
|
+
base.path += "/service/#{service_name}/operation/#{context.operation.name}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_body(context)
|
32
|
+
Builder.new(context.operation.input).serialize(context.params)
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_body(context)
|
36
|
+
cbor = context.http_response.body_contents
|
37
|
+
if (rules = context.operation.output)
|
38
|
+
if cbor.is_a?(Array)
|
39
|
+
# an array of emitted events
|
40
|
+
if cbor[0].respond_to?(:response)
|
41
|
+
# initial response exists
|
42
|
+
# it must be the first event arrived
|
43
|
+
resp_struct = cbor.shift.response
|
44
|
+
else
|
45
|
+
resp_struct = context.operation.output.shape.struct_class.new
|
46
|
+
end
|
47
|
+
|
48
|
+
rules.shape.members.each do |name, ref|
|
49
|
+
if ref.eventstream
|
50
|
+
resp_struct.send("#{name}=", cbor.to_enum)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
resp_struct
|
54
|
+
else
|
55
|
+
Parser.new(
|
56
|
+
rules,
|
57
|
+
query_compatible: query_compatible?(context)
|
58
|
+
).parse(cbor)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
EmptyStructure.new
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def apply_request_id(context)
|
66
|
+
context[:request_id] = context.http_response.headers['x-amzn-requestid']
|
67
|
+
end
|
68
|
+
|
69
|
+
def query_compatible?(context)
|
70
|
+
context.config.api.metadata.key?('awsQueryCompatible')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|