aws-sdk-core 3.191.0 → 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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +153 -1
  3. data/VERSION +1 -1
  4. data/lib/aws-sdk-core/binary/decode_handler.rb +3 -9
  5. data/lib/aws-sdk-core/binary/encode_handler.rb +1 -1
  6. data/lib/aws-sdk-core/binary/event_builder.rb +34 -37
  7. data/lib/aws-sdk-core/binary/event_stream_decoder.rb +1 -0
  8. data/lib/aws-sdk-core/binary/event_stream_encoder.rb +4 -3
  9. data/lib/aws-sdk-core/cbor/cbor_engine.rb +19 -0
  10. data/lib/aws-sdk-core/cbor/decoder.rb +310 -0
  11. data/lib/aws-sdk-core/cbor/encoder.rb +243 -0
  12. data/lib/aws-sdk-core/cbor.rb +106 -0
  13. data/lib/aws-sdk-core/client_stubs.rb +3 -2
  14. data/lib/aws-sdk-core/credential_provider.rb +1 -1
  15. data/lib/aws-sdk-core/ec2_metadata.rb +1 -1
  16. data/lib/aws-sdk-core/ecs_credentials.rb +2 -1
  17. data/lib/aws-sdk-core/endpoints/matchers.rb +5 -1
  18. data/lib/aws-sdk-core/error_handler.rb +41 -0
  19. data/lib/aws-sdk-core/event_emitter.rb +0 -16
  20. data/lib/aws-sdk-core/instance_profile_credentials.rb +3 -2
  21. data/lib/aws-sdk-core/json/builder.rb +8 -1
  22. data/lib/aws-sdk-core/json/error_handler.rb +15 -10
  23. data/lib/aws-sdk-core/json/handler.rb +5 -6
  24. data/lib/aws-sdk-core/json/json_engine.rb +3 -1
  25. data/lib/aws-sdk-core/json/oj_engine.rb +7 -1
  26. data/lib/aws-sdk-core/json/parser.rb +6 -1
  27. data/lib/aws-sdk-core/json.rb +43 -14
  28. data/lib/aws-sdk-core/lru_cache.rb +75 -0
  29. data/lib/aws-sdk-core/pageable_response.rb +1 -1
  30. data/lib/aws-sdk-core/param_validator.rb +7 -2
  31. data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +14 -2
  32. data/lib/aws-sdk-core/plugins/global_configuration.rb +8 -9
  33. data/lib/aws-sdk-core/plugins/invocation_id.rb +1 -11
  34. data/lib/aws-sdk-core/plugins/protocols/api_gateway.rb +3 -1
  35. data/lib/aws-sdk-core/plugins/protocols/ec2.rb +2 -24
  36. data/lib/aws-sdk-core/plugins/protocols/json_rpc.rb +6 -8
  37. data/lib/aws-sdk-core/plugins/protocols/query.rb +4 -2
  38. data/lib/aws-sdk-core/plugins/protocols/rest_json.rb +3 -15
  39. data/lib/aws-sdk-core/plugins/protocols/rest_xml.rb +3 -0
  40. data/lib/aws-sdk-core/plugins/protocols/rpc_v2.rb +17 -0
  41. data/lib/aws-sdk-core/plugins/request_compression.rb +11 -2
  42. data/lib/aws-sdk-core/plugins/retry_errors.rb +10 -3
  43. data/lib/aws-sdk-core/plugins/sign.rb +8 -3
  44. data/lib/aws-sdk-core/plugins/user_agent.rb +61 -26
  45. data/lib/aws-sdk-core/process_credentials.rb +45 -27
  46. data/lib/aws-sdk-core/query/ec2_handler.rb +27 -0
  47. data/lib/aws-sdk-core/query/ec2_param_builder.rb +5 -7
  48. data/lib/aws-sdk-core/query/handler.rb +4 -4
  49. data/lib/aws-sdk-core/query/param_builder.rb +2 -2
  50. data/lib/aws-sdk-core/query.rb +2 -1
  51. data/lib/aws-sdk-core/rest/content_type_handler.rb +60 -0
  52. data/lib/aws-sdk-core/rest/handler.rb +3 -4
  53. data/lib/aws-sdk-core/rest/request/body.rb +32 -5
  54. data/lib/aws-sdk-core/rest/request/endpoint.rb +24 -4
  55. data/lib/aws-sdk-core/rest/request/headers.rb +15 -7
  56. data/lib/aws-sdk-core/rest/request/querystring_builder.rb +23 -11
  57. data/lib/aws-sdk-core/rest/response/body.rb +15 -1
  58. data/lib/aws-sdk-core/rest/response/header_list_parser.rb +79 -0
  59. data/lib/aws-sdk-core/rest/response/headers.rb +8 -3
  60. data/lib/aws-sdk-core/rest.rb +1 -0
  61. data/lib/aws-sdk-core/rpc_v2/builder.rb +62 -0
  62. data/lib/aws-sdk-core/rpc_v2/content_type_handler.rb +45 -0
  63. data/lib/aws-sdk-core/rpc_v2/error_handler.rb +84 -0
  64. data/lib/aws-sdk-core/rpc_v2/handler.rb +74 -0
  65. data/lib/aws-sdk-core/rpc_v2/parser.rb +90 -0
  66. data/lib/aws-sdk-core/rpc_v2.rb +6 -0
  67. data/lib/aws-sdk-core/stubbing/protocols/rpc_v2.rb +41 -0
  68. data/lib/aws-sdk-core/util.rb +39 -0
  69. data/lib/aws-sdk-core/waiters/poller.rb +1 -1
  70. data/lib/aws-sdk-core/xml/builder.rb +17 -9
  71. data/lib/aws-sdk-core/xml/error_handler.rb +32 -42
  72. data/lib/aws-sdk-core/xml/parser/frame.rb +4 -20
  73. data/lib/aws-sdk-core/xml/parser/stack.rb +2 -0
  74. data/lib/aws-sdk-core/xml/parser.rb +2 -6
  75. data/lib/aws-sdk-core.rb +7 -2
  76. data/lib/aws-sdk-sso/client.rb +77 -49
  77. data/lib/aws-sdk-sso.rb +1 -1
  78. data/lib/aws-sdk-ssooidc/client.rb +127 -51
  79. data/lib/aws-sdk-ssooidc/client_api.rb +22 -0
  80. data/lib/aws-sdk-ssooidc/errors.rb +21 -0
  81. data/lib/aws-sdk-ssooidc/types.rb +77 -9
  82. data/lib/aws-sdk-ssooidc.rb +1 -1
  83. data/lib/aws-sdk-sts/client.rb +77 -49
  84. data/lib/aws-sdk-sts/client_api.rb +8 -8
  85. data/lib/aws-sdk-sts.rb +1 -1
  86. data/lib/seahorse/client/async_base.rb +1 -1
  87. data/lib/seahorse/client/async_response.rb +19 -0
  88. data/lib/seahorse/client/base.rb +18 -7
  89. data/lib/seahorse/client/h2/handler.rb +1 -0
  90. data/lib/seahorse/client/handler.rb +1 -1
  91. data/lib/seahorse/client/net_http/connection_pool.rb +3 -9
  92. data/lib/seahorse/client/plugin.rb +8 -0
  93. data/lib/seahorse/client/plugins/endpoint.rb +0 -1
  94. data/lib/seahorse/client/plugins/net_http.rb +48 -16
  95. data/lib/seahorse/model/shapes.rb +2 -2
  96. metadata +24 -7
  97. /data/lib/aws-sdk-core/xml/parser/{engines/libxml.rb → libxml_engine.rb} +0 -0
  98. /data/lib/aws-sdk-core/xml/parser/{engines/nokogiri.rb → nokogiri_engine.rb} +0 -0
  99. /data/lib/aws-sdk-core/xml/parser/{engines/oga.rb → oga_engine.rb} +0 -0
  100. /data/lib/aws-sdk-core/xml/parser/{engines/ox.rb → ox_engine.rb} +0 -0
  101. /data/lib/aws-sdk-core/xml/parser/{engines/rexml.rb → rexml_engine.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc07663afa282f94e8d7f48f837cb98da7041095d4e317435c12e78ea150ad37
4
- data.tar.gz: 3b7de307550bb34cf2751a48ffc58015c0cdd699706cdfed8c167f28b2ff483a
3
+ metadata.gz: d895f327aaebb1d2a4a50f3fd1c4e76e36104438bbf02f6d04399480561b4ef8
4
+ data.tar.gz: a060bd7053cb741fed767a7e71033dee9c8dd1dfd96fe31e4fa2d8525c0c61f9
5
5
  SHA512:
6
- metadata.gz: 283d65ac79f93a3ab22b34bc488d0d1a3fb706184a6efae14246973cc44cd2a0256987d10b75da5358a1fc0ac6ca24cea223ddbb27846da47c3af7a535a5f374
7
- data.tar.gz: 4951a75c31b534cc58a9e29a9f56e5228786f4e02f959fd74dba42079e7e86f51f9aa87947acd9d7fcb8f3efad6d8318f92f6e7eb271aa6b8c6e14af1e5a5920
6
+ metadata.gz: 4f91a98d16fc772e4ea6500b6ae6cbc1440666d7adee2bbbe2ed2f3fc5b9bae3ddfc31434c61ba01f109555a17730d0ff2429d5268e39c90eac91e9bb1cf40bc
7
+ data.tar.gz: c5f0a55469f8b2800ba5b380da353cee13e4e876174cb1e1c0959c192ae1281379074255fc095f64cfa3ef1fd2d7926a74b681523256e28e2b42c2019bffe498
data/CHANGELOG.md CHANGED
@@ -1,6 +1,158 @@
1
1
  Unreleased Changes
2
2
  ------------------
3
3
 
4
+ 3.199.0 (2024-06-25)
5
+ ------------------
6
+
7
+ * Feature - Support RpcV2 protocol.
8
+
9
+ * Feature - Add CBOR encoder and decoder.
10
+
11
+ * Issue - Enhance, refactor, and rebase protocols to be consistent. Ensure protocol tests are run for each engine.
12
+
13
+ 3.198.0 (2024-06-24)
14
+ ------------------
15
+
16
+ * Feature - Updated Aws::STS::Client with the latest API changes.
17
+
18
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
19
+
20
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
21
+
22
+ * Feature - Support `:plugins` option on all Clients or using `Aws.config[:plugins]`.
23
+
24
+ 3.197.2 (2024-06-20)
25
+ ------------------
26
+
27
+ * Issue - fix issue in Endpoint `attr` matcher when path is only an array index.
28
+
29
+ * Issue - Fix trailing slash in endpoint URLs for rest-json and rest-xml services.
30
+
31
+ 3.197.1 (2024-06-19)
32
+ ------------------
33
+
34
+ * Issue - Support an array of string arguments for `Aws::ProcessCredentials` to be executed by `system`.
35
+
36
+ 3.197.0 (2024-06-05)
37
+ ------------------
38
+
39
+ * Issue - Ensure no UTC offset when deserializing `iso8601` timestamp format values.
40
+
41
+ * Feature - Bump User Agent to version 2.1 to track business metrics. This changes the User Agent plugin order to be just before sending.
42
+
43
+ 3.196.1 (2024-05-14)
44
+ ------------------
45
+
46
+ * Issue - Fix `ConnectionPool` for `.empty!` and `.clear!` since it prevented adding a new key from being added to the pool (#3020).
47
+
48
+ 3.196.0 (2024-05-13)
49
+ ------------------
50
+
51
+ * Feature - Updated Aws::STS::Client with the latest API changes.
52
+
53
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
54
+
55
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
56
+
57
+ 3.195.0 (2024-05-10)
58
+ ------------------
59
+
60
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
61
+
62
+ * Feature - Updated request parameters for PKCE support.
63
+
64
+ 3.194.2 (2024-05-07)
65
+ ------------------
66
+
67
+ * Issue - Fix issue where `ConnectionPool` size iteration would prevent a new key from being added to the pool.
68
+
69
+ 3.194.1 (2024-05-03)
70
+ ------------------
71
+
72
+ * Issue - Update EC2 protocol to not serialize empty lists.
73
+
74
+ 3.194.0 (2024-04-30)
75
+ ------------------
76
+
77
+ * Feature - Add an API private cache for S3 Express and Access Grants.
78
+
79
+ 3.193.0 (2024-04-25)
80
+ ------------------
81
+
82
+ * Feature - Updated Aws::STS::Client with the latest API changes.
83
+
84
+ * Feature - Updated Aws::SSOOIDC::Client with the latest API changes.
85
+
86
+ * Feature - Updated Aws::SSO::Client with the latest API changes.
87
+
88
+ * Issue - Update event stream documentation.
89
+ * Issue - Move `InvocationId` plugin to all clients.
90
+ * Issue - Handle event streaming content-sha256 header in the signer plugin.
91
+ * Issue - Add the event stream content type to initial requests.
92
+ * Issue - Fix `standard` and `adaptive` retry mode for event streams.
93
+ * Issue - Add `authority` to http2 headers.
94
+ * Issue - Do not treat single members in event stream structures as implicit payloads.
95
+ * Issue - Do not wait for initial response headers to start sending input events.
96
+
97
+ 3.192.1 (2024-04-18)
98
+ ------------------
99
+
100
+ * Issue - Drop key/value pair if value is `nil` when deserializing json maps.
101
+
102
+ 3.192.0 (2024-04-16)
103
+ ------------------
104
+
105
+ * Feature - Updated Aws::STS::Client with the latest API changes.
106
+
107
+ * Feature - Update serializing/deserializing for all protocols to align with Smithy protocol-tests.
108
+ * Issue - Allow `nil` values in lists and maps.
109
+ * Issue - Populate headers for XML and JSON error responses.
110
+ * Issue - Support fractional seconds when parsing `DateTime` timestamps.
111
+ * Issue - Correctly serialize flattened lists for Query protocol.
112
+ * Issue - Correctly serialize payload name in Rest-XML requests.
113
+ * Issue - Fix an issue where Rest-XML requests do not have a default `Content-Type` header applied.
114
+ * Issue - Apply appropriate `Content-Type` header for payloads in Rest services.
115
+ * Issue - Correctly serialize URI label bindings in Rest requests.
116
+ * Issue - Correctly serialize and parse header bindings in Rest services.
117
+ * Issue - Ensure that null and empty headers are not sent in Rest requests.
118
+ * Issue - Ensure keys in query maps do not override modeled keys in Rest requests.
119
+ * Issue - Ensure empty blob payloads are omitted in Rest requests.
120
+ * Issue - Support parsing of `NaN`, `Infinity` and `-Infinity` float values.
121
+ * Issue - Apply appropriate `xmlName` for flattened lists and maps in Rest-XML services.
122
+ * Issue - Handle serializing of different formats of `xmlNamespace` on shapes.
123
+ * Issue - Fix deserializing of an empty blob to produce an empty string.
124
+ * Issue - Fix deserializing an empty self-closed blob to produce an empty string.
125
+ * Issue - Support parsing of different formats of error data in Rest-XML services.
126
+
127
+ 3.191.6 (2024-04-02)
128
+ ------------------
129
+ * Issue - Performance optimization: ensure presence and order of instance variables in `PluginOptions` (#3002).
130
+
131
+ 3.191.5 (2024-03-26)
132
+ ------------------
133
+
134
+ * Issue - Fix `EC2Metadata` and `InstanceProfileCredentials` to respect the port from a configured endpoint from code, ENV, or shared config.
135
+
136
+ 3.191.4 (2024-03-15)
137
+ ------------------
138
+
139
+ * Issue - Ensure output unions work correctly with stub_responses.
140
+
141
+ 3.191.3 (2024-02-20)
142
+ ------------------
143
+
144
+ * Issue - Remove base64 as dependency.
145
+
146
+ 3.191.2 (2024-02-14)
147
+ ------------------
148
+
149
+ * Issue - Add base64 as dependency to prepare for Ruby 3.4 release (#2984).
150
+
151
+ 3.191.1 (2024-02-07)
152
+ ------------------
153
+
154
+ * Issue - Warn on previously silent credential failures (#2981).
155
+
4
156
  3.191.0 (2024-01-26)
5
157
  ------------------
6
158
 
@@ -10,7 +162,7 @@ Unreleased Changes
10
162
 
11
163
  * Feature - Updated Aws::SSO::Client with the latest API changes.
12
164
 
13
- * Feature - Add RBS signature files to support static type checking.
165
+ * Feature - Add RBS signature files to support static type checking
14
166
 
15
167
  3.190.3 (2024-01-16)
16
168
  ------------------
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.191.0
1
+ 3.199.0
@@ -22,22 +22,16 @@ module Aws
22
22
  end
23
23
 
24
24
  def attach_eventstream_listeners(context, rules)
25
-
26
25
  context.http_response.on_headers(200) do
27
- protocol = context.config.api.metadata['protocol']
28
- output_handler = context[:output_event_stream_handler] || context[:event_stream_handler]
26
+ output_handler = context[:output_event_stream_handler] ||
27
+ context[:event_stream_handler]
29
28
  context.http_response.body = EventStreamDecoder.new(
30
- protocol,
29
+ context.config.protocol,
31
30
  rules,
32
31
  context.operation.output,
33
32
  context.operation.errors,
34
33
  context.http_response.body,
35
34
  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
35
  end
42
36
 
43
37
  context.http_response.on_success(200) do
@@ -10,7 +10,7 @@ module Aws
10
10
  if eventstream_member = eventstream_input?(context)
11
11
  input_es_handler = context[:input_event_stream_handler]
12
12
  input_es_handler.event_emitter.encoder = EventStreamEncoder.new(
13
- context.config.api.metadata['protocol'],
13
+ context.config.protocol,
14
14
  eventstream_member,
15
15
  context.operation.input,
16
16
  signer_for(context)
@@ -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
@@ -47,6 +47,7 @@ module Aws
47
47
  when 'rest-xml' then Aws::Xml::Parser
48
48
  when 'rest-json' then Aws::Json::Parser
49
49
  when 'json' then Aws::Json::Parser
50
+ when 'smithy-rpc-v2-cbor' then Aws::RpcV2::Parser
50
51
  else raise "unsupported protocol #{protocol} for event stream"
51
52
  end
52
53
  end
@@ -43,9 +43,10 @@ module Aws
43
43
 
44
44
  def serializer_class(protocol)
45
45
  case protocol
46
- when 'rest-xml' then Xml::Builder
47
- when 'rest-json' then Json::Builder
48
- when 'json' then Json::Builder
46
+ when 'rest-xml' then Aws::Xml::Builder
47
+ when 'rest-json' then Aws::Json::Builder
48
+ when 'json' then Aws::Json::Builder
49
+ when 'smithy-rpc-v2-cbor' then Aws::RpcV2::Builder
49
50
  else raise "unsupported protocol #{protocol} for event stream"
50
51
  end
51
52
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'encoder'
4
+ require_relative 'decoder'
5
+
6
+ module Aws
7
+ module Cbor
8
+ # Pure Ruby implementation of CBOR encode and decode
9
+ module CborEngine
10
+ def self.encode(data)
11
+ Encoder.new.add(data).bytes
12
+ end
13
+
14
+ def self.decode(bytes)
15
+ Decoder.new(bytes.force_encoding(Encoding::BINARY)).decode
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,310 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aws
4
+ module Cbor
5
+ # Pure Ruby implementation of CBOR Decoder
6
+ class Decoder
7
+ def initialize(bytes)
8
+ @buffer = bytes
9
+ @pos = 0
10
+ end
11
+
12
+ def decode
13
+ return nil if @buffer.nil? || @buffer.empty?
14
+
15
+ val = decode_item
16
+ return val unless @pos != @buffer.size
17
+
18
+ raise ExtraBytesError.new(@pos, @buffer.size)
19
+ end
20
+
21
+ private
22
+
23
+ FIVE_BIT_MASK = 0x1F
24
+ TAG_TYPE_EPOCH = 1
25
+ TAG_TYPE_BIGNUM = 2
26
+ TAG_TYPE_NEG_BIGNUM = 3
27
+ TAG_TYPE_BIGDEC = 4
28
+
29
+ # high level, generic decode. Based on the next type. Consumes and returns
30
+ # the next item as a ruby object.
31
+ def decode_item
32
+ case (next_type = peek_type)
33
+ when :array
34
+ read_array.times.map { decode_item }
35
+ when :map
36
+ read_map.times.map { [read_string, decode_item] }.to_h
37
+ when :indefinite_array
38
+ read_start_indefinite_array
39
+ value = []
40
+ value << decode_item until peek_type == :break_stop_code
41
+ read_end_indefinite_collection
42
+ value
43
+ when :indefinite_map
44
+ read_start_indefinite_map
45
+ value = {}
46
+ value[read_string] = decode_item until peek_type == :break_stop_code
47
+ read_end_indefinite_collection
48
+ value
49
+ when :indefinite_binary_string
50
+ read_info
51
+ value = String.new
52
+ value << read_binary_string until peek_type == :break_stop_code
53
+ read_end_indefinite_collection
54
+ value
55
+ when :indefinite_string
56
+ read_info
57
+ value = String.new
58
+ value << read_string until peek_type == :break_stop_code
59
+ read_end_indefinite_collection
60
+ value.force_encoding(Encoding::UTF_8)
61
+ when :tag
62
+ case (tag = read_tag)
63
+ when TAG_TYPE_EPOCH
64
+ type = peek_type
65
+ item = decode_item
66
+ item /= 1000.0 if type == :integer
67
+ Time.at(item)
68
+ when TAG_TYPE_BIGNUM, TAG_TYPE_NEG_BIGNUM
69
+ read_bignum(tag)
70
+ when TAG_TYPE_BIGDEC
71
+ read_big_decimal
72
+ else
73
+ Tagged.new(tag, decode_item)
74
+ end
75
+ when :break_stop_code
76
+ raise UnexpectedBreakCodeError
77
+ else
78
+ send("read_#{next_type}")
79
+ end
80
+ end
81
+
82
+ # low level streaming interface
83
+ def peek_type
84
+ ib = peek(1).ord
85
+ add_info = ib & FIVE_BIT_MASK
86
+ major_type = ib >> 5
87
+ case major_type
88
+ when 0, 1 then :integer
89
+ when 2
90
+ add_info == 31 ? :indefinite_binary_string : :binary_string
91
+ when 3
92
+ add_info == 31 ? :indefinite_string : :string
93
+ when 4
94
+ add_info == 31 ? :indefinite_array : :array
95
+ when 5
96
+ add_info == 31 ? :indefinite_map : :map
97
+ when 6 then :tag
98
+ when 7 # simple or float
99
+ case add_info
100
+ when 20, 21 then :boolean
101
+ when 22 then :nil
102
+ when 23 then :undefined # for smithy, this should be parsed as nil
103
+ when 25 then :half
104
+ when 26 then :float
105
+ when 27 then :double
106
+ when 31 then :break_stop_code
107
+ else
108
+ :reserved_undefined
109
+ end
110
+ end
111
+ end
112
+
113
+ def read_break_stop_code
114
+ read_info
115
+ :break_stop_code
116
+ end
117
+
118
+ def read_integer
119
+ major_type, add_info = read_info
120
+
121
+ val = read_count(add_info)
122
+ case major_type
123
+ when 0 then val
124
+ when 1 then -1 - val
125
+ else
126
+ raise Error,
127
+ "Expected Integer (0,1) got major type: #{major_type}"
128
+ end
129
+ end
130
+
131
+ def read_binary_string
132
+ _major_type, add_info = read_info
133
+ take(read_count(add_info)).force_encoding(Encoding::BINARY)
134
+ end
135
+
136
+ def read_string
137
+ _major_type, add_info = read_info
138
+ take(read_count(add_info)).force_encoding(Encoding::UTF_8)
139
+ end
140
+
141
+ # returns only the length of the array, caller must read the correct number of values after this
142
+ def read_array
143
+ _major_type, add_info = read_info
144
+ read_count(add_info)
145
+ end
146
+
147
+ # returns nothing but consumes and checks the type/info.
148
+ # Caller must keep reading until encountering the stop sequence
149
+ def read_start_indefinite_array
150
+ read_info
151
+ end
152
+
153
+ # returns nothing but consumes and checks the type/info.
154
+ # Caller must keep reading until encountering the stop sequence
155
+ def read_start_indefinite_map
156
+ read_info
157
+ end
158
+
159
+ # returns nothing but consumes and checks the type/info.
160
+ def read_end_indefinite_collection
161
+ read_info
162
+ end
163
+
164
+ # returns only the length of the array, caller must read the correct number of key value pairs after this
165
+ def read_map
166
+ _major_type, add_info = read_info
167
+ read_count(add_info)
168
+ end
169
+
170
+ # returns only the tag, caller must interpret the tag and read another value as appropriate
171
+ def read_tag
172
+ _major_type, add_info = read_info
173
+ read_count(add_info)
174
+ end
175
+
176
+ def read_reserved_undefined
177
+ _major_type, add_info = read_info
178
+ raise Error,
179
+ "Undefined reserved additional information: #{add_info}"
180
+ end
181
+
182
+ def read_boolean
183
+ _major_type, add_info = read_info
184
+ case add_info
185
+ when 20 then false
186
+ when 21 then true
187
+ else
188
+ raise Error,
189
+ 'Invalid Boolean simple type, expected add_info of 20 or 21, ' \
190
+ "got: #{add_info}"
191
+ end
192
+ end
193
+
194
+ def read_nil
195
+ read_info
196
+ nil
197
+ end
198
+
199
+ def read_undefined
200
+ read_info
201
+ :undefined
202
+ end
203
+
204
+ # 16 bit IEEE 754 half-precision floats
205
+ # Support decoding only
206
+ # format:
207
+ # sign - 1 bit
208
+ # exponent - 5 bits
209
+ # precision - 10 bits
210
+ def read_half
211
+ read_info
212
+ b16 = take(2).unpack1('n')
213
+ exp = (b16 >> 10) & 0x1f
214
+ mant = b16 & 0x3ff
215
+ val =
216
+ case exp
217
+ when 0
218
+ Math.ldexp(mant, -24)
219
+ when 31
220
+ mant.zero? ? Float::INFINITY : Float::NAN
221
+ else
222
+ # exp bias is 15, but to use ldexp we divide by 1024 (2^10) to get
223
+ # exp-15-10
224
+ Math.ldexp(1024 + mant, exp - 25)
225
+ end
226
+ if (b16[15]).zero?
227
+ val
228
+ else
229
+ -val
230
+ end
231
+ end
232
+
233
+ def read_float
234
+ read_info
235
+ take(4).unpack1('g')
236
+ end
237
+
238
+ def read_double
239
+ read_info
240
+ take(8).unpack1('G')
241
+ end
242
+
243
+ # tag type 2 or 3
244
+ def read_bignum(tag_value)
245
+ _major_type, add_info = read_info
246
+ bstr = take(read_count(add_info))
247
+ v = bstr.bytes.inject(0) do |sum, b|
248
+ sum <<= 8
249
+ sum + b
250
+ end
251
+ case tag_value
252
+ when 2 then v
253
+ when 3 then -1 - v
254
+ else
255
+ raise Error,
256
+ 'Invalid Tag value for BigNum, ' \
257
+ "expected 2 or 3, got: #{tag_value}"
258
+ end
259
+ end
260
+
261
+ # A decimal fraction or a bigfloat is represented as a tagged array
262
+ # that contains exactly two integer numbers:
263
+ # an exponent e and a mantissa m
264
+ # See: https://www.rfc-editor.org/rfc/rfc8949.html#name-decimal-fractions-and-bigfl
265
+ def read_big_decimal
266
+ unless (s = read_array) == 2
267
+ raise Error, "Expected array of length 2 but length is: #{s}"
268
+ end
269
+
270
+ e = read_integer
271
+ m = read_integer
272
+ BigDecimal(m) * (BigDecimal(10)**BigDecimal(e))
273
+ end
274
+
275
+ # return a tuple of major_type, add_info
276
+ def read_info
277
+ ib = take(1).ord
278
+ [ib >> 5, ib & FIVE_BIT_MASK]
279
+ end
280
+
281
+ def read_count(add_info)
282
+ case add_info
283
+ when 0..23 then add_info
284
+ when 24 then take(1).ord
285
+ when 25 then take(2).unpack1('n')
286
+ when 26 then take(4).unpack1('N')
287
+ when 27 then take(8).unpack1('Q>')
288
+ when 28 then take(16).unpack1('Q>')
289
+ when 29 then take(32).unpack1('Q>')
290
+ else raise UnexpectedAdditionalInformationError, add_info
291
+ end
292
+ end
293
+
294
+ def take(n_bytes)
295
+ opos = @pos
296
+ @pos += n_bytes
297
+
298
+ return @buffer[opos, n_bytes] if @pos <= @buffer.bytesize
299
+
300
+ raise OutOfBytesError.new(n_bytes, @buffer.bytesize - @pos)
301
+ end
302
+
303
+ def peek(n_bytes)
304
+ return @buffer[@pos, n_bytes] if (@pos + n_bytes) <= @buffer.bytesize
305
+
306
+ raise OutOfBytesError.new(n_bytes, @buffer.bytesize - @pos)
307
+ end
308
+ end
309
+ end
310
+ end