aws-sdk-core 3.39.0 → 3.54.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/aws-sdk-core/async_client_stubs.rb +80 -0
  4. data/lib/aws-sdk-core/binary/decode_handler.rb +9 -1
  5. data/lib/aws-sdk-core/binary/encode_handler.rb +32 -0
  6. data/lib/aws-sdk-core/binary/event_builder.rb +122 -0
  7. data/lib/aws-sdk-core/binary/event_parser.rb +48 -18
  8. data/lib/aws-sdk-core/binary/event_stream_decoder.rb +5 -2
  9. data/lib/aws-sdk-core/binary/event_stream_encoder.rb +53 -0
  10. data/lib/aws-sdk-core/binary.rb +3 -0
  11. data/lib/aws-sdk-core/client_side_monitoring/request_metrics.rb +63 -9
  12. data/lib/aws-sdk-core/client_stubs.rb +1 -1
  13. data/lib/aws-sdk-core/ecs_credentials.rb +12 -8
  14. data/lib/aws-sdk-core/errors.rb +38 -2
  15. data/lib/aws-sdk-core/event_emitter.rb +42 -0
  16. data/lib/aws-sdk-core/instance_profile_credentials.rb +12 -8
  17. data/lib/aws-sdk-core/json/error_handler.rb +19 -2
  18. data/lib/aws-sdk-core/json/handler.rb +19 -1
  19. data/lib/aws-sdk-core/log/param_filter.rb +1 -1
  20. data/lib/aws-sdk-core/param_validator.rb +9 -1
  21. data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +22 -3
  22. data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +5 -1
  23. data/lib/aws-sdk-core/plugins/event_stream_configuration.rb +14 -0
  24. data/lib/aws-sdk-core/plugins/invocation_id.rb +33 -0
  25. data/lib/aws-sdk-core/plugins/retry_errors.rb +2 -0
  26. data/lib/aws-sdk-core/plugins/stub_responses.rb +19 -7
  27. data/lib/aws-sdk-core/plugins/transfer_encoding.rb +53 -0
  28. data/lib/aws-sdk-core/plugins/user_agent.rb +6 -0
  29. data/lib/aws-sdk-core/process_credentials.rb +7 -1
  30. data/lib/aws-sdk-core/query/handler.rb +6 -1
  31. data/lib/aws-sdk-core/refreshing_credentials.rb +1 -1
  32. data/lib/aws-sdk-core/resources/collection.rb +1 -1
  33. data/lib/aws-sdk-core/structure.rb +6 -2
  34. data/lib/aws-sdk-core/stubbing/protocols/rest.rb +19 -0
  35. data/lib/aws-sdk-core/stubbing/stub_data.rb +13 -4
  36. data/lib/aws-sdk-core/waiters/waiter.rb +2 -2
  37. data/lib/aws-sdk-core/xml/error_handler.rb +26 -3
  38. data/lib/aws-sdk-core.rb +1 -0
  39. data/lib/aws-sdk-sts/client.rb +622 -427
  40. data/lib/aws-sdk-sts/client_api.rb +35 -0
  41. data/lib/aws-sdk-sts/errors.rb +128 -0
  42. data/lib/aws-sdk-sts/types.rb +498 -165
  43. data/lib/aws-sdk-sts.rb +1 -1
  44. data/lib/seahorse/client/async_base.rb +50 -0
  45. data/lib/seahorse/client/async_response.rb +62 -0
  46. data/lib/seahorse/client/base.rb +1 -1
  47. data/lib/seahorse/client/configuration.rb +4 -2
  48. data/lib/seahorse/client/events.rb +1 -1
  49. data/lib/seahorse/client/h2/connection.rb +244 -0
  50. data/lib/seahorse/client/h2/handler.rb +151 -0
  51. data/lib/seahorse/client/http/async_response.rb +42 -0
  52. data/lib/seahorse/client/http/response.rb +13 -8
  53. data/lib/seahorse/client/net_http/patches.rb +7 -1
  54. data/lib/seahorse/client/networking_error.rb +28 -0
  55. data/lib/seahorse/client/plugin.rb +1 -1
  56. data/lib/seahorse/client/plugins/content_length.rb +7 -2
  57. data/lib/seahorse/client/plugins/h2.rb +64 -0
  58. data/lib/seahorse/model/api.rb +4 -0
  59. data/lib/seahorse/model/operation.rb +4 -0
  60. data/lib/seahorse/model/shapes.rb +2 -2
  61. data/lib/seahorse.rb +9 -0
  62. metadata +23 -5
