aws-sdk-core 3.46.2 → 3.126.2

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 (206) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1258 -0
  3. data/LICENSE.txt +202 -0
  4. data/VERSION +1 -1
  5. data/lib/aws-defaults/default_configuration.rb +153 -0
  6. data/lib/aws-defaults/defaults_mode_config_resolver.rb +107 -0
  7. data/lib/aws-defaults.rb +3 -0
  8. data/lib/aws-sdk-core/arn.rb +92 -0
  9. data/lib/aws-sdk-core/arn_parser.rb +40 -0
  10. data/lib/aws-sdk-core/assume_role_credentials.rb +20 -0
  11. data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +109 -0
  12. data/lib/aws-sdk-core/async_client_stubs.rb +82 -0
  13. data/lib/aws-sdk-core/binary/decode_handler.rb +11 -1
  14. data/lib/aws-sdk-core/binary/encode_handler.rb +34 -0
  15. data/lib/aws-sdk-core/binary/event_builder.rb +124 -0
  16. data/lib/aws-sdk-core/binary/event_parser.rb +50 -18
  17. data/lib/aws-sdk-core/binary/event_stream_decoder.rb +7 -2
  18. data/lib/aws-sdk-core/binary/event_stream_encoder.rb +55 -0
  19. data/lib/aws-sdk-core/binary.rb +5 -0
  20. data/lib/aws-sdk-core/client_side_monitoring/publisher.rb +11 -1
  21. data/lib/aws-sdk-core/client_side_monitoring/request_metrics.rb +2 -0
  22. data/lib/aws-sdk-core/client_stubs.rb +16 -13
  23. data/lib/aws-sdk-core/credential_provider.rb +1 -30
  24. data/lib/aws-sdk-core/credential_provider_chain.rb +102 -40
  25. data/lib/aws-sdk-core/credentials.rb +2 -0
  26. data/lib/aws-sdk-core/deprecations.rb +17 -11
  27. data/lib/aws-sdk-core/eager_loader.rb +2 -0
  28. data/lib/aws-sdk-core/ec2_metadata.rb +238 -0
  29. data/lib/aws-sdk-core/ecs_credentials.rb +18 -9
  30. data/lib/aws-sdk-core/endpoint_cache.rb +16 -11
  31. data/lib/aws-sdk-core/errors.rb +138 -15
  32. data/lib/aws-sdk-core/event_emitter.rb +44 -0
  33. data/lib/aws-sdk-core/ini_parser.rb +2 -0
  34. data/lib/aws-sdk-core/instance_profile_credentials.rb +179 -42
  35. data/lib/aws-sdk-core/json/builder.rb +2 -0
  36. data/lib/aws-sdk-core/json/error_handler.rb +21 -2
  37. data/lib/aws-sdk-core/json/handler.rb +21 -1
  38. data/lib/aws-sdk-core/json/json_engine.rb +12 -8
  39. data/lib/aws-sdk-core/json/oj_engine.rb +35 -6
  40. data/lib/aws-sdk-core/json/parser.rb +10 -0
  41. data/lib/aws-sdk-core/json.rb +11 -28
  42. data/lib/aws-sdk-core/log/formatter.rb +16 -4
  43. data/lib/aws-sdk-core/log/handler.rb +2 -0
  44. data/lib/aws-sdk-core/log/param_filter.rb +38 -13
  45. data/lib/aws-sdk-core/log/param_formatter.rb +2 -0
  46. data/lib/aws-sdk-core/pageable_response.rb +48 -24
  47. data/lib/aws-sdk-core/pager.rb +5 -0
  48. data/lib/aws-sdk-core/param_converter.rb +2 -0
  49. data/lib/aws-sdk-core/param_validator.rb +63 -7
  50. data/lib/aws-sdk-core/plugins/api_key.rb +5 -1
  51. data/lib/aws-sdk-core/plugins/apig_authorizer_token.rb +2 -0
  52. data/lib/aws-sdk-core/plugins/apig_credentials_configuration.rb +2 -0
  53. data/lib/aws-sdk-core/plugins/apig_user_agent.rb +2 -0
  54. data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +28 -1
  55. data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +2 -0
  56. data/lib/aws-sdk-core/plugins/credentials_configuration.rb +26 -7
  57. data/lib/aws-sdk-core/plugins/defaults_mode.rb +40 -0
  58. data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +12 -4
  59. data/lib/aws-sdk-core/plugins/endpoint_pattern.rb +8 -6
  60. data/lib/aws-sdk-core/plugins/event_stream_configuration.rb +16 -0
  61. data/lib/aws-sdk-core/plugins/global_configuration.rb +2 -0
  62. data/lib/aws-sdk-core/plugins/helpful_socket_errors.rb +2 -0
  63. data/lib/aws-sdk-core/plugins/http_checksum.rb +57 -0
  64. data/lib/aws-sdk-core/plugins/idempotency_token.rb +2 -0
  65. data/lib/aws-sdk-core/plugins/invocation_id.rb +35 -0
  66. data/lib/aws-sdk-core/plugins/jsonvalue_converter.rb +2 -0
  67. data/lib/aws-sdk-core/plugins/logging.rb +2 -0
  68. data/lib/aws-sdk-core/plugins/param_converter.rb +2 -0
  69. data/lib/aws-sdk-core/plugins/param_validator.rb +2 -0
  70. data/lib/aws-sdk-core/plugins/protocols/api_gateway.rb +19 -0
  71. data/lib/aws-sdk-core/plugins/protocols/ec2.rb +2 -0
  72. data/lib/aws-sdk-core/plugins/protocols/json_rpc.rb +2 -0
  73. data/lib/aws-sdk-core/plugins/protocols/query.rb +2 -0
  74. data/lib/aws-sdk-core/plugins/protocols/rest_json.rb +18 -1
  75. data/lib/aws-sdk-core/plugins/protocols/rest_xml.rb +2 -0
  76. data/lib/aws-sdk-core/plugins/recursion_detection.rb +27 -0
  77. data/lib/aws-sdk-core/plugins/regional_endpoint.rb +74 -16
  78. data/lib/aws-sdk-core/plugins/response_paging.rb +2 -0
  79. data/lib/aws-sdk-core/plugins/retries/client_rate_limiter.rb +139 -0
  80. data/lib/aws-sdk-core/plugins/retries/clock_skew.rb +100 -0
  81. data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +146 -0
  82. data/lib/aws-sdk-core/plugins/retries/retry_quota.rb +59 -0
  83. data/lib/aws-sdk-core/plugins/retry_errors.rb +295 -107
  84. data/lib/aws-sdk-core/plugins/signature_v2.rb +2 -0
  85. data/lib/aws-sdk-core/plugins/signature_v4.rb +28 -25
  86. data/lib/aws-sdk-core/plugins/stub_responses.rb +24 -7
  87. data/lib/aws-sdk-core/plugins/transfer_encoding.rb +53 -0
  88. data/lib/aws-sdk-core/plugins/user_agent.rb +6 -8
  89. data/lib/aws-sdk-core/process_credentials.rb +12 -5
  90. data/lib/aws-sdk-core/query/ec2_param_builder.rb +2 -0
  91. data/lib/aws-sdk-core/query/handler.rb +2 -0
  92. data/lib/aws-sdk-core/query/param.rb +2 -0
  93. data/lib/aws-sdk-core/query/param_builder.rb +2 -0
  94. data/lib/aws-sdk-core/query/param_list.rb +2 -0
  95. data/lib/aws-sdk-core/query.rb +2 -0
  96. data/lib/aws-sdk-core/refreshing_credentials.rb +15 -2
  97. data/lib/aws-sdk-core/resources/collection.rb +2 -0
  98. data/lib/aws-sdk-core/rest/handler.rb +2 -0
  99. data/lib/aws-sdk-core/rest/request/body.rb +21 -1
  100. data/lib/aws-sdk-core/rest/request/builder.rb +2 -0
  101. data/lib/aws-sdk-core/rest/request/endpoint.rb +10 -3
  102. data/lib/aws-sdk-core/rest/request/headers.rb +20 -6
  103. data/lib/aws-sdk-core/rest/request/querystring_builder.rb +4 -2
  104. data/lib/aws-sdk-core/rest/response/body.rb +2 -0
  105. data/lib/aws-sdk-core/rest/response/headers.rb +6 -3
  106. data/lib/aws-sdk-core/rest/response/parser.rb +2 -0
  107. data/lib/aws-sdk-core/rest/response/status_code.rb +2 -0
  108. data/lib/aws-sdk-core/rest.rb +2 -0
  109. data/lib/aws-sdk-core/shared_config.rb +153 -127
  110. data/lib/aws-sdk-core/shared_credentials.rb +9 -1
  111. data/lib/aws-sdk-core/sso_credentials.rb +136 -0
  112. data/lib/aws-sdk-core/structure.rb +14 -4
  113. data/lib/aws-sdk-core/stubbing/data_applicator.rb +2 -0
  114. data/lib/aws-sdk-core/stubbing/empty_stub.rb +2 -0
  115. data/lib/aws-sdk-core/stubbing/protocols/api_gateway.rb +2 -0
  116. data/lib/aws-sdk-core/stubbing/protocols/ec2.rb +2 -0
  117. data/lib/aws-sdk-core/stubbing/protocols/json.rb +3 -1
  118. data/lib/aws-sdk-core/stubbing/protocols/query.rb +4 -2
  119. data/lib/aws-sdk-core/stubbing/protocols/rest.rb +52 -7
  120. data/lib/aws-sdk-core/stubbing/protocols/rest_json.rb +3 -1
  121. data/lib/aws-sdk-core/stubbing/protocols/rest_xml.rb +2 -2
  122. data/lib/aws-sdk-core/stubbing/stub_data.rb +15 -4
  123. data/lib/aws-sdk-core/stubbing/xml_error.rb +2 -0
  124. data/lib/aws-sdk-core/type_builder.rb +2 -0
  125. data/lib/aws-sdk-core/util.rb +6 -0
  126. data/lib/aws-sdk-core/waiters/errors.rb +2 -0
  127. data/lib/aws-sdk-core/waiters/poller.rb +2 -0
  128. data/lib/aws-sdk-core/waiters/waiter.rb +4 -2
  129. data/lib/aws-sdk-core/waiters.rb +2 -0
  130. data/lib/aws-sdk-core/xml/builder.rb +5 -3
  131. data/lib/aws-sdk-core/xml/default_list.rb +2 -0
  132. data/lib/aws-sdk-core/xml/default_map.rb +2 -0
  133. data/lib/aws-sdk-core/xml/doc_builder.rb +15 -4
  134. data/lib/aws-sdk-core/xml/error_handler.rb +29 -4
  135. data/lib/aws-sdk-core/xml/parser/engines/libxml.rb +2 -0
  136. data/lib/aws-sdk-core/xml/parser/engines/nokogiri.rb +2 -0
  137. data/lib/aws-sdk-core/xml/parser/engines/oga.rb +2 -0
  138. data/lib/aws-sdk-core/xml/parser/engines/ox.rb +3 -1
  139. data/lib/aws-sdk-core/xml/parser/engines/rexml.rb +4 -1
  140. data/lib/aws-sdk-core/xml/parser/frame.rb +25 -0
  141. data/lib/aws-sdk-core/xml/parser/parsing_error.rb +2 -0
  142. data/lib/aws-sdk-core/xml/parser/stack.rb +2 -0
  143. data/lib/aws-sdk-core/xml/parser.rb +7 -0
  144. data/lib/aws-sdk-core/xml.rb +2 -0
  145. data/lib/aws-sdk-core.rb +23 -4
  146. data/lib/aws-sdk-sso/client.rb +568 -0
  147. data/lib/aws-sdk-sso/client_api.rb +190 -0
  148. data/lib/aws-sdk-sso/customizations.rb +1 -0
  149. data/lib/aws-sdk-sso/errors.rb +102 -0
  150. data/lib/aws-sdk-sso/resource.rb +26 -0
  151. data/lib/aws-sdk-sso/types.rb +352 -0
  152. data/lib/aws-sdk-sso.rb +55 -0
  153. data/lib/aws-sdk-sts/client.rb +1282 -531
  154. data/lib/aws-sdk-sts/client_api.rb +76 -1
  155. data/lib/aws-sdk-sts/customizations.rb +4 -0
  156. data/lib/aws-sdk-sts/errors.rb +153 -1
  157. data/lib/aws-sdk-sts/plugins/sts_regional_endpoints.rb +38 -0
  158. data/lib/aws-sdk-sts/presigner.rb +75 -0
  159. data/lib/aws-sdk-sts/resource.rb +4 -1
  160. data/lib/aws-sdk-sts/types.rb +958 -229
  161. data/lib/aws-sdk-sts.rb +16 -6
  162. data/lib/seahorse/client/async_base.rb +52 -0
  163. data/lib/seahorse/client/async_response.rb +64 -0
  164. data/lib/seahorse/client/base.rb +7 -2
  165. data/lib/seahorse/client/block_io.rb +6 -2
  166. data/lib/seahorse/client/configuration.rb +7 -1
  167. data/lib/seahorse/client/events.rb +3 -1
  168. data/lib/seahorse/client/h2/connection.rb +250 -0
  169. data/lib/seahorse/client/h2/handler.rb +152 -0
  170. data/lib/seahorse/client/handler.rb +2 -0
  171. data/lib/seahorse/client/handler_builder.rb +2 -0
  172. data/lib/seahorse/client/handler_list.rb +2 -0
  173. data/lib/seahorse/client/handler_list_entry.rb +6 -4
  174. data/lib/seahorse/client/http/async_response.rb +44 -0
  175. data/lib/seahorse/client/http/headers.rb +2 -0
  176. data/lib/seahorse/client/http/request.rb +5 -3
  177. data/lib/seahorse/client/http/response.rb +18 -11
  178. data/lib/seahorse/client/logging/formatter.rb +6 -2
  179. data/lib/seahorse/client/logging/handler.rb +2 -0
  180. data/lib/seahorse/client/managed_file.rb +2 -0
  181. data/lib/seahorse/client/net_http/connection_pool.rb +30 -23
  182. data/lib/seahorse/client/net_http/handler.rb +24 -7
  183. data/lib/seahorse/client/net_http/patches.rb +15 -84
  184. data/lib/seahorse/client/networking_error.rb +30 -0
  185. data/lib/seahorse/client/plugin.rb +10 -7
  186. data/lib/seahorse/client/plugin_list.rb +2 -0
  187. data/lib/seahorse/client/plugins/content_length.rb +14 -3
  188. data/lib/seahorse/client/plugins/endpoint.rb +4 -2
  189. data/lib/seahorse/client/plugins/h2.rb +69 -0
  190. data/lib/seahorse/client/plugins/logging.rb +2 -0
  191. data/lib/seahorse/client/plugins/net_http.rb +39 -3
  192. data/lib/seahorse/client/plugins/operation_methods.rb +2 -0
  193. data/lib/seahorse/client/plugins/raise_response_errors.rb +2 -0
  194. data/lib/seahorse/client/plugins/request_callback.rb +110 -0
  195. data/lib/seahorse/client/plugins/response_target.rb +23 -14
  196. data/lib/seahorse/client/request.rb +2 -0
  197. data/lib/seahorse/client/request_context.rb +2 -0
  198. data/lib/seahorse/client/response.rb +5 -5
  199. data/lib/seahorse/model/api.rb +10 -0
  200. data/lib/seahorse/model/authorizer.rb +2 -0
  201. data/lib/seahorse/model/operation.rb +9 -0
  202. data/lib/seahorse/model/shapes.rb +29 -2
  203. data/lib/seahorse/util.rb +8 -1
  204. data/lib/seahorse/version.rb +2 -0
  205. data/lib/seahorse.rb +12 -0
  206. metadata +64 -14
