aws-sdk-core 3.191.1 → 3.228.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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +530 -1
  3. data/VERSION +1 -1
  4. data/lib/aws-defaults/default_configuration.rb +1 -2
  5. data/lib/aws-defaults.rb +4 -1
  6. data/lib/aws-sdk-core/arn.rb +1 -3
  7. data/lib/aws-sdk-core/assume_role_credentials.rb +13 -5
  8. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +14 -7
  9. data/lib/aws-sdk-core/binary/decode_handler.rb +3 -9
  10. data/lib/aws-sdk-core/binary/encode_handler.rb +1 -1
  11. data/lib/aws-sdk-core/binary/event_builder.rb +34 -37
  12. data/lib/aws-sdk-core/binary/event_stream_decoder.rb +1 -0
  13. data/lib/aws-sdk-core/binary/event_stream_encoder.rb +4 -3
  14. data/lib/aws-sdk-core/cbor/decoder.rb +308 -0
  15. data/lib/aws-sdk-core/cbor/encoder.rb +243 -0
  16. data/lib/aws-sdk-core/cbor.rb +53 -0
  17. data/lib/aws-sdk-core/client_side_monitoring.rb +9 -0
  18. data/lib/aws-sdk-core/client_stubs.rb +30 -55
  19. data/lib/aws-sdk-core/credential_provider.rb +4 -0
  20. data/lib/aws-sdk-core/credential_provider_chain.rb +38 -11
  21. data/lib/aws-sdk-core/credentials.rb +19 -6
  22. data/lib/aws-sdk-core/ec2_metadata.rb +1 -1
  23. data/lib/aws-sdk-core/ecs_credentials.rb +1 -0
  24. data/lib/aws-sdk-core/endpoints/endpoint.rb +3 -1
  25. data/lib/aws-sdk-core/endpoints/matchers.rb +8 -10
  26. data/lib/aws-sdk-core/endpoints.rb +101 -21
  27. data/lib/aws-sdk-core/error_handler.rb +46 -0
  28. data/lib/aws-sdk-core/errors.rb +11 -2
  29. data/lib/aws-sdk-core/event_emitter.rb +1 -17
  30. data/lib/aws-sdk-core/instance_profile_credentials.rb +148 -158
  31. data/lib/aws-sdk-core/json/builder.rb +8 -1
  32. data/lib/aws-sdk-core/json/error_handler.rb +29 -13
  33. data/lib/aws-sdk-core/json/handler.rb +6 -6
  34. data/lib/aws-sdk-core/json/json_engine.rb +3 -1
  35. data/lib/aws-sdk-core/json/oj_engine.rb +7 -1
  36. data/lib/aws-sdk-core/json/parser.rb +6 -1
  37. data/lib/aws-sdk-core/json.rb +43 -14
  38. data/lib/aws-sdk-core/log/param_filter.rb +2 -2
  39. data/lib/aws-sdk-core/log/param_formatter.rb +7 -3
  40. data/lib/aws-sdk-core/log.rb +10 -0
  41. data/lib/aws-sdk-core/lru_cache.rb +75 -0
  42. data/lib/aws-sdk-core/pageable_response.rb +1 -1
  43. data/lib/aws-sdk-core/param_validator.rb +7 -2
  44. data/lib/aws-sdk-core/plugins/bearer_authorization.rb +2 -0
  45. data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +332 -169
  46. data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +0 -1
  47. data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +14 -2
  48. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +87 -68
  49. data/lib/aws-sdk-core/plugins/endpoint_pattern.rb +40 -32
  50. data/lib/aws-sdk-core/plugins/global_configuration.rb +8 -9
  51. data/lib/aws-sdk-core/plugins/http_checksum.rb +2 -8
  52. data/lib/aws-sdk-core/plugins/invocation_id.rb +1 -11
  53. data/lib/aws-sdk-core/plugins/protocols/api_gateway.rb +3 -1
  54. data/lib/aws-sdk-core/plugins/protocols/ec2.rb +2 -24
  55. data/lib/aws-sdk-core/plugins/protocols/json_rpc.rb +6 -8
  56. data/lib/aws-sdk-core/plugins/protocols/query.rb +4 -2
  57. data/lib/aws-sdk-core/plugins/protocols/rest_json.rb +3 -15
  58. data/lib/aws-sdk-core/plugins/protocols/rest_xml.rb +3 -0
  59. data/lib/aws-sdk-core/plugins/protocols/rpc_v2.rb +17 -0
  60. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +74 -25
  61. data/lib/aws-sdk-core/plugins/request_compression.rb +11 -2
  62. data/lib/aws-sdk-core/plugins/retry_errors.rb +10 -3
  63. data/lib/aws-sdk-core/plugins/sign.rb +42 -26
  64. data/lib/aws-sdk-core/plugins/signature_v2.rb +2 -1
  65. data/lib/aws-sdk-core/plugins/signature_v4.rb +2 -1
  66. data/lib/aws-sdk-core/plugins/stub_responses.rb +58 -9
  67. data/lib/aws-sdk-core/plugins/telemetry.rb +75 -0
  68. data/lib/aws-sdk-core/plugins/transfer_encoding.rb +16 -9
  69. data/lib/aws-sdk-core/plugins/user_agent.rb +101 -26
  70. data/lib/aws-sdk-core/plugins.rb +39 -0
  71. data/lib/aws-sdk-core/process_credentials.rb +48 -29
  72. data/lib/aws-sdk-core/query/ec2_handler.rb +27 -0
  73. data/lib/aws-sdk-core/query/ec2_param_builder.rb +5 -7
  74. data/lib/aws-sdk-core/query/handler.rb +4 -4
  75. data/lib/aws-sdk-core/query/param_builder.rb +2 -2
  76. data/lib/aws-sdk-core/query.rb +2 -1
  77. data/lib/aws-sdk-core/resources.rb +8 -0
  78. data/lib/aws-sdk-core/rest/content_type_handler.rb +60 -0
  79. data/lib/aws-sdk-core/rest/handler.rb +3 -4
  80. data/lib/aws-sdk-core/rest/request/body.rb +32 -5
  81. data/lib/aws-sdk-core/rest/request/endpoint.rb +24 -4
  82. data/lib/aws-sdk-core/rest/request/headers.rb +15 -7
  83. data/lib/aws-sdk-core/rest/request/querystring_builder.rb +23 -11
  84. data/lib/aws-sdk-core/rest/response/body.rb +15 -1
  85. data/lib/aws-sdk-core/rest/response/header_list_parser.rb +79 -0
  86. data/lib/aws-sdk-core/rest/response/headers.rb +8 -3
  87. data/lib/aws-sdk-core/rest.rb +1 -0
  88. data/lib/aws-sdk-core/rpc_v2/builder.rb +62 -0
  89. data/lib/aws-sdk-core/rpc_v2/cbor_engine.rb +18 -0
  90. data/lib/aws-sdk-core/rpc_v2/content_type_handler.rb +47 -0
  91. data/lib/aws-sdk-core/rpc_v2/error_handler.rb +95 -0
  92. data/lib/aws-sdk-core/rpc_v2/handler.rb +79 -0
  93. data/lib/aws-sdk-core/rpc_v2/parser.rb +98 -0
  94. data/lib/aws-sdk-core/rpc_v2.rb +69 -0
  95. data/lib/aws-sdk-core/shared_config.rb +79 -22
  96. data/lib/aws-sdk-core/shared_credentials.rb +1 -7
  97. data/lib/aws-sdk-core/sso_credentials.rb +4 -1
  98. data/lib/aws-sdk-core/static_token_provider.rb +1 -2
  99. data/lib/aws-sdk-core/stubbing/protocols/ec2.rb +12 -11
  100. data/lib/aws-sdk-core/stubbing/protocols/json.rb +11 -10
  101. data/lib/aws-sdk-core/stubbing/protocols/query.rb +7 -6
  102. data/lib/aws-sdk-core/stubbing/protocols/rest.rb +2 -1
  103. data/lib/aws-sdk-core/stubbing/protocols/rest_json.rb +9 -8
  104. data/lib/aws-sdk-core/stubbing/protocols/rest_xml.rb +6 -5
  105. data/lib/aws-sdk-core/stubbing/protocols/rpc_v2.rb +39 -0
  106. data/lib/aws-sdk-core/stubbing.rb +22 -0
  107. data/lib/aws-sdk-core/telemetry/base.rb +177 -0
  108. data/lib/aws-sdk-core/telemetry/no_op.rb +70 -0
  109. data/lib/aws-sdk-core/telemetry/otel.rb +235 -0
  110. data/lib/aws-sdk-core/telemetry/span_kind.rb +22 -0
  111. data/lib/aws-sdk-core/telemetry/span_status.rb +59 -0
  112. data/lib/aws-sdk-core/telemetry.rb +78 -0
  113. data/lib/aws-sdk-core/token.rb +3 -3
  114. data/lib/aws-sdk-core/token_provider.rb +4 -0
  115. data/lib/aws-sdk-core/token_provider_chain.rb +2 -6
  116. data/lib/aws-sdk-core/util.rb +41 -1
  117. data/lib/aws-sdk-core/waiters/poller.rb +10 -5
  118. data/lib/aws-sdk-core/xml/builder.rb +17 -9
  119. data/lib/aws-sdk-core/xml/error_handler.rb +35 -43
  120. data/lib/aws-sdk-core/xml/parser/frame.rb +4 -20
  121. data/lib/aws-sdk-core/xml/parser/stack.rb +2 -0
  122. data/lib/aws-sdk-core/xml/parser.rb +2 -6
  123. data/lib/aws-sdk-core.rb +82 -107
  124. data/lib/aws-sdk-sso/client.rb +185 -89
  125. data/lib/aws-sdk-sso/client_api.rb +7 -0
  126. data/lib/aws-sdk-sso/endpoint_parameters.rb +9 -6
  127. data/lib/aws-sdk-sso/endpoint_provider.rb +14 -18
  128. data/lib/aws-sdk-sso/endpoints.rb +2 -54
  129. data/lib/aws-sdk-sso/plugins/endpoints.rb +19 -20
  130. data/lib/aws-sdk-sso/types.rb +1 -0
  131. data/lib/aws-sdk-sso.rb +15 -11
  132. data/lib/aws-sdk-ssooidc/client.rb +270 -109
  133. data/lib/aws-sdk-ssooidc/client_api.rb +33 -0
  134. data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +9 -6
  135. data/lib/aws-sdk-ssooidc/endpoint_provider.rb +14 -18
  136. data/lib/aws-sdk-ssooidc/endpoints.rb +2 -54
  137. data/lib/aws-sdk-ssooidc/errors.rb +21 -0
  138. data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +19 -20
  139. data/lib/aws-sdk-ssooidc/types.rb +125 -24
  140. data/lib/aws-sdk-ssooidc.rb +15 -11
  141. data/lib/aws-sdk-sts/client.rb +393 -141
  142. data/lib/aws-sdk-sts/client_api.rb +36 -8
  143. data/lib/aws-sdk-sts/customizations.rb +5 -1
  144. data/lib/aws-sdk-sts/endpoint_parameters.rb +10 -9
  145. data/lib/aws-sdk-sts/endpoint_provider.rb +50 -55
  146. data/lib/aws-sdk-sts/endpoints.rb +2 -118
  147. data/lib/aws-sdk-sts/errors.rb +15 -0
  148. data/lib/aws-sdk-sts/plugins/endpoints.rb +19 -28
  149. data/lib/aws-sdk-sts/presigner.rb +2 -6
  150. data/lib/aws-sdk-sts/types.rb +171 -28
  151. data/lib/aws-sdk-sts.rb +15 -11
  152. data/lib/seahorse/client/async_base.rb +4 -5
  153. data/lib/seahorse/client/async_response.rb +19 -0
  154. data/lib/seahorse/client/base.rb +18 -21
  155. data/lib/seahorse/client/h2/connection.rb +18 -28
  156. data/lib/seahorse/client/h2/handler.rb +14 -3
  157. data/lib/seahorse/client/handler.rb +1 -1
  158. data/lib/seahorse/client/http/response.rb +1 -1
  159. data/lib/seahorse/client/net_http/connection_pool.rb +15 -12
  160. data/lib/seahorse/client/net_http/handler.rb +21 -9
  161. data/lib/seahorse/client/networking_error.rb +1 -1
  162. data/lib/seahorse/client/plugin.rb +8 -0
  163. data/lib/seahorse/client/plugins/endpoint.rb +0 -1
  164. data/lib/seahorse/client/plugins/h2.rb +4 -4
  165. data/lib/seahorse/client/plugins/net_http.rb +57 -16
  166. data/lib/seahorse/client/request_context.rb +9 -2
  167. data/lib/seahorse/client/response.rb +2 -0
  168. data/lib/seahorse/model/shapes.rb +2 -2
  169. data/lib/seahorse/util.rb +2 -1
  170. data/sig/aws-sdk-core/async_client_stubs.rbs +21 -0
  171. data/sig/aws-sdk-core/telemetry/base.rbs +46 -0
  172. data/sig/aws-sdk-core/telemetry/otel.rbs +22 -0
  173. data/sig/aws-sdk-core/telemetry/span_kind.rbs +15 -0
  174. data/sig/aws-sdk-core/telemetry/span_status.rbs +24 -0
  175. data/sig/seahorse/client/async_base.rbs +18 -0
  176. metadata +96 -23
  177. /data/lib/aws-sdk-core/xml/parser/{engines/libxml.rb → libxml_engine.rb} +0 -0
  178. /data/lib/aws-sdk-core/xml/parser/{engines/nokogiri.rb → nokogiri_engine.rb} +0 -0
  179. /data/lib/aws-sdk-core/xml/parser/{engines/oga.rb → oga_engine.rb} +0 -0
  180. /data/lib/aws-sdk-core/xml/parser/{engines/ox.rb → ox_engine.rb} +0 -0
  181. /data/lib/aws-sdk-core/xml/parser/{engines/rexml.rb → rexml_engine.rb} +0 -0