data/lib/aws-sdk-sts.rb CHANGED
@@ -40,6 +40,6 @@ require_relative 'aws-sdk-sts/customizations'
40
40
  # @service
41
41
  module Aws::STS
42
42
 
43
- GEM_VERSION = '3.39.0'
43
+ GEM_VERSION = '3.54.2'
44
44
 
45
45
  end
@@ -0,0 +1,50 @@
1
+ module Seahorse
2
+ module Client
3
+ class AsyncBase < Seahorse::Client::Base
4
+
5
+ # default H2 plugins
6
+ @plugins = PluginList.new([
7
+ Plugins::Endpoint,
8
+ Plugins::H2,
9
+ Plugins::ResponseTarget
10
+ ])
11
+
12
+ def initialize(plugins, options)
13
+ super
14
+ @connection = H2::Connection.new(options)
15
+ @options = options
16
+ end
17
+
18
+ # @return [H2::Connection]
19
+ attr_reader :connection
20
+
21
+ # @return [Array<Symbol>] Returns a list of valid async request
22
+ # operation names.
23
+ def operation_names
24
+ self.class.api.async_operation_names
25
+ end
26
+
27
+ # Closes the underlying HTTP2 Connection for the client
28
+ # @return [Symbol] Returns the status of the connection (:closed)
29
+ def close_connection
30
+ @connection.close!
31
+ end
32
+
33
+ # Creates a new HTTP2 Connection for the client
34
+ # @return [Seahorse::Client::H2::Connection]
35
+ def new_connection
36
+ if @connection.closed?
37
+ @connection = H2::Connection.new(@options)
38
+ else
39
+ @connection
40
+ end
41
+ end
42
+
43
+ def connection_errors
44
+ @connection.errors
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,62 @@
1
+ module Seahorse
2
+ module Client
3
+ class AsyncResponse
4
+
5
+ def initialize(options = {})
6
+ @response = Response.new(context: options[:context])
7
+ @stream = options[:stream]
8
+ @stream_mutex = options[:stream_mutex]
9
+ @close_condition = options[:close_condition]
10
+ @sync_queue = options[:sync_queue]
11
+ end
12
+
13
+ def context
14
+ @response.context
15
+ end
16
+
17
+ def error
18
+ @response.error
19
+ end
20
+
21
+ def on(range, &block)
22
+ @response.on(range, &block)
23
+ self
24
+ end
25
+
26
+ def on_complete(&block)
27
+ @response.on_complete(&block)
28
+ self
29
+ end
30
+
31
+ def wait
32
+ if error && context.config.raise_response_errors
33
+ raise error
34
+ elsif @stream
35
+ # have a sync signal that #signal can be blocked on
36
+ # else, if #signal is called before #wait
37
+ # will be waiting for a signal never arrives
38
+ @sync_queue << "sync_signal"
39
+ # now #signal is unlocked for
40
+ # signaling close condition when ready
41
+ @stream_mutex.synchronize {
42
+ @close_condition.wait(@stream_mutex)
43
+ }
44
+ @response
45
+ end
46
+ end
47
+
48
+ def join!
49
+ if error && context.config.raise_response_errors
50
+ raise error
51
+ elsif @stream
52
+ # close callback is waiting
53
+ # for the "sync_signal"
54
+ @sync_queue << "sync_signal"
55
+ @stream.close
56
+ @response
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -46,7 +46,7 @@ module Seahorse
46
46
  # names. These are valid arguments to {#build_request} and are also
47
47
  # valid methods.
48
48
  def operation_names
49
- self.class.api.operation_names
49
+ self.class.api.operation_names - self.class.api.async_operation_names
50
50
  end
51
51
 
52
52
  private
@@ -104,7 +104,7 @@ module Seahorse
104
104
  #
105
105
  # @return [self]
106
106
  def add_option(name, default = nil, &block)
107
- default = DynamicDefault.new(Proc.new) if block_given?
107
+ default = DynamicDefault.new(block) if block_given?
108
108
  @defaults[name.to_sym] << default
109
109
  self
110
110
  end