data/lib/aws-sdk-sts.rb CHANGED
@@ -1,11 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # WARNING ABOUT GENERATED CODE
2
4
  #
3
5
  # This file is generated. See the contributing guide for more information:
4
- # https://github.com/aws/aws-sdk-ruby/blob/master/CONTRIBUTING.md
6
+ # https://github.com/aws/aws-sdk-ruby/blob/version-3/CONTRIBUTING.md
5
7
  #
6
8
  # WARNING ABOUT GENERATED CODE
7
9
 
8
10
 
11
+ unless Module.const_defined?(:Aws)
12
+ require 'aws-sdk-core'
13
+ require 'aws-sigv4'
14
+ end
15
+
9
16
  require_relative 'aws-sdk-sts/types'
10
17
  require_relative 'aws-sdk-sts/client_api'
11
18
  require_relative 'aws-sdk-sts/client'
@@ -22,24 +29,27 @@ require_relative 'aws-sdk-sts/customizations'
22
29
  # methods each accept a hash of request parameters and return a response
23
30
  # structure.
24
31
  #
32
+ # sts = Aws::STS::Client.new
33
+ # resp = sts.assume_role(params)
34
+ #
25
35
  # See {Client} for more information.
26
36
  #
27
37
  # # Errors
28
38
  #
