aws-sdk-core 3.178.0 → 3.233.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 +709 -0
- data/VERSION +1 -1
- data/lib/aws-defaults/default_configuration.rb +1 -2
- data/lib/aws-defaults.rb +4 -1
- data/lib/aws-sdk-core/arn.rb +1 -3
- data/lib/aws-sdk-core/assume_role_credentials.rb +13 -5
- data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +14 -7
- data/lib/aws-sdk-core/binary/decode_handler.rb +3 -9
- data/lib/aws-sdk-core/binary/encode_handler.rb +1 -1
- data/lib/aws-sdk-core/binary/event_builder.rb +34 -37
- 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/decoder.rb +308 -0
- data/lib/aws-sdk-core/cbor/encoder.rb +243 -0
- data/lib/aws-sdk-core/cbor.rb +53 -0
- data/lib/aws-sdk-core/client_side_monitoring.rb +9 -0
- data/lib/aws-sdk-core/client_stubs.rb +33 -55
- data/lib/aws-sdk-core/credential_provider.rb +5 -1
- data/lib/aws-sdk-core/credential_provider_chain.rb +38 -11
- data/lib/aws-sdk-core/credentials.rb +19 -6
- data/lib/aws-sdk-core/ec2_metadata.rb +1 -1
- data/lib/aws-sdk-core/ecs_credentials.rb +79 -11
- data/lib/aws-sdk-core/endpoints/endpoint.rb +3 -1
- data/lib/aws-sdk-core/endpoints/matchers.rb +21 -19
- data/lib/aws-sdk-core/endpoints.rb +101 -21
- data/lib/aws-sdk-core/error_handler.rb +46 -0
- data/lib/aws-sdk-core/errors.rb +14 -5
- data/lib/aws-sdk-core/event_emitter.rb +1 -17
- data/lib/aws-sdk-core/ini_parser.rb +8 -1
- data/lib/aws-sdk-core/instance_profile_credentials.rb +168 -155
- data/lib/aws-sdk-core/json/builder.rb +8 -1
- data/lib/aws-sdk-core/json/error_handler.rb +29 -13
- data/lib/aws-sdk-core/json/handler.rb +13 -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 +33 -3
- data/lib/aws-sdk-core/json.rb +43 -14
- data/lib/aws-sdk-core/log/param_filter.rb +2 -2
- data/lib/aws-sdk-core/log/param_formatter.rb +7 -3
- data/lib/aws-sdk-core/log.rb +10 -0
- data/lib/aws-sdk-core/lru_cache.rb +75 -0
- data/lib/aws-sdk-core/pageable_response.rb +1 -1
- data/lib/aws-sdk-core/param_validator.rb +9 -4
- data/lib/aws-sdk-core/plugins/bearer_authorization.rb +2 -0
- data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +332 -167
- data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +1 -1
- data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +14 -2
- data/lib/aws-sdk-core/plugins/credentials_configuration.rb +78 -56
- data/lib/aws-sdk-core/plugins/endpoint_pattern.rb +40 -32
- data/lib/aws-sdk-core/plugins/global_configuration.rb +8 -9
- data/lib/aws-sdk-core/plugins/http_checksum.rb +3 -8
- data/lib/aws-sdk-core/plugins/invocation_id.rb +1 -11
- data/lib/aws-sdk-core/plugins/logging.rb +2 -0
- 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 +3 -15
- data/lib/aws-sdk-core/plugins/protocols/rest_xml.rb +3 -0
- data/lib/aws-sdk-core/plugins/protocols/rpc_v2.rb +17 -0
- data/lib/aws-sdk-core/plugins/regional_endpoint.rb +74 -25
- data/lib/aws-sdk-core/plugins/request_compression.rb +11 -2
- data/lib/aws-sdk-core/plugins/retry_errors.rb +12 -3
- data/lib/aws-sdk-core/plugins/sign.rb +55 -34
- data/lib/aws-sdk-core/plugins/signature_v2.rb +2 -1
- data/lib/aws-sdk-core/plugins/signature_v4.rb +2 -1
- data/lib/aws-sdk-core/plugins/stub_responses.rb +59 -9
- data/lib/aws-sdk-core/plugins/telemetry.rb +75 -0
- data/lib/aws-sdk-core/plugins/transfer_encoding.rb +16 -9
- data/lib/aws-sdk-core/plugins/user_agent.rb +101 -26
- data/lib/aws-sdk-core/plugins.rb +39 -0
- data/lib/aws-sdk-core/process_credentials.rb +48 -29
- data/lib/aws-sdk-core/query/ec2_handler.rb +27 -0
- data/lib/aws-sdk-core/query/ec2_param_builder.rb +5 -7
- data/lib/aws-sdk-core/query/handler.rb +4 -4
- data/lib/aws-sdk-core/query/param_builder.rb +2 -2
- data/lib/aws-sdk-core/query.rb +2 -1
- data/lib/aws-sdk-core/refreshing_credentials.rb +12 -6
- data/lib/aws-sdk-core/resources.rb +8 -0
- data/lib/aws-sdk-core/rest/content_type_handler.rb +60 -0
- data/lib/aws-sdk-core/rest/handler.rb +3 -4
- data/lib/aws-sdk-core/rest/request/body.rb +32 -5
- data/lib/aws-sdk-core/rest/request/endpoint.rb +24 -4
- data/lib/aws-sdk-core/rest/request/headers.rb +15 -7
- data/lib/aws-sdk-core/rest/request/querystring_builder.rb +62 -36
- data/lib/aws-sdk-core/rest/response/body.rb +15 -1
- data/lib/aws-sdk-core/rest/response/header_list_parser.rb +79 -0
- data/lib/aws-sdk-core/rest/response/headers.rb +8 -3
- data/lib/aws-sdk-core/rest.rb +1 -0
- data/lib/aws-sdk-core/rpc_v2/builder.rb +62 -0
- data/lib/aws-sdk-core/rpc_v2/cbor_engine.rb +18 -0
- data/lib/aws-sdk-core/rpc_v2/content_type_handler.rb +47 -0
- data/lib/aws-sdk-core/rpc_v2/error_handler.rb +95 -0
- data/lib/aws-sdk-core/rpc_v2/handler.rb +79 -0
- data/lib/aws-sdk-core/rpc_v2/parser.rb +98 -0
- data/lib/aws-sdk-core/rpc_v2.rb +69 -0
- data/lib/aws-sdk-core/shared_config.rb +113 -41
- data/lib/aws-sdk-core/shared_credentials.rb +1 -7
- data/lib/aws-sdk-core/sso_credentials.rb +4 -1
- data/lib/aws-sdk-core/static_token_provider.rb +1 -2
- data/lib/aws-sdk-core/stubbing/protocols/ec2.rb +12 -11
- data/lib/aws-sdk-core/stubbing/protocols/json.rb +11 -10
- data/lib/aws-sdk-core/stubbing/protocols/query.rb +7 -6
- data/lib/aws-sdk-core/stubbing/protocols/rest.rb +2 -1
- data/lib/aws-sdk-core/stubbing/protocols/rest_json.rb +9 -8
- data/lib/aws-sdk-core/stubbing/protocols/rest_xml.rb +6 -5
- data/lib/aws-sdk-core/stubbing/protocols/rpc_v2.rb +39 -0
- data/lib/aws-sdk-core/stubbing/stub_data.rb +11 -0
- data/lib/aws-sdk-core/stubbing.rb +22 -0
- data/lib/aws-sdk-core/telemetry/base.rb +177 -0
- data/lib/aws-sdk-core/telemetry/no_op.rb +70 -0
- data/lib/aws-sdk-core/telemetry/otel.rb +235 -0
- data/lib/aws-sdk-core/telemetry/span_kind.rb +22 -0
- data/lib/aws-sdk-core/telemetry/span_status.rb +59 -0
- data/lib/aws-sdk-core/telemetry.rb +78 -0
- data/lib/aws-sdk-core/token.rb +3 -3
- data/lib/aws-sdk-core/token_provider.rb +4 -0
- data/lib/aws-sdk-core/token_provider_chain.rb +2 -6
- data/lib/aws-sdk-core/util.rb +41 -1
- data/lib/aws-sdk-core/waiters/poller.rb +10 -5
- data/lib/aws-sdk-core/xml/builder.rb +17 -9
- data/lib/aws-sdk-core/xml/error_handler.rb +35 -43
- data/lib/aws-sdk-core/xml/parser/frame.rb +4 -20
- data/lib/aws-sdk-core/xml/parser/stack.rb +2 -0
- data/lib/aws-sdk-core/xml/parser.rb +2 -6
- data/lib/aws-sdk-core.rb +82 -107
- data/lib/aws-sdk-sso/client.rb +189 -96
- data/lib/aws-sdk-sso/client_api.rb +7 -0
- data/lib/aws-sdk-sso/endpoint_parameters.rb +9 -6
- data/lib/aws-sdk-sso/endpoint_provider.rb +30 -28
- data/lib/aws-sdk-sso/endpoints.rb +2 -54
- data/lib/aws-sdk-sso/plugins/endpoints.rb +23 -22
- data/lib/aws-sdk-sso/types.rb +1 -0
- data/lib/aws-sdk-sso.rb +15 -11
- data/lib/aws-sdk-ssooidc/client.rb +609 -129
- data/lib/aws-sdk-ssooidc/client_api.rb +94 -1
- data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +9 -6
- data/lib/aws-sdk-ssooidc/endpoint_provider.rb +30 -28
- data/lib/aws-sdk-ssooidc/endpoints.rb +2 -40
- data/lib/aws-sdk-ssooidc/errors.rb +62 -0
- data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +23 -20
- data/lib/aws-sdk-ssooidc/types.rb +419 -53
- data/lib/aws-sdk-ssooidc.rb +15 -11
- data/lib/aws-sdk-sts/client.rb +414 -147
- data/lib/aws-sdk-sts/client_api.rb +48 -9
- data/lib/aws-sdk-sts/customizations.rb +5 -2
- data/lib/aws-sdk-sts/endpoint_parameters.rb +10 -9
- data/lib/aws-sdk-sts/endpoint_provider.rb +52 -57
- data/lib/aws-sdk-sts/endpoints.rb +2 -118
- data/lib/aws-sdk-sts/errors.rb +15 -0
- data/lib/aws-sdk-sts/plugins/endpoints.rb +23 -30
- data/lib/aws-sdk-sts/presigner.rb +3 -7
- data/lib/aws-sdk-sts/types.rb +209 -27
- data/lib/aws-sdk-sts.rb +15 -11
- data/lib/seahorse/client/async_base.rb +4 -5
- data/lib/seahorse/client/async_response.rb +19 -0
- data/lib/seahorse/client/base.rb +18 -21
- data/lib/seahorse/client/h2/connection.rb +18 -28
- data/lib/seahorse/client/h2/handler.rb +14 -3
- data/lib/seahorse/client/handler.rb +1 -1
- data/lib/seahorse/client/http/response.rb +1 -1
- data/lib/seahorse/client/net_http/connection_pool.rb +15 -12
- data/lib/seahorse/client/net_http/handler.rb +21 -9
- data/lib/seahorse/client/net_http/patches.rb +1 -4
- data/lib/seahorse/client/networking_error.rb +1 -1
- data/lib/seahorse/client/plugin.rb +9 -0
- data/lib/seahorse/client/plugins/endpoint.rb +0 -1
- data/lib/seahorse/client/plugins/h2.rb +4 -4
- data/lib/seahorse/client/plugins/net_http.rb +57 -16
- data/lib/seahorse/client/plugins/request_callback.rb +31 -0
- data/lib/seahorse/client/request_context.rb +9 -2
- data/lib/seahorse/client/response.rb +8 -0
- data/lib/seahorse/model/shapes.rb +2 -2
- data/lib/seahorse/util.rb +2 -1
- data/sig/aws-sdk-core/async_client_stubs.rbs +21 -0
- data/sig/aws-sdk-core/client_stubs.rbs +10 -0
- data/sig/aws-sdk-core/errors.rbs +22 -0
- data/sig/aws-sdk-core/resources/collection.rbs +21 -0
- data/sig/aws-sdk-core/structure.rbs +4 -0
- data/sig/aws-sdk-core/telemetry/base.rbs +46 -0
- data/sig/aws-sdk-core/telemetry/otel.rbs +22 -0
- data/sig/aws-sdk-core/telemetry/span_kind.rbs +15 -0
- data/sig/aws-sdk-core/telemetry/span_status.rbs +24 -0
- data/sig/aws-sdk-core/waiters/errors.rbs +20 -0
- data/sig/aws-sdk-core.rbs +7 -0
- data/sig/seahorse/client/async_base.rbs +18 -0
- data/sig/seahorse/client/base.rbs +25 -0
- data/sig/seahorse/client/handler_builder.rbs +16 -0
- data/sig/seahorse/client/response.rbs +61 -0
- metadata +105 -23
- /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
@@ -30,7 +30,9 @@ module Aws
|
|
30
30
|
private
|
31
31
|
|
32
32
|
def apply_path_params(uri, params)
|
33
|
-
path = uri.path.sub(
|
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
|
@@ -38,22 +40,40 @@ module Aws
|
|
38
40
|
|
39
41
|
def param_value_for_placeholder(placeholder, params)
|
40
42
|
name = param_name(placeholder)
|
41
|
-
|
43
|
+
param_shape = @rules.shape.member(name).shape
|
44
|
+
value =
|
45
|
+
case param_shape
|
46
|
+
when Seahorse::Model::Shapes::TimestampShape
|
47
|
+
timestamp(param_shape, params[name]).to_s
|
48
|
+
else
|
49
|
+
params[name].to_s
|
50
|
+
end
|
51
|
+
|
42
52
|
raise ArgumentError, ":#{name} must not be blank" if value.empty?
|
43
53
|
|
44
54
|
if placeholder.include?('+')
|
45
|
-
value.gsub(
|
55
|
+
value.gsub(%r{[^/]+}) { |v| escape(v) }
|
46
56
|
else
|
47
57
|
escape(value)
|
48
58
|
end
|
49
59
|
end
|
50
60
|
|
51
61
|
def param_name(placeholder)
|
52
|
-
location_name = placeholder.gsub(/[{}+]/,'')
|
62
|
+
location_name = placeholder.gsub(/[{}+]/, '')
|
53
63
|
param_name, _ = @rules.shape.member_by_location_name(location_name)
|
54
64
|
param_name
|
55
65
|
end
|
56
66
|
|
67
|
+
def timestamp(ref, value)
|
68
|
+
case ref['timestampFormat']
|
69
|
+
when 'unixTimestamp' then value.to_i
|
70
|
+
when 'rfc822' then value.utc.httpdate
|
71
|
+
else
|
72
|
+
# serializing as RFC 3399 date-time is the default
|
73
|
+
value.utc.iso8601
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
57
77
|
def apply_querystring_params(uri, params)
|
58
78
|
# collect params that are supposed to be part of the query string
|
59
79
|
parts = @rules.shape.members.inject([]) do |prts, (member_name, member_ref)|
|
@@ -21,6 +21,7 @@ module Aws
|
|
21
21
|
@rules.shape.members.each do |name, ref|
|
22
22
|
value = params[name]
|
23
23
|
next if value.nil?
|
24
|
+
|
24
25
|
case ref.location
|
25
26
|
when 'header' then apply_header_value(http_req.headers, ref, value)
|
26
27
|
when 'headers' then apply_header_map(http_req.headers, ref, value)
|
@@ -49,18 +50,25 @@ module Aws
|
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
52
|
-
def list(headers, ref,
|
53
|
-
return if
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
.
|
53
|
+
def list(headers, ref, values)
|
54
|
+
return if values.nil?
|
55
|
+
|
56
|
+
member_ref = ref.shape.member
|
57
|
+
values = values.collect do |value|
|
58
|
+
case member_ref.shape
|
59
|
+
when TimestampShape
|
60
|
+
timestamp(member_ref, value).to_s
|
61
|
+
else
|
62
|
+
Seahorse::Util.escape_header_list_string(value.to_s)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
headers[ref.location_name] = values.compact.join(', ')
|
58
66
|
end
|
59
67
|
|
60
68
|
def apply_header_map(headers, ref, values)
|
61
69
|
prefix = ref.location_name || ''
|
62
70
|
values.each_pair do |name, value|
|
63
|
-
headers["#{prefix}#{name}"]
|
71
|
+
headers["#{prefix}#{name}"] ||= value.to_s
|
64
72
|
end
|
65
73
|
end
|
66
74
|
|
@@ -4,9 +4,16 @@ module Aws
|
|
4
4
|
module Rest
|
5
5
|
module Request
|
6
6
|
class QuerystringBuilder
|
7
|
-
|
8
7
|
include Seahorse::Model::Shapes
|
9
8
|
|
9
|
+
SUPPORTED_TYPES = [
|
10
|
+
BooleanShape,
|
11
|
+
FloatShape,
|
12
|
+
IntegerShape,
|
13
|
+
StringShape,
|
14
|
+
TimestampShape
|
15
|
+
].freeze
|
16
|
+
|
10
17
|
# Provide shape references and param values:
|
11
18
|
#
|
12
19
|
# [
|
@@ -23,39 +30,32 @@ module Aws
|
|
23
30
|
#
|
24
31
|
# @return [String] Returns a built querystring
|
25
32
|
def build(params)
|
33
|
+
# keys in query maps must NOT override other keys
|
34
|
+
query_keys = query_keys(params)
|
26
35
|
params.map do |(shape_ref, param_value)|
|
27
|
-
build_part(shape_ref, param_value)
|
28
|
-
end.join('&')
|
36
|
+
build_part(shape_ref, param_value, query_keys)
|
37
|
+
end.reject { |p| p.nil? || p.empty? }.join('&')
|
29
38
|
end
|
30
39
|
|
31
40
|
private
|
32
41
|
|
33
|
-
def
|
42
|
+
def query_keys(params)
|
43
|
+
keys = Set.new
|
44
|
+
params.each do |(shape_ref, _)|
|
45
|
+
keys << shape_ref.location_name unless shape_ref.shape.is_a?(MapShape)
|
46
|
+
end
|
47
|
+
keys
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_part(shape_ref, param_value, query_keys)
|
34
51
|
case shape_ref.shape
|
35
52
|
# supported scalar types
|
36
|
-
when
|
37
|
-
|
38
|
-
"#{param_name}=#{escape(param_value.to_s)}"
|
39
|
-
when TimestampShape
|
40
|
-
param_name = shape_ref.location_name
|
41
|
-
"#{param_name}=#{escape(timestamp(shape_ref, param_value))}"
|
53
|
+
when *SUPPORTED_TYPES
|
54
|
+
"#{shape_ref.location_name}=#{query_value(shape_ref, param_value)}"
|
42
55
|
when MapShape
|
43
|
-
|
44
|
-
query_map_of_string(param_value)
|
45
|
-
elsif ListShape === shape_ref.shape.value.shape
|
46
|
-
query_map_of_string_list(param_value)
|
47
|
-
else
|
48
|
-
msg = "only map of string and string list supported"
|
49
|
-
raise NotImplementedError, msg
|
50
|
-
end
|
56
|
+
generate_query_map(shape_ref, param_value, query_keys)
|
51
57
|
when ListShape
|
52
|
-
|
53
|
-
list_of_strings(shape_ref.location_name, param_value)
|
54
|
-
else
|
55
|
-
msg = "Only list of strings supported, got "\
|
56
|
-
"#{shape_ref.shape.member.shape.class.name}"
|
57
|
-
raise NotImplementedError, msg
|
58
|
-
end
|
58
|
+
generate_query_list(shape_ref, param_value)
|
59
59
|
else
|
60
60
|
raise NotImplementedError
|
61
61
|
end
|
@@ -71,34 +71,60 @@ module Aws
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
def
|
74
|
+
def query_value(ref, value)
|
75
|
+
case ref.shape
|
76
|
+
when TimestampShape
|
77
|
+
escape(timestamp(ref, value))
|
78
|
+
when *SUPPORTED_TYPES
|
79
|
+
escape(value.to_s)
|
80
|
+
else
|
81
|
+
raise NotImplementedError
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def generate_query_list(ref, values)
|
86
|
+
member_ref = ref.shape.member
|
87
|
+
values.map do |value|
|
88
|
+
value = query_value(member_ref, value)
|
89
|
+
"#{ref.location_name}=#{value}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_query_map(ref, value, query_keys)
|
94
|
+
case ref.shape.value.shape
|
95
|
+
when StringShape
|
96
|
+
query_map_of_string(value, query_keys)
|
97
|
+
when ListShape
|
98
|
+
query_map_of_string_list(value, query_keys)
|
99
|
+
else
|
100
|
+
msg = 'Only map of string and string list supported'
|
101
|
+
raise NotImplementedError, msg
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def query_map_of_string(hash, query_keys)
|
75
106
|
list = []
|
76
107
|
hash.each_pair do |key, value|
|
77
|
-
|
108
|
+
key = escape(key)
|
109
|
+
list << "#{key}=#{escape(value)}" unless query_keys.include?(key)
|
78
110
|
end
|
79
111
|
list
|
80
112
|
end
|
81
113
|
|
82
|
-
def query_map_of_string_list(hash)
|
114
|
+
def query_map_of_string_list(hash, query_keys)
|
83
115
|
list = []
|
84
116
|
hash.each_pair do |key, values|
|
117
|
+
key = escape(key)
|
85
118
|
values.each do |value|
|
86
|
-
list << "#{
|
119
|
+
list << "#{key}=#{escape(value)}" unless query_keys.include?(key)
|
87
120
|
end
|
88
121
|
end
|
89
122
|
list
|
90
123
|
end
|
91
124
|
|
92
|
-
def list_of_strings(name, values)
|
93
|
-
values.map do |value|
|
94
|
-
"#{name}=#{escape(value)}"
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
125
|
def escape(string)
|
99
126
|
Seahorse::Util.uri_escape(string)
|
100
127
|
end
|
101
|
-
|
102
128
|
end
|
103
129
|
end
|
104
130
|
end
|
@@ -20,7 +20,8 @@ module Aws
|
|
20
20
|
if event_stream?
|
21
21
|
data[@rules[:payload]] = parse_eventstream(body)
|
22
22
|
elsif streaming?
|
23
|
-
|
23
|
+
# empty blob payloads are omitted
|
24
|
+
data[@rules[:payload]] = body unless empty_blob_payload?(body)
|
24
25
|
elsif @rules[:payload]
|
25
26
|
data[@rules[:payload]] = parse(body.read, @rules[:payload_member])
|
26
27
|
elsif !@rules.shape.member_names.empty?
|
@@ -30,6 +31,19 @@ module Aws
|
|
30
31
|
|
31
32
|
private
|
32
33
|
|
34
|
+
def empty_blob_payload?(body)
|
35
|
+
true if non_streaming_blob_payload? && empty_body?(body)
|
36
|
+
end
|
37
|
+
|
38
|
+
def non_streaming_blob_payload?
|
39
|
+
@rules[:payload_member].shape.is_a?(BlobShape) &&
|
40
|
+
!@rules[:payload_member]['streaming']
|
41
|
+
end
|
42
|
+
|
43
|
+
def empty_body?(body)
|
44
|
+
body.respond_to?(:size) && body.size.zero?
|
45
|
+
end
|
46
|
+
|
33
47
|
def event_stream?
|
34
48
|
@rules[:payload] && @rules[:payload_member].eventstream
|
35
49
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
module Aws
|
6
|
+
module Rest
|
7
|
+
module Response
|
8
|
+
# @api private
|
9
|
+
module HeaderListParser
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# parse a list of possibly quoted and escaped string values
|
13
|
+
# Follows:
|
14
|
+
# # [RFC-7230's specification of header values](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6).
|
15
|
+
def parse_string_list(value)
|
16
|
+
buffer = StringScanner.new(value)
|
17
|
+
parsed = []
|
18
|
+
|
19
|
+
parsed << read_value(buffer) until buffer.eos?
|
20
|
+
|
21
|
+
parsed
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_timestamp_list(value, ref)
|
25
|
+
# timestamp lists use an http-date by default and are unescaped
|
26
|
+
# eg: Mon, 16 Dec 2019 23:48:18 GMT, Mon, 16 Dec 2019 23:48:18 GMT
|
27
|
+
case ref['timestampFormat'] || ref.shape['timestampFormat']
|
28
|
+
when 'unixTimestamp'
|
29
|
+
value.split(', ').map { |v| Time.at(v.to_f) }
|
30
|
+
when 'iso8601' then value.split(', ').map { |v| Time.parse(v) }
|
31
|
+
else
|
32
|
+
# header default to rfc822/http-date, which has a comma after day
|
33
|
+
value.split(',').each_slice(2).map { |v| Time.parse(v[0] + v[1])}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def read_value(buffer)
|
40
|
+
until buffer.eos?
|
41
|
+
case buffer.peek(1)
|
42
|
+
when ' ', "\t"
|
43
|
+
# drop leading whitespace
|
44
|
+
buffer.getch
|
45
|
+
next
|
46
|
+
when '"'
|
47
|
+
buffer.getch # drop the quote and advance
|
48
|
+
return read_quoted_value(buffer)
|
49
|
+
else
|
50
|
+
return read_unquoted_value(buffer)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
# buffer is only whitespace
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def read_unquoted_value(buffer)
|
58
|
+
# there cannot be any escaped values
|
59
|
+
value = buffer.scan_until(/,|$/)
|
60
|
+
# drop the comma if we matched it
|
61
|
+
buffer.matched == ',' ? value.chop : value
|
62
|
+
end
|
63
|
+
|
64
|
+
def read_quoted_value(buffer)
|
65
|
+
# scan until we have an unescaped double quote
|
66
|
+
value = buffer.scan_until(/[^\\]"/)
|
67
|
+
raise ArgumentError, 'Invalid String list: No closing quote found' unless value
|
68
|
+
|
69
|
+
# drop any remaining whitespace/commas
|
70
|
+
buffer.scan_until(/[\s,]*/)
|
71
|
+
# the last character will always be the closing quote.
|
72
|
+
# Add a starting quote and then unescape (undump)
|
73
|
+
"\"#{value}".undump
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'time'
|
4
4
|
require 'base64'
|
5
|
+
require_relative 'header_list_parser'
|
5
6
|
|
6
7
|
module Aws
|
7
8
|
module Rest
|
@@ -36,12 +37,16 @@ module Aws
|
|
36
37
|
def cast_value(ref, value)
|
37
38
|
value = extract_json_trait(value) if ref['jsonvalue']
|
38
39
|
case ref.shape
|
39
|
-
when StringShape then value
|
40
|
+
when StringShape then value.to_s
|
40
41
|
when IntegerShape then value.to_i
|
41
|
-
when FloatShape then value
|
42
|
+
when FloatShape then Util.deserialize_number(value)
|
42
43
|
when BooleanShape then value == 'true'
|
43
44
|
when ListShape then
|
44
|
-
|
45
|
+
case ref.shape.member.shape
|
46
|
+
when StringShape then HeaderListParser.parse_string_list(value)
|
47
|
+
when TimestampShape then HeaderListParser.parse_timestamp_list(value, ref.shape.member)
|
48
|
+
else value.split(', ').map { |v| cast_value(ref.shape.member, v) }
|
49
|
+
end
|
45
50
|
when TimestampShape
|
46
51
|
if value =~ /^\d+(\.\d*)/
|
47
52
|
Time.at(value.to_f)
|
data/lib/aws-sdk-core/rest.rb
CHANGED
@@ -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
|
+
RpcV2.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,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../cbor'
|
4
|
+
|
5
|
+
module Aws
|
6
|
+
module RpcV2
|
7
|
+
# Pure Ruby implementation of CBOR encode and decode
|
8
|
+
module CborEngine
|
9
|
+
def self.encode(data)
|
10
|
+
Cbor::Encoder.new.add(data).bytes
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.decode(bytes)
|
14
|
+
Cbor::Decoder.new(bytes.force_encoding(Encoding::BINARY)).decode
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,47 @@
|
|
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
|
+
else
|
17
|
+
'application/cbor'
|
18
|
+
end
|
19
|
+
|
20
|
+
headers = context.http_request.headers
|
21
|
+
headers['Content-Type'] ||= content_type if content_type
|
22
|
+
headers['Accept'] ||= accept
|
23
|
+
@handler.call(context)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def eventstream_input?(context)
|
29
|
+
context.operation.input.shape.members.each do |_, ref|
|
30
|
+
return true if ref.eventstream
|
31
|
+
end
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def eventstream_output?(context)
|
36
|
+
context.operation.output.shape.members.each do |_, ref|
|
37
|
+
return true if ref.eventstream
|
38
|
+
end
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
def empty_input_structure?(context)
|
43
|
+
context.operation.input.shape.struct_class == EmptyStructure
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module RpcV2
|
5
|
+
# @api private
|
6
|
+
class ErrorHandler < Aws::ErrorHandler
|
7
|
+
|
8
|
+
def call(context)
|
9
|
+
# Malformed responses should throw an http based error, so we check
|
10
|
+
# 200 range for error handling only for this case.
|
11
|
+
@handler.call(context).on(200..599) do |response|
|
12
|
+
if !valid_response?(context)
|
13
|
+
code, message, data = http_status_error(context)
|
14
|
+
response.error = build_error(context, code, message, data)
|
15
|
+
elsif (300..599).cover?(context.http_response.status_code)
|
16
|
+
response.error = error(context)
|
17
|
+
end
|
18
|
+
response.data = nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def valid_response?(context)
|
25
|
+
req_header = context.http_request.headers['smithy-protocol']
|
26
|
+
resp_header = context.http_response.headers['smithy-protocol']
|
27
|
+
req_header == resp_header
|
28
|
+
end
|
29
|
+
|
30
|
+
def extract_error(body, context)
|
31
|
+
data = RpcV2.decode(body)
|
32
|
+
code = error_code(data, context)
|
33
|
+
message = data['message']
|
34
|
+
data = parse_error_data(context, body, code)
|
35
|
+
[code, message, data]
|
36
|
+
rescue Cbor::Error
|
37
|
+
[http_status_error_code(context), '', EmptyStructure.new]
|
38
|
+
end
|
39
|
+
|
40
|
+
def error_code(data, context)
|
41
|
+
# This is not correct per protocol tests. awsQueryError is intended to populate the
|
42
|
+
# error code of the error class. The error class should come from __type. Query and
|
43
|
+
# query compatible services currently have dynamic errors raised from error codes instead
|
44
|
+
# of the modeled error class. However, changing this in this major version would break
|
45
|
+
# existing usage.
|
46
|
+
code =
|
47
|
+
if aws_query_error?(context)
|
48
|
+
aws_query_error_code(context)
|
49
|
+
else
|
50
|
+
data['__type']
|
51
|
+
end
|
52
|
+
if code
|
53
|
+
code.split('#').last
|
54
|
+
else
|
55
|
+
http_status_error_code(context)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def aws_query_error?(context)
|
60
|
+
context.config.api.metadata['awsQueryCompatible'] &&
|
61
|
+
context.http_response.headers['x-amzn-query-error']
|
62
|
+
end
|
63
|
+
|
64
|
+
def aws_query_error_code(context)
|
65
|
+
query_header = context.http_response.headers['x-amzn-query-error']
|
66
|
+
error, _type = query_header.split(';') # type not supported
|
67
|
+
remove_prefix(error, context)
|
68
|
+
end
|
69
|
+
|
70
|
+
def remove_prefix(error_code, context)
|
71
|
+
if (prefix = context.config.api.metadata['errorPrefix'])
|
72
|
+
error_code.sub(/^#{prefix}/, '')
|
73
|
+
else
|
74
|
+
error_code
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse_error_data(context, body, code)
|
79
|
+
data = EmptyStructure.new
|
80
|
+
if (error_rules = context.operation.errors)
|
81
|
+
error_rules.each do |rule|
|
82
|
+
# match modeled shape name with the type(code) only
|
83
|
+
# some type(code) might contains invalid characters
|
84
|
+
# such as ':' (efs) etc
|
85
|
+
match = rule.shape.name == code.gsub(/[^^a-zA-Z0-9]/, '')
|
86
|
+
next unless match && rule.shape.members.any?
|
87
|
+
|
88
|
+
data = Parser.new(rule).parse(body)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
data
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,79 @@
|
|
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 = with_metric { @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 with_metric(&block)
|
19
|
+
Aws::Plugins::UserAgent.metric('PROTOCOL_RPC_V2_CBOR', &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_request(context)
|
23
|
+
context.http_request.headers['Smithy-Protocol'] = 'rpc-v2-cbor'
|
24
|
+
context.http_request.headers['X-Amzn-Query-Mode'] = 'true' if query_compatible?(context)
|
25
|
+
context.http_request.http_method = 'POST'
|
26
|
+
context.http_request.body = build_body(context)
|
27
|
+
build_url(context)
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_url(context)
|
31
|
+
base = context.http_request.endpoint
|
32
|
+
service_name = context.config.api.metadata['targetPrefix']
|
33
|
+
base.path += "/service/#{service_name}/operation/#{context.operation.name}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_body(context)
|
37
|
+
Builder.new(context.operation.input).serialize(context.params)
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_body(context)
|
41
|
+
cbor = context.http_response.body_contents
|
42
|
+
if (rules = context.operation.output)
|
43
|
+
if cbor.is_a?(Array)
|
44
|
+
# an array of emitted events
|
45
|
+
if cbor[0].respond_to?(:response)
|
46
|
+
# initial response exists
|
47
|
+
# it must be the first event arrived
|
48
|
+
resp_struct = cbor.shift.response
|
49
|
+
else
|
50
|
+
resp_struct = context.operation.output.shape.struct_class.new
|
51
|
+
end
|
52
|
+
|
53
|
+
rules.shape.members.each do |name, ref|
|
54
|
+
if ref.eventstream
|
55
|
+
resp_struct.send("#{name}=", cbor.to_enum)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
resp_struct
|
59
|
+
else
|
60
|
+
Parser.new(
|
61
|
+
rules,
|
62
|
+
query_compatible: query_compatible?(context)
|
63
|
+
).parse(cbor)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
EmptyStructure.new
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def apply_request_id(context)
|
71
|
+
context[:request_id] = context.http_response.headers['x-amzn-requestid']
|
72
|
+
end
|
73
|
+
|
74
|
+
def query_compatible?(context)
|
75
|
+
context.config.api.metadata.key?('awsQueryCompatible')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|