@@ -199,7 +199,9 @@ module Seahorse
199
199
  value = @struct[opt_name]
200
200
  if value.is_a?(Defaults)
201
201
  # this config value is used by endpoint discovery
202
- @struct[:regional_endpoint] = true if opt_name == :endpoint
202
+ if opt_name == :endpoint && @struct.members.include?(:regional_endpoint)
203
+ @struct[:regional_endpoint] = true
204
+ end
203
205
  resolve_defaults(opt_name, value)
204
206
  else
205
207
  value
@@ -9,7 +9,7 @@ module Seahorse
9
9
 
10
10
  def emit(event_name, *args, &block)
11
11
  @listeners[event_name] ||= []
12
- @listeners[event_name] << Proc.new
12
+ @listeners[event_name] << block if block_given?
13
13
  end
14
14
 
15
15
  def signal(event, *args)
@@ -0,0 +1,244 @@
1
+ if RUBY_VERSION >= '2.1'
2
+ begin
3
+ require 'http/2'
4
+ rescue LoadError; end
5
+ 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
+ end
52
+
53
+ OPTIONS.keys.each do |attr_name|
54
+ attr_reader(attr_name)
55
+ end
56
+
57
+ alias ssl_verify_peer? ssl_verify_peer
58
+
59
+ attr_reader :errors
60
+
61
+ attr_accessor :input_signal_thread
62
+
63
+ def new_stream
64
+ begin
65
+ @h2_client.new_stream
66
+ rescue => error
67
+ raise Http2StreamInitializeError.new(error)
68
+ end
69
+ end
70
+
71
+ def connect(endpoint)
72
+ @mutex.synchronize {
73
+ if @status == :ready
74
+ tcp, addr = _tcp_socket(endpoint)
75
+ debug_output("opening connection to #{endpoint.host}:#{endpoint.port} ...")
76
+ _nonblocking_connect(tcp, addr)
77
+ debug_output("opened")
78
+
79
+ @socket = OpenSSL::SSL::SSLSocket.new(tcp, _tls_context)
80
+ @socket.sync_close = true
81
+ @socket.hostname = endpoint.host
82
+
83
+ debug_output("starting TLS for #{endpoint.host}:#{endpoint.port} ...")
84
+ @socket.connect
85
+ debug_output("TLS established")
86
+ _register_h2_callbacks
87
+ @status = :active
88
+ elsif @status == :closed
89
+ msg = "Async Client HTTP2 Connection is closed, you may"\
90
+ " use #new_connection to create a new HTTP2 Connection for this client"
91
+ raise Http2ConnectionClosedError.new(msg)
92
+ end
93
+ }
94
+ end
95
+
96
+ def start(stream)
97
+ @mutex.synchronize {
98
+ return if @socket_thread
99
+ @socket_thread = Thread.new do
100
+ while !@socket.closed?
101
+ begin
102
+ data = @socket.read_nonblock(@chunk_size)
103
+ @h2_client << data
104
+ rescue IO::WaitReadable
105
+ begin
106
+ unless IO.select([@socket], nil, nil, connection_read_timeout)
107
+ self.debug_output("socket connection read time out")
108
+ self.close!
109
+ else
110
+ # available, retry to start reading
111
+ retry
112
+ end
113
+ rescue
114
+ # error can happen when closing the socket
115
+ # while it's waiting for read
116
+ self.close!
117
+ end
118
+ rescue EOFError
119
+ self.close!
120
+ rescue => error
121
+ self.debug_output(error.inspect)
122
+ @errors << error
123
+ self.close!
124
+ end
125
+ end
126
+ end
127
+ @socket_thread.abort_on_exception = true
128
+ }
129
+ end
130
+
131
+ def close!
132
+ @mutex.synchronize {
133
+ self.debug_output("closing connection ...")
134
+ if @socket
135
+ @socket.close
136
+ @socket = nil
137
+ end
138
+ if @socket_thread
139
+ Thread.kill(@socket_thread)
140
+ @socket_thread = nil
141
+ end
142
+ @status = :closed
143
+ }
144
+ end
145
+
146
+ def closed?
147
+ @status == :closed
148
+ end
149
+
150
+ def debug_output(msg, type = nil)
151
+ prefix = case type
152
+ when :send then "-> "
153
+ when :receive then "<- "
154
+ else
155
+ ""
156
+ end
157
+ return unless @logger
158
+ _debug_entry(prefix + msg)
159
+ end
160
+
161
+ private
162
+
163
+ def _debug_entry(str)
164
+ @logger << str
165
+ @logger << "\n"
166
+ end
167
+
168
+ def _register_h2_callbacks
169
+ @h2_client.on(:frame) do |bytes|
170
+ if @socket.nil?
171
+ msg = "Connection is closed due to errors, "\
172
+ "you can find errors at async_client.connection.errors"
173
+ raise Http2ConnectionClosedError.new(msg)
174
+ else
175
+ @socket.print(bytes)
176
+ @socket.flush
177
+ end
178
+ end
179
+ @h2_client.on(:frame_sent) do |frame|
180
+ debug_output("frame: #{frame.inspect}", :send)
181
+ end
182
+ @h2_client.on(:frame_received) do |frame|
183
+ debug_output("frame: #{frame.inspect}", :receive)
184
+ end
185
+ end
186
+
187
+ def _tcp_socket(endpoint)
188
+ tcp = ::Socket.new(SOCKET_FAMILY, ::Socket::SOCK_STREAM, 0)
189
+ tcp.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
190
+
191
+ address = ::Socket.getaddrinfo(endpoint.host, nil, SOCKET_FAMILY).first[3]
192
+ sockaddr = ::Socket.sockaddr_in(endpoint.port, address)
193
+
194
+ [tcp, sockaddr]
195
+ end
196
+
197
+ def _nonblocking_connect(tcp, addr)
198
+ begin
199
+ tcp.connect_nonblock(addr)
200
+ rescue IO::WaitWritable
201
+ unless IO.select(nil, [tcp], nil, connection_timeout)
202
+ tcp.close
203
+ raise
204
+ end
205
+ begin
206
+ tcp.connect_nonblock(addr)
207
+ rescue Errno::EISCONN
208
+ # tcp socket connected, continue
209
+ end
210
+ end
211
+ end
212
+
213
+ def _tls_context
214
+ ssl_ctx = OpenSSL::SSL::SSLContext.new(:TLSv1_2)
215
+ if ssl_verify_peer?
216
+ ssl_ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
217
+ ssl_ctx.ca_file = ssl_ca_bundle ? ssl_ca_bundle : _default_ca_bundle
218
+ ssl_ctx.ca_path = ssl_ca_directory ? ssl_ca_directory : _default_ca_directory
219
+ ssl_ctx.cert_store = ssl_ca_store if ssl_ca_store
220
+ else
221
+ ssl_ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
222
+ end
223
+ if enable_alpn
224
+ debug_output("enabling ALPN for TLS ...")
225
+ ssl_ctx.alpn_protocols = ['h2']
226
+ end
227
+ ssl_ctx
228
+ end
229
+
230
+ def _default_ca_bundle
231
+ File.exist?(OpenSSL::X509::DEFAULT_CERT_FILE) ?
232
+ OpenSSL::X509::DEFAULT_CERT_FILE : nil
233
+ end
234
+
235
+ def _default_ca_directory
236
+ Dir.exist?(OpenSSL::X509::DEFAULT_CERT_DIR) ?
237
+ OpenSSL::X509::DEFAULT_CERT_DIR : nil
238
+ end
239
+
240
+ end
241
+ end
242
+ end
243
+ end
244
+
@@ -0,0 +1,151 @@
1
+ if RUBY_VERSION >= '2.1'
2
+ begin
3
+ require 'http/2'
4
+ rescue LoadError; end
5
+ end
6
+ require 'securerandom'
7
+
8
+ module Seahorse
9
+ module Client
10
+ # @api private
11
+ module H2
12
+
13
+ NETWORK_ERRORS = [
14
+ SocketError, EOFError, IOError, Timeout::Error,
15
+ Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE,
16
+ Errno::EINVAL, Errno::ETIMEDOUT, OpenSSL::SSL::SSLError,
17
+ Errno::EHOSTUNREACH, Errno::ECONNREFUSED,# OpenSSL::SSL::SSLErrorWaitReadable
18
+ ]
19
+
20
+ # @api private
21
+ DNS_ERROR_MESSAGES = [
22
+ 'getaddrinfo: nodename nor servname provided, or not known', # MacOS
23
+ 'getaddrinfo: Name or service not known' # GNU
24
+ ]
25
+
26
+ class Handler < Client::Handler
27
+
28
+ def call(context)
29
+ stream = nil
30
+ begin
31
+ conn = context.client.connection
32
+ stream = conn.new_stream
33
+
34
+ stream_mutex = Mutex.new
35
+ close_condition = ConditionVariable.new
36
+ sync_queue = Queue.new
37
+
38
+ conn.connect(context.http_request.endpoint)
39
+ _register_callbacks(
40
+ context.http_response,
41
+ stream,
42
+ stream_mutex,
43
+ close_condition,
44
+ sync_queue
45
+ )
46
+
47
+ conn.debug_output("sending initial request ...")
48
+ if input_emitter = context[:input_event_emitter]
49
+ _send_initial_headers(context.http_request, stream)
50
+
51
+ # prepare for sending events later
52
+ input_emitter.stream = stream
53
+ # request sigv4 serves as the initial #prior_signature
54
+ input_emitter.encoder.prior_signature =
55
+ context.http_request.headers['authorization'].split('Signature=').last
56
+ input_emitter.validate_event = context.config.validate_params
57
+ else
58
+ _send_initial_headers(context.http_request, stream)
59
+ _send_initial_data(context.http_request, stream)
60
+ end
61
+
62
+ conn.start(stream)
63
+ rescue *NETWORK_ERRORS => error
64
+ error = NetworkingError.new(
65
+ error, error_message(context.http_request, error))
66
+ context.http_response.signal_error(error)
67
+ rescue => error
68
+ conn.debug_output(error.inspect)
69
+ # not retryable
70
+ context.http_response.signal_error(error)
71
+ end
72
+
73
+ AsyncResponse.new(
74
+ context: context,
75
+ stream: stream,
76
+ stream_mutex: stream_mutex,
77
+ close_condition: close_condition,
78
+ sync_queue: sync_queue
79
+ )
80
+ end
81
+
82
+ private
83
+
84
+ def _register_callbacks(resp, stream, stream_mutex, close_condition, sync_queue)
85
+ stream.on(:headers) do |headers|
86
+ resp.signal_headers(headers)
87
+ end
88
+
89
+ stream.on(:data) do |data|
90
+ resp.signal_data(data)
91
+ end
92
+
93
+ stream.on(:close) do
94
+ resp.signal_done
95
+ # block until #wait is ready for signal
96
+ # else deadlock may happen because #signal happened
97
+ # eariler than #wait (see AsyncResponse#wait)
98
+ sync_queue.pop
99
+ stream_mutex.synchronize {
100
+ close_condition.signal
101
+ }
102
+ end
103
+ end
104
+
105
+ def _send_initial_headers(req, stream)
106
+ begin
107
+ headers = _h2_headers(req)
108
+ stream.headers(headers, end_stream: false)
109
+ rescue => e
110
+ raise Http2InitialRequestError.new(e)
111
+ end
112
+ end
113
+
114
+ def _send_initial_data(req, stream)
115
+ begin
116
+ data = req.body.read
117
+ stream.data(data, end_stream: true)
118
+ rescue => e
119
+ raise Http2InitialRequestError.new(e)
120
+ end
121
+ data
122
+ end
123
+
124
+ # H2 pseudo headers
125
+ # https://http2.github.io/http2-spec/#rfc.section.8.1.2.3
126
+ def _h2_headers(req)
127
+ headers = {}
128
+ headers[':method'] = req.http_method.upcase
129
+ headers[':scheme'] = req.endpoint.scheme
130
+ headers[':path'] = req.endpoint.path.empty? ? '/' : req.endpoint.path
131
+ if req.endpoint.query && !req.endpoint.query.empty?
132
+ headers[':path'] += "?#{req.endpoint.query}"
133
+ end
134
+ req.headers.each {|k, v| headers[k.downcase] = v }
135
+ headers
136
+ end
137
+
138
+ def error_message(req, error)
139
+ if error.is_a?(SocketError) && DNS_ERROR_MESSAGES.include?(error.message)
140
+ host = req.endpoint.host
141
+ "unable to connect to `#{host}`; SocketError: #{error.message}"
142
+ else
143
+ error.message
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,42 @@
1
+ module Seahorse
2
+ module Client
3
+ module Http
4
+ class AsyncResponse < Seahorse::Client::Http::Response
5
+
6
+ def initialize(options = {})
7
+ super
8
+ end
9
+
10
+ def signal_headers(headers)
11
+ # H2 headers arrive as array of pair
12
+ hash = headers.inject({}) do |h, pair|
13
+ key, value = pair
14
+ h[key] = value
15
+ h
16
+ end
17
+ @status_code = hash[":status"].to_i
18
+ @headers = Headers.new(hash)
19
+ emit(:headers, @status_code, @headers)
20
+ end
21
+
22
+ def signal_done(options = {})
23
+ # H2 only has header and body
24
+ # ':status' header will be sent back
25
+ if options.keys.sort == [:body, :headers]
26
+ signal_headers(options[:headers])
27
+ signal_data(options[:body])
28
+ signal_done
29
+ elsif options.empty?
30
+ @body.rewind if @body.respond_to?(:rewind)
31
+ @done = true
32
+ emit(:done)
33
+ else
34
+ msg = "options must be empty or must contain :headers and :body"
35
+ raise ArgumentError, msg
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -40,12 +40,17 @@ module Seahorse
40
40
  end