29
- # Errors returned from AWS Security Token Service all
30
- # extend {Errors::ServiceError}.
39
+ # Errors returned from AWS Security Token Service are defined in the
40
+ # {Errors} module and all extend {Errors::ServiceError}.
31
41
  #
32
42
  # begin
33
43
  # # do stuff
34
44
  # rescue Aws::STS::Errors::ServiceError
35
- # # rescues all service API errors
45
+ # # rescues all AWS Security Token Service API errors
36
46
  # end
37
47
  #
38
48
  # See {Errors} for more information.
39
49
  #
40
- # @service
50
+ # @!group service
41
51
  module Aws::STS
42
52
 
43
- GEM_VERSION = '3.46.2'
53
+ GEM_VERSION = '3.126.2'
44
54
 
45
55
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Seahorse
4
+ module Client
5
+ class AsyncBase < Seahorse::Client::Base
6
+
7
+ # default H2 plugins
8
+ @plugins = PluginList.new([
9
+ Plugins::Endpoint,
10
+ Plugins::H2,
11
+ Plugins::ResponseTarget
12
+ ])
13
+
14
+ def initialize(plugins, options)
15
+ super
16
+ @connection = H2::Connection.new(options)
17
+ @options = options
18
+ end
19
+
20
+ # @return [H2::Connection]
21
+ attr_reader :connection
22
+
23
+ # @return [Array<Symbol>] Returns a list of valid async request
24
+ # operation names.
25
+ def operation_names
26
+ self.class.api.async_operation_names
27
+ end
28
+
29
+ # Closes the underlying HTTP2 Connection for the client
30
+ # @return [Symbol] Returns the status of the connection (:closed)
31
+ def close_connection
32
+ @connection.close!
33
+ end
34
+
35
+ # Creates a new HTTP2 Connection for the client
36
+ # @return [Seahorse::Client::H2::Connection]
37
+ def new_connection
38
+ if @connection.closed?
39
+ @connection = H2::Connection.new(@options)
40
+ else
41
+ @connection
42
+ end
43
+ end
44
+
45
+ def connection_errors
46
+ @connection.errors
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Seahorse
4
+ module Client
5
+ class AsyncResponse
6
+
7
+ def initialize(options = {})
8
+ @response = Response.new(context: options[:context])
9
+ @stream = options[:stream]
10
+ @stream_mutex = options[:stream_mutex]
11
+ @close_condition = options[:close_condition]
12
+ @sync_queue = options[:sync_queue]
13
+ end
14
+
15
+ def context
16
+ @response.context
17
+ end
18
+
19
+ def error
20
+ @response.error
21
+ end
22
+
23
+ def on(range, &block)
24
+ @response.on(range, &block)
25
+ self
26
+ end
27
+
28
+ def on_complete(&block)
29
+ @response.on_complete(&block)
30
+ self
31
+ end
32
+
33
+ def wait
34
+ if error && context.config.raise_response_errors
35
+ raise error
36
+ elsif @stream
37
+ # have a sync signal that #signal can be blocked on
38
+ # else, if #signal is called before #wait
39
+ # will be waiting for a signal never arrives
40
+ @sync_queue << "sync_signal"
41
+ # now #signal is unlocked for
42
+ # signaling close condition when ready
43
+ @stream_mutex.synchronize {
44
+ @close_condition.wait(@stream_mutex)
45
+ }
46
+ @response
47
+ end
48
+ end
49
+
50
+ def join!
51
+ if error && context.config.raise_response_errors
52
+ raise error
53
+ elsif @stream
54
+ # close callback is waiting
55
+ # for the "sync_signal"
56
+ @sync_queue << "sync_signal"
57
+ @stream.close
58
+ @response
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thread'
2
4
 