@@ -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,308 @@
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
+ item = decode_item
65
+ Time.at(item)
66
+ when TAG_TYPE_BIGNUM, TAG_TYPE_NEG_BIGNUM
67
+ read_bignum(tag)
68
+ when TAG_TYPE_BIGDEC
69
+ read_big_decimal
70
+ else
71
+ Tagged.new(tag, decode_item)
72
+ end
73
+ when :break_stop_code
74
+ raise UnexpectedBreakCodeError
75
+ else
76
+ send("read_#{next_type}")
77
+ end
78
+ end
79
+
80
+ # low level streaming interface
81
+ def peek_type
82
+ ib = peek(1).ord
83
+ add_info = ib & FIVE_BIT_MASK
84
+ major_type = ib >> 5
85
+ case major_type
86
+ when 0, 1 then :integer
87
+ when 2
88
+ add_info == 31 ? :indefinite_binary_string : :binary_string
89
+ when 3
90
+ add_info == 31 ? :indefinite_string : :string
91
+ when 4
92
+ add_info == 31 ? :indefinite_array : :array
93
+ when 5
94
+ add_info == 31 ? :indefinite_map : :map
95
+ when 6 then :tag
96
+ when 7 # simple or float
97
+ case add_info
98
+ when 20, 21 then :boolean
99
+ when 22 then :nil
100
+ when 23 then :undefined # for smithy, this should be parsed as nil
101
+ when 25 then :half
102
+ when 26 then :float
103
+ when 27 then :double
104
+ when 31 then :break_stop_code
105
+ else
106
+ :reserved_undefined
107
+ end
108
+ end
109
+ end
110
+
111
+ def read_break_stop_code
112
+ read_info
113
+ :break_stop_code
114
+ end
115
+
116
+ def read_integer
117
+ major_type, add_info = read_info
118
+
119
+ val = read_count(add_info)
120
+ case major_type
121
+ when 0 then val
122
+ when 1 then -1 - val
123
+ else
124
+ raise Error,
125
+ "Expected Integer (0,1) got major type: #{major_type}"
126
+ end
127
+ end
128
+
129
+ def read_binary_string
130
+ _major_type, add_info = read_info
131
+ take(read_count(add_info)).force_encoding(Encoding::BINARY)
132
+ end
133
+
134
+ def read_string
135
+ _major_type, add_info = read_info
136
+ take(read_count(add_info)).force_encoding(Encoding::UTF_8)
137
+ end
138
+
139
+ # returns only the length of the array, caller must read the correct number of values after this
140
+ def read_array
141
+ _major_type, add_info = read_info
142
+ read_count(add_info)
143
+ end
144
+
145
+ # returns nothing but consumes and checks the type/info.
146
+ # Caller must keep reading until encountering the stop sequence
147
+ def read_start_indefinite_array
148
+ read_info
149
+ end
150
+
151
+ # returns nothing but consumes and checks the type/info.
152
+ # Caller must keep reading until encountering the stop sequence
153
+ def read_start_indefinite_map
154
+ read_info
155
+ end
156
+
157
+ # returns nothing but consumes and checks the type/info.
158
+ def read_end_indefinite_collection
159
+ read_info
160
+ end
161
+
162
+ # returns only the length of the array, caller must read the correct number of key value pairs after this
163
+ def read_map
164
+ _major_type, add_info = read_info
165
+ read_count(add_info)
166
+ end
167
+
168
+ # returns only the tag, caller must interpret the tag and read another value as appropriate
169
+ def read_tag
170
+ _major_type, add_info = read_info
171
+ read_count(add_info)
172
+ end
173
+
174
+ def read_reserved_undefined
175
+ _major_type, add_info = read_info
176
+ raise Error,
177
+ "Undefined reserved additional information: #{add_info}"
178
+ end
179
+
180
+ def read_boolean
181
+ _major_type, add_info = read_info
182
+ case add_info
183
+ when 20 then false
184
+ when 21 then true
185
+ else
186
+ raise Error,
187
+ 'Invalid Boolean simple type, expected add_info of 20 or 21, ' \
188
+ "got: #{add_info}"
189
+ end
190
+ end
191
+
192
+ def read_nil
193
+ read_info
194
+ nil
195
+ end
196
+
197
+ def read_undefined
198
+ read_info
199
+ :undefined
200
+ end
201
+
202
+ # 16 bit IEEE 754 half-precision floats
203
+ # Support decoding only
204
+ # format:
205
+ # sign - 1 bit
206
+ # exponent - 5 bits
207
+ # precision - 10 bits
208
+ def read_half
209
+ read_info
210
+ b16 = take(2).unpack1('n')
211
+ exp = (b16 >> 10) & 0x1f
212
+ mant = b16 & 0x3ff
213
+ val =
214
+ case exp
215
+ when 0
216
+ Math.ldexp(mant, -24)
217
+ when 31
218
+ mant.zero? ? Float::INFINITY : Float::NAN
219
+ else
220
+ # exp bias is 15, but to use ldexp we divide by 1024 (2^10) to get
221
+ # exp-15-10
222
+ Math.ldexp(1024 + mant, exp - 25)
223
+ end
224
+ if (b16[15]).zero?
225
+ val
226
+ else
227
+ -val
228
+ end
229
+ end
230
+
231
+ def read_float
232
+ read_info
233
+ take(4).unpack1('g')
234
+ end
235
+
236
+ def read_double
237
+ read_info
238
+ take(8).unpack1('G')
239
+ end
240
+
241
+ # tag type 2 or 3
242
+ def read_bignum(tag_value)
243
+ _major_type, add_info = read_info
244
+ bstr = take(read_count(add_info))
245
+ v = bstr.bytes.inject(0) do |sum, b|
246
+ sum <<= 8
247
+ sum + b
248
+ end
249
+ case tag_value
250
+ when 2 then v
251
+ when 3 then -1 - v
252
+ else
253
+ raise Error,
254
+ 'Invalid Tag value for BigNum, ' \
255
+ "expected 2 or 3, got: #{tag_value}"
256
+ end
257
+ end
258
+
259
+ # A decimal fraction or a bigfloat is represented as a tagged array
260
+ # that contains exactly two integer numbers:
261
+ # an exponent e and a mantissa m
262
+ # See: https://www.rfc-editor.org/rfc/rfc8949.html#name-decimal-fractions-and-bigfl
263
+ def read_big_decimal
264
+ unless (s = read_array) == 2
265
+ raise Error, "Expected array of length 2 but length is: #{s}"
266
+ end
267
+
268
+ e = read_integer
269
+ m = read_integer
270
+ BigDecimal(m) * (BigDecimal(10)**BigDecimal(e))
271
+ end
272
+
273
+ # return a tuple of major_type, add_info
274
+ def read_info
275
+ ib = take(1).ord
276
+ [ib >> 5, ib & FIVE_BIT_MASK]
277
+ end
278
+
279
+ def read_count(add_info)
280
+ case add_info
281
+ when 0..23 then add_info
282
+ when 24 then take(1).ord
283
+ when 25 then take(2).unpack1('n')
284
+ when 26 then take(4).unpack1('N')
285
+ when 27 then take(8).unpack1('Q>')
286
+ when 28 then take(16).unpack1('Q>')
287
+ when 29 then take(32).unpack1('Q>')
288
+ else raise UnexpectedAdditionalInformationError, add_info
289
+ end
290
+ end
291
+
292
+ def take(n_bytes)
293
+ opos = @pos
294
+ @pos += n_bytes
295
+
296
+ return @buffer[opos, n_bytes] if @pos <= @buffer.bytesize
297
+
298
+ raise OutOfBytesError.new(n_bytes, @buffer.bytesize - @pos)
299
+ end
300
+
301
+ def peek(n_bytes)
302
+ return @buffer[@pos, n_bytes] if (@pos + n_bytes) <= @buffer.bytesize
303
+
304
+ raise OutOfBytesError.new(n_bytes, @buffer.bytesize - @pos)
305
+ end
306
+ end
307
+ end
308
+ end
@@ -0,0 +1,243 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bigdecimal'
4
+
5
+ module Aws
6
+ module Cbor
7
+ # Pure ruby implementation of CBOR encoder.
8
+ class Encoder
9
+ def initialize
10
+ @buffer = String.new
11
+ end
12
+
13
+ # @return the encoded bytes in CBOR format for all added data
14
+ def bytes
15
+ @buffer
16
+ end
17
+
18
+ # generic method for adding generic Ruby data based on its type
19
+ def add(value)
20
+ case value
21
+ when BigDecimal then add_big_decimal(value)
22
+ when Integer then add_auto_integer(value)
23
+ when Numeric then add_auto_float(value)
24
+ when Symbol then add_string(value.to_s)
25
+ when true, false then add_boolean(value)
26
+ when nil then add_nil
27
+ when Tagged
28
+ add_tag(value.tag)
29
+ add(value.value)
30
+ when String
31
+ if value.encoding == Encoding::BINARY
32
+ add_byte_string(value)
33
+ else
34
+ add_string(value)
35
+ end
36
+ when Array
37
+ start_array(value.size)
38
+ value.each { |di| add(di) }
39
+ when Hash
40
+ start_map(value.size)
41
+ value.each do |k, v|
42
+ add(k)
43
+ add(v)
44
+ end
45
+ when Time
46
+ add_time(value)
47
+ else
48
+ raise UnknownTypeError, value
49
+ end
50
+ self
51
+ end
52
+
53
+ private
54
+
55
+ MAJOR_TYPE_UNSIGNED_INT = 0x00 # 000_00000 - Major Type 0 - unsigned int
56
+ MAJOR_TYPE_NEGATIVE_INT = 0x20 # 001_00000 - Major Type 1 - negative int
57
+ MAJOR_TYPE_BYTE_STR = 0x40 # 010_00000 - Major Type 2 (Byte String)
58
+ MAJOR_TYPE_STR = 0x60 # 011_00000 - Major Type 3 (Text String)
59
+ MAJOR_TYPE_ARRAY = 0x80 # 100_00000 - Major Type 4 (Array)
60
+ MAJOR_TYPE_MAP = 0xa0 # 101_00000 - Major Type 5 (Map)
61
+ MAJOR_TYPE_TAG = 0xc0 # 110_00000 - Major type 6 (Tag)
62
+ MAJOR_TYPE_SIMPLE = 0xe0 # 111_00000 - Major type 7 (111) + 5 bit 0
63
+
64
+ FLOAT_BYTES = 0xfa # 111_11010 - Major type 7 (Float) + value: 26
65
+ DOUBLE_BYTES = 0xfb # 111_ 11011 - Major type 7 (Float) + value: 26
66
+
67
+ # https://www.rfc-editor.org/rfc/rfc8949.html#tags
68
+ TAG_TYPE_EPOCH = 1
69
+ TAG_BIGNUM_BASE = 2
70
+ TAG_TYPE_BIGDEC = 4
71
+
72
+ MAX_INTEGER = 18_446_744_073_709_551_616 # 2^64
73
+
74
+ def head(major_type, value)
75
+ @buffer <<
76
+ case value
77
+ when 0...24
78
+ [major_type + value].pack('C') # 8-bit unsigned
79
+ when 0...256
80
+ [major_type + 24, value].pack('CC')
81
+ when 0...65_536
82
+ [major_type + 25, value].pack('Cn')
83
+ when 0...4_294_967_296
84
+ [major_type + 26, value].pack('CN')
85
+ when 0...MAX_INTEGER
86
+ [major_type + 27, value].pack('CQ>')
87
+ else
88
+ raise Error, "Value is too large to encode: #{value}"
89
+ end
90
+ end
91
+
92
+ # streaming style, lower level interface
93
+ def add_integer(value)
94
+ major_type =
95
+ if value.negative?
96
+ value = -1 - value
97
+ MAJOR_TYPE_NEGATIVE_INT
98
+ else
99
+ MAJOR_TYPE_UNSIGNED_INT
100
+ end
101
+ head(major_type, value)
102
+ end
103
+
104
+ def add_bignum(value)
105
+ major_type =
106
+ if value.negative?
107
+ value = -1 - value
108
+ MAJOR_TYPE_NEGATIVE_INT
109
+ else
110
+ MAJOR_TYPE_UNSIGNED_INT
111
+ end
112
+ s = bignum_to_bytes(value)
113
+ head(MAJOR_TYPE_TAG, TAG_BIGNUM_BASE + (major_type >> 5))
114
+ head(MAJOR_TYPE_BYTE_STR, s.bytesize)
115
+ @buffer << s
116
+ end
117
+
118
+ # A decimal fraction or a bigfloat is represented as a tagged array
119
+ # that contains exactly two integer numbers:
120
+ # an exponent e and a mantissa m
121
+ # decimal fractions are always represented with a base of 10
122
+ # See: https://www.rfc-editor.org/rfc/rfc8949.html#name-decimal-fractions-and-bigfl
123
+ def add_big_decimal(value)
124
+ if value.infinite? == 1
125
+ return add_float(value.infinite? * Float::INFINITY)
126
+ elsif value.nan?
127
+ return add_float(Float::NAN)
128
+ end
129
+
130
+ head(MAJOR_TYPE_TAG, TAG_TYPE_BIGDEC)
131
+ sign, digits, base, exp = value.split
132
+ # Ruby BigDecimal digits of XXX are used as 0.XXX, convert
133
+ exp = exp - digits.size
134
+ digits = sign * digits.to_i
135
+ start_array(2)
136
+ add_auto_integer(exp)
137
+ add_auto_integer(digits)
138
+ end
139
+
140
+ def add_auto_integer(value)
141
+ major_type =
142
+ if value.negative?
143
+ value = -1 - value
144
+ MAJOR_TYPE_NEGATIVE_INT
145
+ else
146
+ MAJOR_TYPE_UNSIGNED_INT
147
+ end
148
+
149
+ if value >= MAX_INTEGER
150
+ s = bignum_to_bytes(value)
151
+ head(MAJOR_TYPE_TAG, TAG_BIGNUM_BASE + (major_type >> 5))
152
+ head(MAJOR_TYPE_BYTE_STR, s.bytesize)
153
+ @buffer << s
154
+ else
155
+ head(major_type, value)
156
+ end
157
+ end
158
+
159
+ def add_float(value)
160
+ @buffer << [FLOAT_BYTES, value].pack('Cg') # single-precision
161
+ end
162
+
163
+ def add_double(value)
164
+ @buffer << [DOUBLE_BYTES, value].pack('CG') # double-precision
165
+ end
166
+
167
+ def add_auto_float(value)
168
+ if value.nan?
169
+ @buffer << FLOAT_BYTES << [value].pack('g')
170
+ else
171
+ ss = [value].pack('g') # single-precision
172
+ if ss.unpack1('g') == value
173
+ @buffer << FLOAT_BYTES << ss
174
+ else
175
+ @buffer << [DOUBLE_BYTES, value].pack('CG') # double-precision
176
+ end
177
+ end
178
+ end
179
+
180
+ def add_nil
181
+ head(MAJOR_TYPE_SIMPLE, 22)
182
+ end
183
+
184
+ def add_boolean(value)
185
+ value ? head(MAJOR_TYPE_SIMPLE, 21) : head(MAJOR_TYPE_SIMPLE, 20)
186
+ end
187
+
188
+ # Encoding MUST already be Encoding::BINARY
189
+ def add_byte_string(value)
190
+ head(MAJOR_TYPE_BYTE_STR, value.bytesize)
191
+ @buffer << value
192
+ end
193
+
194
+ def add_string(value)
195
+ value = value.encode(Encoding::UTF_8).force_encoding(Encoding::BINARY)
196
+ head(MAJOR_TYPE_STR, value.bytesize)
197
+ @buffer << value
198
+ end
199
+
200
+ # caller is responsible for adding length values
201
+ def start_array(length)
202
+ head(MAJOR_TYPE_ARRAY, length)
203
+ end
204
+
205
+ def start_indefinite_array
206
+ head(MAJOR_TYPE_ARRAY + 31, 0)
207
+ end
208
+
209
+ # caller is responsible for adding length key/value pairs
210
+ def start_map(length)
211
+ head(MAJOR_TYPE_MAP, length)
212
+ end
213
+
214
+ def start_indefinite_map
215
+ head(MAJOR_TYPE_MAP + 31, 0)
216
+ end
217
+
218
+ def end_indefinite_collection
219
+ # write the stop sequence
220
+ head(MAJOR_TYPE_SIMPLE + 31, 0)
221
+ end
222
+
223
+ def add_tag(tag)
224
+ head(MAJOR_TYPE_TAG, tag)
225
+ end
226
+
227
+ def add_time(value)
228
+ head(MAJOR_TYPE_TAG, TAG_TYPE_EPOCH)
229
+ epoch = value.to_f
230
+ add_double(epoch)
231
+ end
232
+
233
+ def bignum_to_bytes(value)
234
+ s = String.new
235
+ while value != 0
236
+ s << (value & 0xFF)
237
+ value >>= 8
238
+ end
239
+ s.reverse!
240
+ end
241
+ end
242
+ end
243
+ end