41
41
  end
42
42
 
43
- # @return [String]
43
+ # @return [String|Array]
44
44
  def body_contents
45
- body.rewind
46
- contents = body.read
47
- body.rewind
48
- contents
45
+ if body.is_a?(Array)
46
+ # an array of parsed events
47
+ body
48
+ else
49
+ body.rewind
50
+ contents = body.read
51
+ body.rewind
52
+ contents
53
+ end
49
54
  end
50
55
 
51
56
  # @param [Integer] status_code
@@ -117,15 +122,15 @@ module Seahorse
117
122
  end
118
123
 
119
124
  def on_headers(status_code_range = nil, &block)
120
- @listeners[:headers] << listener(status_code_range, Proc.new)
125
+ @listeners[:headers] << listener(status_code_range, block)
121
126
  end
122
127
 
123
128
  def on_data(&callback)
124
- @listeners[:data] << Proc.new
129
+ @listeners[:data] << callback
125
130
  end
126
131
 
127
132
  def on_done(status_code_range = nil, &callback)
128
- listener = listener(status_code_range, Proc.new)
133
+ listener = listener(status_code_range, callback)
129
134
  if @done
130
135
  listener.call
131
136
  else
@@ -10,6 +10,12 @@ module Seahorse
10
10
 
11
11
  def self.apply!