3
5
  module Seahorse
@@ -12,6 +14,7 @@ module Seahorse
12
14
  Plugins::NetHttp,
13
15
  Plugins::RaiseResponseErrors,
14
16
  Plugins::ResponseTarget,
17
+ Plugins::RequestCallback
15
18
  ])
16
19
 
17
20
  # @api private
@@ -46,7 +49,7 @@ module Seahorse
46
49
  # names. These are valid arguments to {#build_request} and are also
47
50
  # valid methods.
48
51
  def operation_names
49
- self.class.api.operation_names
52
+ self.class.api.operation_names - self.class.api.async_operation_names
50
53
  end
51
54
 
52
55
  private
@@ -194,13 +197,15 @@ module Seahorse
194
197
  private
195
198
 
196
199
  def define_operation_methods
200
+ operations_module = Module.new
197
201
  @api.operation_names.each do |method_name|
198
- define_method(method_name) do |*args, &block|
202
+ operations_module.send(:define_method, method_name) do |*args, &block|
199
203
  params = args[0] || {}
200
204
  options = args[1] || {}
201
205
  build_request(method_name, params).send_request(options, &block)
202
206
  end
203
207
  end
208
+ include(operations_module)
204
209
  end
205
210
 
206
211
  def build_plugins
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seahorse
2
4
  module Client
