httpx 0.12.0 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/doc/release_notes/0_10_1.md +1 -1
- data/doc/release_notes/0_13_0.md +58 -0
- data/doc/release_notes/0_13_1.md +5 -0
- data/doc/release_notes/0_13_2.md +9 -0
- data/doc/release_notes/0_14_0.md +79 -0
- data/doc/release_notes/0_14_1.md +7 -0
- data/lib/httpx.rb +1 -2
- data/lib/httpx/callbacks.rb +12 -3
- data/lib/httpx/chainable.rb +2 -2
- data/lib/httpx/connection.rb +29 -22
- data/lib/httpx/connection/http1.rb +35 -15
- data/lib/httpx/connection/http2.rb +61 -15
- data/lib/httpx/headers.rb +7 -3
- data/lib/httpx/io/ssl.rb +30 -17
- data/lib/httpx/io/tcp.rb +48 -27
- data/lib/httpx/io/udp.rb +31 -7
- data/lib/httpx/io/unix.rb +27 -12
- data/lib/httpx/options.rb +97 -74
- data/lib/httpx/plugins/aws_sdk_authentication.rb +5 -2
- data/lib/httpx/plugins/aws_sigv4.rb +5 -4
- data/lib/httpx/plugins/basic_authentication.rb +8 -3
- data/lib/httpx/plugins/compression.rb +24 -12
- data/lib/httpx/plugins/compression/brotli.rb +10 -7
- data/lib/httpx/plugins/compression/deflate.rb +6 -5
- data/lib/httpx/plugins/compression/gzip.rb +4 -3
- data/lib/httpx/plugins/cookies.rb +3 -7
- data/lib/httpx/plugins/digest_authentication.rb +5 -5
- data/lib/httpx/plugins/expect.rb +6 -6
- data/lib/httpx/plugins/follow_redirects.rb +4 -4
- data/lib/httpx/plugins/grpc.rb +247 -0
- data/lib/httpx/plugins/grpc/call.rb +62 -0
- data/lib/httpx/plugins/grpc/message.rb +85 -0
- data/lib/httpx/plugins/h2c.rb +43 -58
- data/lib/httpx/plugins/internal_telemetry.rb +1 -1
- data/lib/httpx/plugins/multipart/part.rb +2 -2
- data/lib/httpx/plugins/proxy.rb +3 -7
- data/lib/httpx/plugins/proxy/http.rb +5 -4
- data/lib/httpx/plugins/proxy/ssh.rb +3 -3
- data/lib/httpx/plugins/rate_limiter.rb +1 -1
- data/lib/httpx/plugins/retries.rb +14 -15
- data/lib/httpx/plugins/stream.rb +99 -75
- data/lib/httpx/plugins/upgrade.rb +84 -0
- data/lib/httpx/plugins/upgrade/h2.rb +54 -0
- data/lib/httpx/pool.rb +14 -5
- data/lib/httpx/request.rb +25 -2
- data/lib/httpx/resolver/native.rb +7 -3
- data/lib/httpx/response.rb +9 -5
- data/lib/httpx/session.rb +17 -7
- data/lib/httpx/transcoder/chunker.rb +1 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/callbacks.rbs +2 -0
- data/sig/chainable.rbs +2 -1
- data/sig/connection/http1.rbs +6 -1
- data/sig/connection/http2.rbs +6 -2
- data/sig/headers.rbs +2 -2
- data/sig/options.rbs +16 -22
- data/sig/plugins/aws_sdk_authentication.rbs +2 -0
- data/sig/plugins/aws_sigv4.rbs +0 -1
- data/sig/plugins/basic_authentication.rbs +2 -0
- data/sig/plugins/compression.rbs +7 -5
- data/sig/plugins/compression/brotli.rbs +1 -1
- data/sig/plugins/compression/deflate.rbs +1 -1
- data/sig/plugins/compression/gzip.rbs +1 -1
- data/sig/plugins/cookies.rbs +0 -1
- data/sig/plugins/digest_authentication.rbs +0 -1
- data/sig/plugins/expect.rbs +0 -2
- data/sig/plugins/follow_redirects.rbs +0 -2
- data/sig/plugins/h2c.rbs +5 -10
- data/sig/plugins/persistent.rbs +0 -1
- data/sig/plugins/proxy.rbs +0 -1
- data/sig/plugins/retries.rbs +0 -4
- data/sig/plugins/stream.rbs +17 -16
- data/sig/plugins/upgrade.rbs +23 -0
- data/sig/request.rbs +7 -2
- data/sig/response.rbs +4 -1
- data/sig/session.rbs +4 -0
- metadata +21 -7
- data/lib/httpx/timeout.rb +0 -67
- data/sig/timeout.rbs +0 -29
@@ -21,14 +21,16 @@ module HTTPX
|
|
21
21
|
|
22
22
|
def initialize(buffer, options)
|
23
23
|
@options = Options.new(options)
|
24
|
-
@
|
25
|
-
@max_requests = @options.max_requests || 0
|
24
|
+
@settings = @options.http2_settings
|
26
25
|
@pending = []
|
27
26
|
@streams = {}
|
28
27
|
@drains = {}
|
29
28
|
@pings = []
|
30
29
|
@buffer = buffer
|
31
30
|
@handshake_completed = false
|
31
|
+
@wait_for_handshake = @settings.key?(:wait_for_handshake) ? @settings.delete(:wait_for_handshake) : true
|
32
|
+
@max_concurrent_requests = @options.max_concurrent_requests || MAX_CONCURRENT_REQUESTS
|
33
|
+
@max_requests = @options.max_requests || 0
|
32
34
|
init_connection
|
33
35
|
end
|
34
36
|
|
@@ -36,7 +38,11 @@ module HTTPX
|
|
36
38
|
# waiting for WINDOW_UPDATE frames
|
37
39
|
return :r if @buffer.full?
|
38
40
|
|
39
|
-
|
41
|
+
if @connection.state == :closed
|
42
|
+
return unless @handshake_completed
|
43
|
+
|
44
|
+
return :w
|
45
|
+
end
|
40
46
|
|
41
47
|
unless (@connection.state == :connected && @handshake_completed)
|
42
48
|
return @buffer.empty? ? :r : :rw
|
@@ -75,9 +81,13 @@ module HTTPX
|
|
75
81
|
end
|
76
82
|
|
77
83
|
def can_buffer_more_requests?
|
78
|
-
@handshake_completed
|
84
|
+
if @handshake_completed
|
79
85
|
@streams.size < @max_concurrent_requests &&
|
80
|
-
|
86
|
+
@streams.size < @max_requests
|
87
|
+
else
|
88
|
+
!@wait_for_handshake &&
|
89
|
+
@streams.size < @max_concurrent_requests
|
90
|
+
end
|
81
91
|
end
|
82
92
|
|
83
93
|
def send(request)
|
@@ -91,7 +101,6 @@ module HTTPX
|
|
91
101
|
@streams[request] = stream
|
92
102
|
@max_requests -= 1
|
93
103
|
end
|
94
|
-
request.once(:headers, &method(:set_protocol_headers))
|
95
104
|
handle(request, stream)
|
96
105
|
true
|
97
106
|
rescue HTTP2Next::Error::StreamLimitExceeded
|
@@ -141,12 +150,14 @@ module HTTPX
|
|
141
150
|
join_headers(stream, request) if request.state == :headers
|
142
151
|
request.transition(:body)
|
143
152
|
join_body(stream, request) if request.state == :body
|
153
|
+
request.transition(:trailers)
|
154
|
+
join_trailers(stream, request) if request.state == :trailers && !request.body.empty?
|
144
155
|
request.transition(:done)
|
145
156
|
end
|
146
157
|
end
|
147
158
|
|
148
159
|
def init_connection
|
149
|
-
@connection = HTTP2Next::Client.new(@
|
160
|
+
@connection = HTTP2Next::Client.new(@settings)
|
150
161
|
@connection.max_streams = @max_requests if @connection.respond_to?(:max_streams=) && @max_requests.positive?
|
151
162
|
@connection.on(:frame, &method(:on_frame))
|
152
163
|
@connection.on(:frame_sent, &method(:on_frame_sent))
|
@@ -170,6 +181,7 @@ module HTTPX
|
|
170
181
|
public :reset
|
171
182
|
|
172
183
|
def handle_stream(stream, request)
|
184
|
+
request.on(:refuse, &method(:on_stream_refuse).curry(3)[stream, request])
|
173
185
|
stream.on(:close, &method(:on_stream_close).curry(3)[stream, request])
|
174
186
|
stream.on(:half_close) do
|
175
187
|
log(level: 2) { "#{stream.id}: waiting for response..." }
|
@@ -180,17 +192,32 @@ module HTTPX
|
|
180
192
|
end
|
181
193
|
|
182
194
|
def set_protocol_headers(request)
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
195
|
+
{
|
196
|
+
":scheme" => request.scheme,
|
197
|
+
":method" => request.verb.to_s.upcase,
|
198
|
+
":path" => headline_uri(request),
|
199
|
+
":authority" => request.authority,
|
200
|
+
}
|
187
201
|
end
|
188
202
|
|
189
203
|
def join_headers(stream, request)
|
204
|
+
extra_headers = set_protocol_headers(request)
|
205
|
+
log(level: 1, color: :yellow) do
|
206
|
+
request.headers.merge(extra_headers).each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{v}" }.join("\n")
|
207
|
+
end
|
208
|
+
stream.headers(request.headers.each(extra_headers), end_stream: request.empty?)
|
209
|
+
end
|
210
|
+
|
211
|
+
def join_trailers(stream, request)
|
212
|
+
unless request.trailers?
|
213
|
+
stream.data("", end_stream: true) if request.callbacks_for?(:trailers)
|
214
|
+
return
|
215
|
+
end
|
216
|
+
|
190
217
|
log(level: 1, color: :yellow) do
|
191
|
-
request.
|
218
|
+
request.trailers.each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{v}" }.join("\n")
|
192
219
|
end
|
193
|
-
stream.headers(request.
|
220
|
+
stream.headers(request.trailers.each, end_stream: true)
|
194
221
|
end
|
195
222
|
|
196
223
|
def join_body(stream, request)
|
@@ -201,13 +228,15 @@ module HTTPX
|
|
201
228
|
next_chunk = request.drain_body
|
202
229
|
log(level: 1, color: :green) { "#{stream.id}: -> DATA: #{chunk.bytesize} bytes..." }
|
203
230
|
log(level: 2, color: :green) { "#{stream.id}: -> #{chunk.inspect}" }
|
204
|
-
stream.data(chunk, end_stream: !next_chunk)
|
205
|
-
if next_chunk && @buffer.full?
|
231
|
+
stream.data(chunk, end_stream: !(next_chunk || request.trailers? || request.callbacks_for?(:trailers)))
|
232
|
+
if next_chunk && (@buffer.full? || request.body.unbounded_body?)
|
206
233
|
@drains[request] = next_chunk
|
207
234
|
throw(:buffer_full)
|
208
235
|
end
|
209
236
|
chunk = next_chunk
|
210
237
|
end
|
238
|
+
|
239
|
+
on_stream_refuse(stream, request, request.drain_error) if request.drain_error
|
211
240
|
end
|
212
241
|
|
213
242
|
######
|
@@ -215,6 +244,11 @@ module HTTPX
|
|
215
244
|
######
|
216
245
|
|
217
246
|
def on_stream_headers(stream, request, h)
|
247
|
+
if request.response && request.response.version == "2.0"
|
248
|
+
on_stream_trailers(stream, request, h)
|
249
|
+
return
|
250
|
+
end
|
251
|
+
|
218
252
|
log(color: :yellow) do
|
219
253
|
h.map { |k, v| "#{stream.id}: <- HEADER: #{k}: #{v}" }.join("\n")
|
220
254
|
end
|
@@ -227,12 +261,24 @@ module HTTPX
|
|
227
261
|
handle(request, stream) if request.expects?
|
228
262
|
end
|
229
263
|
|
264
|
+
def on_stream_trailers(stream, request, h)
|
265
|
+
log(color: :yellow) do
|
266
|
+
h.map { |k, v| "#{stream.id}: <- HEADER: #{k}: #{v}" }.join("\n")
|
267
|
+
end
|
268
|
+
request.response.merge_headers(h)
|
269
|
+
end
|
270
|
+
|
230
271
|
def on_stream_data(stream, request, data)
|
231
272
|
log(level: 1, color: :green) { "#{stream.id}: <- DATA: #{data.bytesize} bytes..." }
|
232
273
|
log(level: 2, color: :green) { "#{stream.id}: <- #{data.inspect}" }
|
233
274
|
request.response << data
|
234
275
|
end
|
235
276
|
|
277
|
+
def on_stream_refuse(stream, request, error)
|
278
|
+
stream.close
|
279
|
+
on_stream_close(stream, request, error)
|
280
|
+
end
|
281
|
+
|
236
282
|
def on_stream_close(stream, request, error)
|
237
283
|
log(level: 2) { "#{stream.id}: closing stream" }
|
238
284
|
@drains.delete(request)
|
data/lib/httpx/headers.rb
CHANGED
@@ -103,16 +103,20 @@ module HTTPX
|
|
103
103
|
# returns the enumerable headers store in pairs of header field + the values in
|
104
104
|
# the comma-separated string format
|
105
105
|
#
|
106
|
-
def each
|
107
|
-
return enum_for(__method__) { @headers.size } unless block_given?
|
106
|
+
def each(extra_headers = nil)
|
107
|
+
return enum_for(__method__, extra_headers) { @headers.size } unless block_given?
|
108
108
|
|
109
109
|
@headers.each do |field, value|
|
110
110
|
yield(field, value.join(", ")) unless value.empty?
|
111
111
|
end
|
112
|
+
|
113
|
+
extra_headers.each do |field, value|
|
114
|
+
yield(field, value) unless value.empty?
|
115
|
+
end if extra_headers
|
112
116
|
end
|
113
117
|
|
114
118
|
def ==(other)
|
115
|
-
|
119
|
+
other == to_hash
|
116
120
|
end
|
117
121
|
|
118
122
|
# the headers store in Hash format
|
data/lib/httpx/io/ssl.rb
CHANGED
@@ -47,10 +47,6 @@ module HTTPX
|
|
47
47
|
|
48
48
|
def connect
|
49
49
|
super
|
50
|
-
if @keep_open
|
51
|
-
@state = :negotiated
|
52
|
-
return
|
53
|
-
end
|
54
50
|
return if @state == :negotiated ||
|
55
51
|
@state != :connected
|
56
52
|
|
@@ -59,17 +55,22 @@ module HTTPX
|
|
59
55
|
@io.hostname = @sni_hostname
|
60
56
|
@io.sync_close = true
|
61
57
|
end
|
62
|
-
|
63
|
-
@io.post_connection_check(@sni_hostname) if @ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
64
|
-
transition(:negotiated)
|
65
|
-
@interests = :w
|
66
|
-
rescue ::IO::WaitReadable
|
67
|
-
@interests = :r
|
68
|
-
rescue ::IO::WaitWritable
|
69
|
-
@interests = :w
|
58
|
+
try_ssl_connect
|
70
59
|
end
|
71
60
|
|
72
61
|
if RUBY_VERSION < "2.3"
|
62
|
+
# :nocov:
|
63
|
+
def try_ssl_connect
|
64
|
+
@io.connect_nonblock
|
65
|
+
@io.post_connection_check(@sni_hostname) if @ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
66
|
+
transition(:negotiated)
|
67
|
+
@interests = :w
|
68
|
+
rescue ::IO::WaitReadable
|
69
|
+
@interests = :r
|
70
|
+
rescue ::IO::WaitWritable
|
71
|
+
@interests = :w
|
72
|
+
end
|
73
|
+
|
73
74
|
def read(_, buffer)
|
74
75
|
super
|
75
76
|
rescue ::IO::WaitWritable
|
@@ -82,7 +83,23 @@ module HTTPX
|
|
82
83
|
rescue ::IO::WaitReadable
|
83
84
|
0
|
84
85
|
end
|
86
|
+
# :nocov:
|
85
87
|
else
|
88
|
+
def try_ssl_connect
|
89
|
+
case @io.connect_nonblock(exception: false)
|
90
|
+
when :wait_readable
|
91
|
+
@interests = :r
|
92
|
+
return
|
93
|
+
when :wait_writable
|
94
|
+
@interests = :w
|
95
|
+
return
|
96
|
+
end
|
97
|
+
@io.post_connection_check(@sni_hostname) if @ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
98
|
+
transition(:negotiated)
|
99
|
+
@interests = :w
|
100
|
+
end
|
101
|
+
|
102
|
+
# :nocov:
|
86
103
|
if OpenSSL::VERSION < "2.0.6"
|
87
104
|
def read(size, buffer)
|
88
105
|
@io.read_nonblock(size, buffer)
|
@@ -95,11 +112,7 @@ module HTTPX
|
|
95
112
|
nil
|
96
113
|
end
|
97
114
|
end
|
98
|
-
|
99
|
-
|
100
|
-
def inspect
|
101
|
-
id = @io.closed? ? "closed" : @io.to_io.fileno
|
102
|
-
"#<SSL(fd: #{id}): #{@ip}:#{@port} state: #{@state}>"
|
115
|
+
# :nocov:
|
103
116
|
end
|
104
117
|
|
105
118
|
private
|
data/lib/httpx/io/tcp.rb
CHANGED
@@ -7,6 +7,8 @@ module HTTPX
|
|
7
7
|
class TCP
|
8
8
|
include Loggable
|
9
9
|
|
10
|
+
using URIExtensions
|
11
|
+
|
10
12
|
attr_reader :ip, :port, :addresses, :state, :interests
|
11
13
|
|
12
14
|
alias_method :host, :ip
|
@@ -14,7 +16,6 @@ module HTTPX
|
|
14
16
|
def initialize(origin, addresses, options)
|
15
17
|
@state = :idle
|
16
18
|
@hostname = origin.host
|
17
|
-
@addresses = addresses
|
18
19
|
@options = Options.new(options)
|
19
20
|
@fallback_protocol = @options.fallback_protocol
|
20
21
|
@port = origin.port
|
@@ -26,17 +27,17 @@ module HTTPX
|
|
26
27
|
else
|
27
28
|
@options.io
|
28
29
|
end
|
30
|
+
raise Error, "Given IO objects do not match the request authority" unless @io
|
31
|
+
|
29
32
|
_, _, _, @ip = @io.addr
|
30
33
|
@addresses ||= [@ip]
|
31
34
|
@ip_index = @addresses.size - 1
|
32
|
-
|
33
|
-
|
34
|
-
@state = :connected
|
35
|
-
end
|
35
|
+
@keep_open = true
|
36
|
+
@state = :connected
|
36
37
|
else
|
37
|
-
@
|
38
|
-
@ip = @addresses[@ip_index]
|
38
|
+
@addresses = addresses.map { |addr| addr.is_a?(IPAddr) ? addr : IPAddr.new(addr) }
|
39
39
|
end
|
40
|
+
@ip_index = @addresses.size - 1
|
40
41
|
@io ||= build_socket
|
41
42
|
end
|
42
43
|
|
@@ -51,36 +52,40 @@ module HTTPX
|
|
51
52
|
def connect
|
52
53
|
return unless closed?
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
@io = build_socket
|
58
|
-
end
|
59
|
-
@io.connect_nonblock(Socket.sockaddr_in(@port, @ip.to_s))
|
60
|
-
rescue Errno::EISCONN
|
55
|
+
if @io.closed?
|
56
|
+
transition(:idle)
|
57
|
+
@io = build_socket
|
61
58
|
end
|
62
|
-
|
63
|
-
|
64
|
-
transition(:connected)
|
59
|
+
try_connect
|
65
60
|
rescue Errno::EHOSTUNREACH => e
|
66
61
|
raise e if @ip_index <= 0
|
67
62
|
|
68
63
|
@ip_index -= 1
|
69
64
|
retry
|
70
65
|
rescue Errno::ETIMEDOUT => e
|
71
|
-
raise ConnectTimeoutError.new(@options.timeout
|
66
|
+
raise ConnectTimeoutError.new(@options.timeout[:connect_timeout], e.message) if @ip_index <= 0
|
72
67
|
|
73
68
|
@ip_index -= 1
|
74
69
|
retry
|
75
|
-
rescue Errno::EINPROGRESS,
|
76
|
-
Errno::EALREADY
|
77
|
-
@interests = :w
|
78
|
-
rescue ::IO::WaitReadable
|
79
|
-
@interests = :r
|
80
70
|
end
|
81
71
|
|
82
72
|
if RUBY_VERSION < "2.3"
|
83
73
|
# :nocov:
|
74
|
+
def try_connect
|
75
|
+
@io.connect_nonblock(Socket.sockaddr_in(@port, @ip.to_s))
|
76
|
+
rescue ::IO::WaitWritable, Errno::EALREADY
|
77
|
+
@interests = :w
|
78
|
+
rescue ::IO::WaitReadable
|
79
|
+
@interests = :r
|
80
|
+
rescue Errno::EISCONN
|
81
|
+
transition(:connected)
|
82
|
+
@interests = :w
|
83
|
+
else
|
84
|
+
transition(:connected)
|
85
|
+
@interests = :w
|
86
|
+
end
|
87
|
+
private :try_connect
|
88
|
+
|
84
89
|
def read(size, buffer)
|
85
90
|
@io.read_nonblock(size, buffer)
|
86
91
|
log { "READ: #{buffer.bytesize} bytes..." }
|
@@ -104,6 +109,22 @@ module HTTPX
|
|
104
109
|
end
|
105
110
|
# :nocov:
|
106
111
|
else
|
112
|
+
def try_connect
|
113
|
+
case @io.connect_nonblock(Socket.sockaddr_in(@port, @ip.to_s), exception: false)
|
114
|
+
when :wait_readable
|
115
|
+
@interests = :r
|
116
|
+
return
|
117
|
+
when :wait_writable
|
118
|
+
@interests = :w
|
119
|
+
return
|
120
|
+
end
|
121
|
+
transition(:connected)
|
122
|
+
@interests = :w
|
123
|
+
rescue Errno::EALREADY
|
124
|
+
@interests = :w
|
125
|
+
end
|
126
|
+
private :try_connect
|
127
|
+
|
107
128
|
def read(size, buffer)
|
108
129
|
ret = @io.read_nonblock(size, buffer, exception: false)
|
109
130
|
if ret == :wait_readable
|
@@ -148,14 +169,14 @@ module HTTPX
|
|
148
169
|
|
149
170
|
# :nocov:
|
150
171
|
def inspect
|
151
|
-
|
152
|
-
"#<TCP(fd: #{id}): #{@ip}:#{@port} (state: #{@state})>"
|
172
|
+
"#<#{self.class}: #{@ip}:#{@port} (state: #{@state})>"
|
153
173
|
end
|
154
174
|
# :nocov:
|
155
175
|
|
156
176
|
private
|
157
177
|
|
158
178
|
def build_socket
|
179
|
+
@ip = @addresses[@ip_index]
|
159
180
|
Socket.new(@ip.family, :STREAM, 0)
|
160
181
|
end
|
161
182
|
|
@@ -178,9 +199,9 @@ module HTTPX
|
|
178
199
|
def log_transition_state(nextstate)
|
179
200
|
case nextstate
|
180
201
|
when :connected
|
181
|
-
"Connected to #{
|
202
|
+
"Connected to #{host} (##{@io.fileno})"
|
182
203
|
else
|
183
|
-
"#{
|
204
|
+
"#{host} #{@state} -> #{nextstate}"
|
184
205
|
end
|
185
206
|
end
|
186
207
|
end
|
data/lib/httpx/io/udp.rb
CHANGED
@@ -39,16 +39,20 @@ module HTTPX
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
def write(buffer)
|
43
|
-
siz = @io.send(buffer.to_s, 0, @host, @port)
|
44
|
-
log { "WRITE: #{siz} bytes..." }
|
45
|
-
buffer.shift!(siz)
|
46
|
-
siz
|
47
|
-
end
|
48
|
-
|
49
42
|
# :nocov:
|
50
43
|
if (RUBY_ENGINE == "truffleruby" && RUBY_ENGINE_VERSION < "21.1.0") ||
|
51
44
|
RUBY_VERSION < "2.3"
|
45
|
+
def write(buffer)
|
46
|
+
siz = @io.sendmsg_nonblock(buffer.to_s, 0, Socket.sockaddr_in(@port, @host.to_s))
|
47
|
+
log { "WRITE: #{siz} bytes..." }
|
48
|
+
buffer.shift!(siz)
|
49
|
+
siz
|
50
|
+
rescue ::IO::WaitWritable
|
51
|
+
0
|
52
|
+
rescue EOFError
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
52
56
|
def read(size, buffer)
|
53
57
|
data, _ = @io.recvfrom_nonblock(size)
|
54
58
|
buffer.replace(data)
|
@@ -59,6 +63,18 @@ module HTTPX
|
|
59
63
|
rescue IOError
|
60
64
|
end
|
61
65
|
else
|
66
|
+
|
67
|
+
def write(buffer)
|
68
|
+
siz = @io.sendmsg_nonblock(buffer.to_s, 0, Socket.sockaddr_in(@port, @host.to_s), exception: false)
|
69
|
+
return 0 if siz == :wait_writable
|
70
|
+
return if siz.nil?
|
71
|
+
|
72
|
+
log { "WRITE: #{siz} bytes..." }
|
73
|
+
|
74
|
+
buffer.shift!(siz)
|
75
|
+
siz
|
76
|
+
end
|
77
|
+
|
62
78
|
def read(size, buffer)
|
63
79
|
ret = @io.recvfrom_nonblock(size, 0, buffer, exception: false)
|
64
80
|
return 0 if ret == :wait_readable
|
@@ -68,6 +84,14 @@ module HTTPX
|
|
68
84
|
rescue IOError
|
69
85
|
end
|
70
86
|
end
|
87
|
+
|
88
|
+
# In JRuby, sendmsg_nonblock is not implemented
|
89
|
+
def write(buffer)
|
90
|
+
siz = @io.send(buffer.to_s, 0, @host, @port)
|
91
|
+
log { "WRITE: #{siz} bytes..." }
|
92
|
+
buffer.shift!(siz)
|
93
|
+
siz
|
94
|
+
end if RUBY_ENGINE == "jruby"
|
71
95
|
# :nocov:
|
72
96
|
end
|
73
97
|
end
|