12
12
  return unless RUBY_VERSION < '2.5'
13
+ if RUBY_VERSION >= '2.3'
14
+ Net::HTTP::IDEMPOTENT_METHODS_.clear
15
+ return
16
+ end
17
+ # no further patches needed for above versions
18
+
13
19
  if RUBY_VERSION >= '2.0'
14
20
  Net::HTTP.send(:include, Ruby_2)
15
21
  Net::HTTP::IDEMPOTENT_METHODS_.clear
@@ -30,7 +36,7 @@ module Seahorse
30
36
  begin
31
37
  res = Net::HTTPResponse.read_new(@socket)
32
38
  res.decode_content = req.decode_content
33
- end while res.kind_of?(Net::HTTPContinue)
39
+ end while res.kind_of?(Net::HTTPInformation)
34
40
 
35
41
  res.uri = req.uri
36
42
 
@@ -11,5 +11,33 @@ module Seahorse
11
11
  attr_reader :original_error
12
12
 
13
13
  end
14
+
15
+ # Raised when sending initial headers and data failed
16
+ # for event stream requests over Http2
17
+ class Http2InitialRequestError < StandardError
18
+
19
+ def initialize(error)
20
+ @original_error = error
21
+ end
22
+
23
+ # @return [HTTP2::Error]
24
+ attr_reader :original_error
25
+
26
+ end
27
+
28
+ # Raised when connection failed to initialize a new stream
29
+ class Http2StreamInitializeError < StandardError
30
+
31
+ def initialize(error)
32
+ @original_error = error
33
+ end
34
+
35
+ # @return [HTTP2::Error]
36
+ attr_reader :original_error
37
+
38
+ end
39
+
40
+ # Rasied when trying to use an closed connection
41
+ class Http2ConnectionClosedError < StandardError; end
14
42
  end
15
43
  end