3
5
  class BlockIO
4
6
 
5
- def initialize(&block)
7
+ def initialize(headers = nil, &block)
8
+ @headers = headers
6
9
  @block = block
7
10
  @size = 0
8
11
  end
@@ -10,7 +13,8 @@ module Seahorse
10
13
  # @param [String] chunk
11
14
  # @return [Integer]
12
15
  def write(chunk)
13
- @block.call(chunk)
16
+ @block.call(chunk, @headers)
17
+ ensure
14
18
  chunk.bytesize.tap { |chunk_size| @size += chunk_size }
15
19
  end
16
20
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module Seahorse
@@ -104,7 +106,7 @@ module Seahorse
104
106
  #
105
107
  # @return [self]
106
108
  def add_option(name, default = nil, &block)
107
- default = DynamicDefault.new(Proc.new) if block_given?
109
+ default = DynamicDefault.new(block) if block_given?
108
110
  @defaults[name.to_sym] << default
109
111
  self
110
112
  end
@@ -193,6 +195,10 @@ module Seahorse
193
195
  @members.include?(method_name) or super
194
196
  end
195
197
 
198
+ def override_config(k, v)
199
+ @struct[k] = v
200
+ end
201
+
196
202
  private
197
203
 
198
204
  def value_at(opt_name)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seahorse
2
4
  module Client
3
5
  module EventEmitter
@@ -9,7 +11,7 @@ module Seahorse
9
11
 
10
12
  def emit(event_name, *args, &block)
11
13
  @listeners[event_name] ||= []
12
- @listeners[event_name] << Proc.new
14
+ @listeners[event_name] << block if block_given?
13
15
  end
14
16
 
15
17
  def signal(event, *args)
@@ -0,0 +1,250 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'http/2'
5
+ rescue LoadError; end
6
+ require 'openssl'
7
+ require 'socket'
8
+
9
+ module Seahorse
10
+ module Client
11
+ # @api private
12
+ module H2
13
+
14
+ # H2 Connection build on top of `http/2` gem
15
+ # (requires Ruby >= 2.1)
16
+ # with TLS layer plus ALPN, requires:
17
+ # Ruby >= 2.3 and OpenSSL >= 1.0.2
18
+ class Connection
19
+
20
+ OPTIONS = {
21
+ max_concurrent_streams: 100,
22
+ connection_timeout: 60,
23
+ connection_read_timeout: 60,
24
+ http_wire_trace: false,
25
+ logger: nil,
26
+ ssl_verify_peer: true,
27
+ ssl_ca_bundle: nil,
28
+ ssl_ca_directory: nil,
29
+ ssl_ca_store: nil,
30
+ enable_alpn: false
31
+ }
32
+
33
+ # chunk read size at socket
34
+ CHUNKSIZE = 1024
35
+
36
+ SOCKET_FAMILY = ::Socket::AF_INET
37
+
38
+ def initialize(options = {})
39
+ OPTIONS.each_pair do |opt_name, default_value|
40
+ value = options[opt_name].nil? ? default_value : options[opt_name]
41
+ instance_variable_set("@#{opt_name}", value)
42
+ end
43
+ @h2_client = HTTP2::Client.new(
44
+ settings_max_concurrent_streams: max_concurrent_streams
45
+ )
46
+ @logger = options[:logger] || Logger.new($stdout) if @http_wire_trace
47
+ @chunk_size = options[:read_chunk_size] || CHUNKSIZE
48
+ @errors = []
49
+ @status = :ready
50
+ @mutex = Mutex.new # connection can be shared across requests
51
+ @socket = nil
52
+ @socket_thread = nil
53
+ end
54
+
55
+ OPTIONS.keys.each do |attr_name|
56
+ attr_reader(attr_name)
57
+ end
58
+
59
+ alias ssl_verify_peer? ssl_verify_peer
60
+
61
+ attr_reader :errors
62
+
63
+ attr_accessor :input_signal_thread
64
+
65
+ def new_stream
66
+ begin
67
+ @h2_client.new_stream
68
+ rescue => error
69
+ raise Http2StreamInitializeError.new(error)
70
+ end
71
+ end
72
+
73
+ def connect(endpoint)
74
+ @mutex.synchronize {
75
+ if @status == :ready
76
+ tcp, addr = _tcp_socket(endpoint)
77
+ debug_output("opening connection to #{endpoint.host}:#{endpoint.port} ...")
78
+ _nonblocking_connect(tcp, addr)
79
+ debug_output('opened')
80
+
81
+ if endpoint.scheme == 'https'
82
+ @socket = OpenSSL::SSL::SSLSocket.new(tcp, _tls_context)
83
+ @socket.sync_close = true
84
+ @socket.hostname = endpoint.host
85
+
86
+ debug_output("starting TLS for #{endpoint.host}:#{endpoint.port} ...")
87
+ @socket.connect
88
+ debug_output('TLS established')
89
+ else
90
+ @socket = tcp
91
+ end
92
+
93
+ _register_h2_callbacks
94
+ @status = :active
95
+ elsif @status == :closed
96
+ msg = 'Async Client HTTP2 Connection is closed, you may'\
97
+ ' use #new_connection to create a new HTTP2 Connection for this client'
98
+ raise Http2ConnectionClosedError.new(msg)
99
+ end
100
+ }
101
+ end
102
+
103
+ def start(stream)
104
+ @mutex.synchronize {
105
+ return if @socket_thread
106
+ @socket_thread = Thread.new do
107
+ while !@socket.closed?
108
+ begin
109
+ data = @socket.read_nonblock(@chunk_size)
110
+ @h2_client << data
111
+ rescue IO::WaitReadable
112
+ begin
113
+ unless IO.select([@socket], nil, nil, connection_read_timeout)
114
+ self.debug_output('socket connection read time out')
115
+ self.close!
116
+ else
117
+ # available, retry to start reading
118
+ retry
119
+ end
120
+ rescue
121
+ # error can happen when closing the socket
122
+ # while it's waiting for read
123
+ self.close!
124
+ end
125
+ rescue EOFError
126
+ self.close!
127
+ rescue => error
128
+ self.debug_output(error.inspect)
129
+ @errors << error
130
+ self.close!
131
+ end
132
+ end
133
+ end
134
+ @socket_thread.abort_on_exception = true
135
+ }
136
+ end
137
+
138
+ def close!
139
+ @mutex.synchronize {
140
+ self.debug_output('closing connection ...')
141
+ if @socket
142
+ @socket.close
143
+ @socket = nil
144
+ end
145
+ if @socket_thread
146
+ Thread.kill(@socket_thread)
147
+ @socket_thread = nil
148
+ end
149
+ @status = :closed
150
+ }
151
+ end
152
+
153
+ def closed?
154
+ @status == :closed
155
+ end
156
+
157
+ def debug_output(msg, type = nil)
158
+ prefix = case type
159
+ when :send then '-> '
160
+ when :receive then '<- '
161
+ else
162
+ ''
163
+ end
164
+ return unless @logger
165
+ _debug_entry(prefix + msg)
166
+ end
167
+
168
+ private
169
+
170
+ def _debug_entry(str)
171
+ @logger << str
172
+ @logger << "\n"
173
+ end
174
+
175
+ def _register_h2_callbacks
176
+ @h2_client.on(:frame) do |bytes|
177
+ if @socket.nil?
178
+ msg = 'Connection is closed due to errors, '\
179
+ 'you can find errors at async_client.connection.errors'
180
+ raise Http2ConnectionClosedError.new(msg)
181
+ else
182
+ @socket.print(bytes)
183
+ @socket.flush
184
+ end
185
+ end
186
+ @h2_client.on(:frame_sent) do |frame|
187
+ debug_output("frame: #{frame.inspect}", :send)
188
+ end
189
+ @h2_client.on(:frame_received) do |frame|
190
+ debug_output("frame: #{frame.inspect}", :receive)
191
+ end
192
+ end
193
+
194
+ def _tcp_socket(endpoint)
195
+ tcp = ::Socket.new(SOCKET_FAMILY, ::Socket::SOCK_STREAM, 0)
196
+ tcp.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
197
+
198
+ address = ::Socket.getaddrinfo(endpoint.host, nil, SOCKET_FAMILY).first[3]
199
+ sockaddr = ::Socket.sockaddr_in(endpoint.port, address)
200
+
201
+ [tcp, sockaddr]
202
+ end
203
+
204
+ def _nonblocking_connect(tcp, addr)
205
+ begin
206
+ tcp.connect_nonblock(addr)
207
+ rescue IO::WaitWritable
208
+ unless IO.select(nil, [tcp], nil, connection_timeout)
209
+ tcp.close
210
+ raise
211
+ end
212
+ begin
213
+ tcp.connect_nonblock(addr)
214
+ rescue Errno::EISCONN
215
+ # tcp socket connected, continue
216
+ end
217
+ end
218
+ end
219
+
220
+ def _tls_context
221
+ ssl_ctx = OpenSSL::SSL::SSLContext.new(:TLSv1_2)
222
+ if ssl_verify_peer?
223
+ ssl_ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
224
+ ssl_ctx.ca_file = ssl_ca_bundle ? ssl_ca_bundle : _default_ca_bundle
225
+ ssl_ctx.ca_path = ssl_ca_directory ? ssl_ca_directory : _default_ca_directory
226
+ ssl_ctx.cert_store = ssl_ca_store if ssl_ca_store
227
+ else
228
+ ssl_ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
229
+ end
230
+ if enable_alpn
231
+ debug_output('enabling ALPN for TLS ...')
232
+ ssl_ctx.alpn_protocols = ['h2']
233
+ end
234
+ ssl_ctx
235
+ end
236
+
237
+ def _default_ca_bundle
238
+ File.exist?(OpenSSL::X509::DEFAULT_CERT_FILE) ?
239
+ OpenSSL::X509::DEFAULT_CERT_FILE : nil
240
+ end
241
+
242
+ def _default_ca_directory
243
+ Dir.exist?(OpenSSL::X509::DEFAULT_CERT_DIR) ?
244
+ OpenSSL::X509::DEFAULT_CERT_DIR : nil
245
+ end
246
+
247
+ end
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'http/2'
5
+ rescue LoadError; end
6
+
7
+ require 'securerandom'
8
+
9
+ module Seahorse
10
+ module Client
11
+ # @api private
12
+ module H2
13
+
14
+ NETWORK_ERRORS = [
15
+ SocketError, EOFError, IOError, Timeout::Error,
16
+ Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE,
17
+ Errno::EINVAL, Errno::ETIMEDOUT, OpenSSL::SSL::SSLError,
18
+ Errno::EHOSTUNREACH, Errno::ECONNREFUSED,# OpenSSL::SSL::SSLErrorWaitReadable
19
+ ]
20
+
21
+ # @api private
22
+ DNS_ERROR_MESSAGES = [
23
+ 'getaddrinfo: nodename nor servname provided, or not known', # MacOS
24
+ 'getaddrinfo: Name or service not known' # GNU
25
+ ]
26
+
27
+ class Handler < Client::Handler
28
+
29
+ def call(context)
30
+ stream = nil
31
+ begin
32
+ conn = context.client.connection
33
+ stream = conn.new_stream
34
+
35
+ stream_mutex = Mutex.new
36
+ close_condition = ConditionVariable.new
37
+ sync_queue = Queue.new
38
+
39
+ conn.connect(context.http_request.endpoint)
40
+ _register_callbacks(
41
+ context.http_response,
42
+ stream,
43
+ stream_mutex,
44
+ close_condition,
45
+ sync_queue
46
+ )
47
+
48
+ conn.debug_output("sending initial request ...")
49
+ if input_emitter = context[:input_event_emitter]
50
+ _send_initial_headers(context.http_request, stream)
51
+
52
+ # prepare for sending events later
53
+ input_emitter.stream = stream
54
+ # request sigv4 serves as the initial #prior_signature
55
+ input_emitter.encoder.prior_signature =
56
+ context.http_request.headers['authorization'].split('Signature=').last
57
+ input_emitter.validate_event = context.config.validate_params
58
+ else
59
+ _send_initial_headers(context.http_request, stream)
60
+ _send_initial_data(context.http_request, stream)
61
+ end
62
+
63
+ conn.start(stream)
64
+ rescue *NETWORK_ERRORS => error
65
+ error = NetworkingError.new(
66
+ error, error_message(context.http_request, error))
67
+ context.http_response.signal_error(error)
68
+ rescue => error
69
+ conn.debug_output(error.inspect)
70
+ # not retryable
71
+ context.http_response.signal_error(error)
72
+ end
73
+
74
+ AsyncResponse.new(
75
+ context: context,
76
+ stream: stream,
77
+ stream_mutex: stream_mutex,
78
+ close_condition: close_condition,
79
+ sync_queue: sync_queue
80
+ )
81
+ end
82
+
83
+ private
84
+
85
+ def _register_callbacks(resp, stream, stream_mutex, close_condition, sync_queue)
86
+ stream.on(:headers) do |headers|
87
+ resp.signal_headers(headers)
88
+ end
89
+
90
+ stream.on(:data) do |data|
91
+ resp.signal_data(data)
92
+ end
93
+
94
+ stream.on(:close) do
95
+ resp.signal_done
96
+ # block until #wait is ready for signal
97
+ # else deadlock may happen because #signal happened
98
+ # eariler than #wait (see AsyncResponse#wait)
99
+ sync_queue.pop
100
+ stream_mutex.synchronize {
101
+ close_condition.signal
102
+ }
103
+ end
104
+ end
105
+
106
+ def _send_initial_headers(req, stream)
107
+ begin
108
+ headers = _h2_headers(req)
109
+ stream.headers(headers, end_stream: false)
110
+ rescue => e
111
+ raise Http2InitialRequestError.new(e)
112
+ end
113
+ end
114
+
115
+ def _send_initial_data(req, stream)
116
+ begin
117
+ data = req.body.read
118
+ stream.data(data, end_stream: true)
119
+ rescue => e
120
+ raise Http2InitialRequestError.new(e)
121
+ end
122
+ data
123
+ end
124
+
125
+ # H2 pseudo headers
126
+ # https://http2.github.io/http2-spec/#rfc.section.8.1.2.3
127
+ def _h2_headers(req)
128
+ headers = {}
129
+ headers[':method'] = req.http_method.upcase
130
+ headers[':scheme'] = req.endpoint.scheme
131
+ headers[':path'] = req.endpoint.path.empty? ? '/' : req.endpoint.path
132
+ if req.endpoint.query && !req.endpoint.query.empty?
133
+ headers[':path'] += "?#{req.endpoint.query}"
134
+ end
135
+ req.headers.each {|k, v| headers[k.downcase] = v }
136
+ headers
137
+ end
138
+
139
+ def error_message(req, error)
140
+ if error.is_a?(SocketError) && DNS_ERROR_MESSAGES.include?(error.message)
141
+ host = req.endpoint.host
142
+ "unable to connect to `#{host}`; SocketError: #{error.message}"
143
+ else
144
+ error.message
145
+ end
146
+ end
147
+
148
+ end
149
+
150
+ end
151
+ end
152
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seahorse
2
4
  module Client
3
5
  class Handler
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Seahorse
2
4
  module Client
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thread'
2
4
  require 'set'
3
5