httpx 0.11.3 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/doc/release_notes/0_11_1.md +5 -1
- data/doc/release_notes/0_12_0.md +55 -0
- data/lib/httpx.rb +2 -1
- data/lib/httpx/adapters/faraday.rb +4 -6
- data/lib/httpx/altsvc.rb +1 -0
- data/lib/httpx/connection.rb +63 -15
- data/lib/httpx/connection/http1.rb +8 -7
- data/lib/httpx/connection/http2.rb +32 -25
- data/lib/httpx/io.rb +16 -3
- data/lib/httpx/io/ssl.rb +7 -9
- data/lib/httpx/io/tcp.rb +9 -8
- data/lib/httpx/io/tls.rb +218 -0
- data/lib/httpx/io/tls/box.rb +365 -0
- data/lib/httpx/io/tls/context.rb +199 -0
- data/lib/httpx/io/tls/ffi.rb +390 -0
- data/lib/httpx/parser/http1.rb +4 -4
- data/lib/httpx/plugins/aws_sdk_authentication.rb +81 -0
- data/lib/httpx/plugins/aws_sigv4.rb +218 -0
- data/lib/httpx/plugins/compression/deflate.rb +2 -5
- data/lib/httpx/plugins/internal_telemetry.rb +93 -0
- data/lib/httpx/plugins/multipart.rb +2 -0
- data/lib/httpx/plugins/multipart/encoder.rb +4 -9
- data/lib/httpx/plugins/proxy.rb +1 -1
- data/lib/httpx/plugins/proxy/http.rb +1 -1
- data/lib/httpx/plugins/proxy/socks4.rb +8 -0
- data/lib/httpx/plugins/proxy/socks5.rb +8 -0
- data/lib/httpx/plugins/push_promise.rb +3 -2
- data/lib/httpx/plugins/retries.rb +1 -1
- data/lib/httpx/plugins/stream.rb +3 -5
- data/lib/httpx/pool.rb +0 -1
- data/lib/httpx/registry.rb +1 -7
- data/lib/httpx/request.rb +11 -1
- data/lib/httpx/resolver/https.rb +3 -11
- data/lib/httpx/response.rb +9 -2
- data/lib/httpx/selector.rb +5 -0
- data/lib/httpx/session.rb +25 -2
- data/lib/httpx/transcoder/body.rb +3 -5
- data/lib/httpx/version.rb +1 -1
- data/sig/connection/http1.rbs +2 -2
- data/sig/connection/http2.rbs +5 -3
- data/sig/plugins/aws_sdk_authentication.rbs +17 -0
- data/sig/plugins/aws_sigv4.rbs +65 -0
- data/sig/plugins/push_promise.rbs +1 -1
- metadata +13 -2
@@ -29,18 +29,13 @@ module HTTPX::Plugins
|
|
29
29
|
|
30
30
|
def rewind
|
31
31
|
form = @form.each_with_object([]) do |(key, val), aux|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
val.rewind
|
36
|
-
val
|
37
|
-
else
|
38
|
-
v
|
39
|
-
end
|
40
|
-
aux << [key, v]
|
32
|
+
val = val.reopen(val.path, File::RDONLY) if val.is_a?(File) && val.closed?
|
33
|
+
val.rewind if val.respond_to?(:rewind)
|
34
|
+
aux << [key, val]
|
41
35
|
end
|
42
36
|
@form = form
|
43
37
|
@parts = to_parts(form)
|
38
|
+
@part_index = 0
|
44
39
|
end
|
45
40
|
|
46
41
|
private
|
data/lib/httpx/plugins/proxy.rb
CHANGED
@@ -81,7 +81,7 @@ module HTTPX
|
|
81
81
|
request.uri.to_s
|
82
82
|
end
|
83
83
|
|
84
|
-
def
|
84
|
+
def set_protocol_headers(request)
|
85
85
|
super
|
86
86
|
proxy_params = @options.proxy
|
87
87
|
request.headers["proxy-authorization"] = "Basic #{proxy_params.token_authentication}" if proxy_params.authenticated?
|
@@ -35,6 +35,14 @@ module HTTPX
|
|
35
35
|
super || @state == :authenticating || @state == :negotiating
|
36
36
|
end
|
37
37
|
|
38
|
+
def interests
|
39
|
+
if @state == :connecting || @state == :authenticating || @state == :negotiating
|
40
|
+
return @write_buffer.empty? ? :r : :w
|
41
|
+
end
|
42
|
+
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
38
46
|
private
|
39
47
|
|
40
48
|
def transition(nextstate)
|
@@ -43,7 +43,7 @@ module HTTPX
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def __on_promise_request(parser, stream, h)
|
46
|
-
log(level: 1) do
|
46
|
+
log(level: 1, color: :yellow) do
|
47
47
|
# :nocov:
|
48
48
|
h.map { |k, v| "#{stream.id}: -> PROMISE HEADER: #{k}: #{v}" }.join("\n")
|
49
49
|
# :nocov:
|
@@ -57,6 +57,8 @@ module HTTPX
|
|
57
57
|
request.merge_headers(headers)
|
58
58
|
promise_headers[stream] = request
|
59
59
|
parser.pending.delete(request)
|
60
|
+
parser.streams[request] = stream
|
61
|
+
request.transition(:done)
|
60
62
|
else
|
61
63
|
stream.refuse
|
62
64
|
end
|
@@ -67,7 +69,6 @@ module HTTPX
|
|
67
69
|
return unless request
|
68
70
|
|
69
71
|
parser.__send__(:on_stream_headers, stream, request, h)
|
70
|
-
request.transition(:done)
|
71
72
|
response = request.response
|
72
73
|
response.mark_as_pushed!
|
73
74
|
stream.on(:data, &parser.method(:on_stream_data).curry(3)[stream, request])
|
data/lib/httpx/plugins/stream.rb
CHANGED
@@ -119,11 +119,9 @@ module HTTPX
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def method_missing(meth, *args, &block)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
super
|
126
|
-
end
|
122
|
+
return super unless @options.response_class.public_method_defined?(meth)
|
123
|
+
|
124
|
+
response.__send__(meth, *args, &block)
|
127
125
|
end
|
128
126
|
end
|
129
127
|
end
|
data/lib/httpx/pool.rb
CHANGED
data/lib/httpx/registry.rb
CHANGED
@@ -62,13 +62,7 @@ module HTTPX
|
|
62
62
|
handler = @registry.fetch(tag)
|
63
63
|
raise(Error, "#{tag} is not registered in #{self}") unless handler
|
64
64
|
|
65
|
-
|
66
|
-
when Symbol, String
|
67
|
-
obj = const_get(handler)
|
68
|
-
@registry[tag] = obj
|
69
|
-
else
|
70
|
-
handler
|
71
|
-
end
|
65
|
+
handler
|
72
66
|
end
|
73
67
|
|
74
68
|
# @param [Object] tag the identifier for the handler in the registry
|
data/lib/httpx/request.rb
CHANGED
@@ -217,6 +217,16 @@ module HTTPX
|
|
217
217
|
"#{unbounded_body? ? "stream" : "@bytesize=#{bytesize}"}>"
|
218
218
|
end
|
219
219
|
# :nocov:
|
220
|
+
|
221
|
+
def respond_to_missing?(meth, *args)
|
222
|
+
@body.respond_to?(meth, *args) || super
|
223
|
+
end
|
224
|
+
|
225
|
+
def method_missing(meth, *args, &block)
|
226
|
+
return super unless @body.respond_to?(meth)
|
227
|
+
|
228
|
+
@body.__send__(meth, *args, &block)
|
229
|
+
end
|
220
230
|
end
|
221
231
|
|
222
232
|
def transition(nextstate)
|
@@ -247,7 +257,7 @@ module HTTPX
|
|
247
257
|
return if @state == :expect
|
248
258
|
end
|
249
259
|
@state = nextstate
|
250
|
-
emit(@state)
|
260
|
+
emit(@state, self)
|
251
261
|
nil
|
252
262
|
end
|
253
263
|
|
data/lib/httpx/resolver/https.rb
CHANGED
@@ -55,20 +55,12 @@ module HTTPX
|
|
55
55
|
early_resolve(connection) || resolve(connection)
|
56
56
|
end
|
57
57
|
|
58
|
-
def timeout
|
59
|
-
@connections.map(&:timeout).min
|
60
|
-
end
|
61
|
-
|
62
58
|
def closed?
|
63
|
-
|
64
|
-
|
65
|
-
resolver_connection.closed?
|
59
|
+
true
|
66
60
|
end
|
67
61
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
resolver_connection.__send__(__method__)
|
62
|
+
def empty?
|
63
|
+
true
|
72
64
|
end
|
73
65
|
|
74
66
|
private
|
data/lib/httpx/response.rb
CHANGED
@@ -268,8 +268,15 @@ module HTTPX
|
|
268
268
|
@error.message
|
269
269
|
end
|
270
270
|
|
271
|
-
|
272
|
-
|
271
|
+
if Exception.method_defined?(:full_message)
|
272
|
+
def to_s
|
273
|
+
@error.full_message
|
274
|
+
end
|
275
|
+
else
|
276
|
+
def to_s
|
277
|
+
"#{@error.message} (#{@error.class})\n" \
|
278
|
+
"#{@error.backtrace.join("\n") if @error.backtrace}"
|
279
|
+
end
|
273
280
|
end
|
274
281
|
|
275
282
|
def raise_for_status
|
data/lib/httpx/selector.rb
CHANGED
@@ -69,6 +69,11 @@ class HTTPX::Selector
|
|
69
69
|
|
70
70
|
if @selectables.empty?
|
71
71
|
@selectables = selectables
|
72
|
+
|
73
|
+
# do not run event loop if there's nothing to wait on.
|
74
|
+
# this might happen if connect failed and connection was unregistered.
|
75
|
+
return if (!r || r.empty?) && (!w || w.empty?)
|
76
|
+
|
72
77
|
break
|
73
78
|
else
|
74
79
|
@selectables = [*selectables, @selectables]
|
data/lib/httpx/session.rb
CHANGED
@@ -199,7 +199,18 @@ module HTTPX
|
|
199
199
|
responses << response
|
200
200
|
requests.shift
|
201
201
|
|
202
|
-
break if requests.empty?
|
202
|
+
break if requests.empty?
|
203
|
+
|
204
|
+
next unless pool.empty?
|
205
|
+
|
206
|
+
# in some cases, the pool of connections might have been drained because there was some
|
207
|
+
# handshake error, and the error responses have already been emitted, but there was no
|
208
|
+
# opportunity to traverse the requests, hence we're returning only a fraction of the errors
|
209
|
+
# we were supposed to. This effectively fetches the existing responses and return them.
|
210
|
+
while (request = requests.shift)
|
211
|
+
responses << fetch_response(request, connections, request_options)
|
212
|
+
end
|
213
|
+
break
|
203
214
|
end
|
204
215
|
responses
|
205
216
|
ensure
|
@@ -269,7 +280,19 @@ module HTTPX
|
|
269
280
|
end
|
270
281
|
# :nocov:
|
271
282
|
end
|
283
|
+
end
|
284
|
+
|
285
|
+
unless ENV.grep(/https?_proxy$/i).empty?
|
286
|
+
proxy_session = plugin(:proxy)
|
287
|
+
::HTTPX.send(:remove_const, :Session)
|
288
|
+
::HTTPX.send(:const_set, :Session, proxy_session.class)
|
289
|
+
end
|
272
290
|
|
273
|
-
|
291
|
+
# :nocov:
|
292
|
+
if Session.default_options.debug_level > 2
|
293
|
+
proxy_session = plugin(:internal_telemetry)
|
294
|
+
::HTTPX.send(:remove_const, :Session)
|
295
|
+
::HTTPX.send(:const_set, :Session, proxy_session.class)
|
274
296
|
end
|
297
|
+
# :nocov:
|
275
298
|
end
|
@@ -44,11 +44,9 @@ module HTTPX::Transcoder
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def method_missing(meth, *args, &block)
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
super
|
51
|
-
end
|
47
|
+
return super unless @raw.respond_to?(meth)
|
48
|
+
|
49
|
+
@raw.__send__(meth, *args, &block)
|
52
50
|
end
|
53
51
|
end
|
54
52
|
|
data/lib/httpx/version.rb
CHANGED
data/sig/connection/http1.rbs
CHANGED
@@ -31,7 +31,7 @@ module HTTPX
|
|
31
31
|
|
32
32
|
def on_headers: (Hash[String, Array[String]] headers) -> void
|
33
33
|
|
34
|
-
def on_trailers: (
|
34
|
+
def on_trailers: (Hash[String, Array[String]] headers) -> void
|
35
35
|
|
36
36
|
def on_data: (string chunk) -> void
|
37
37
|
|
@@ -51,7 +51,7 @@ module HTTPX
|
|
51
51
|
|
52
52
|
def disable_pipelining: () -> void
|
53
53
|
|
54
|
-
def
|
54
|
+
def set_protocol_headers: (Request) -> void
|
55
55
|
|
56
56
|
def headline_uri: (Request) -> String
|
57
57
|
|
data/sig/connection/http2.rbs
CHANGED
@@ -3,7 +3,7 @@ module HTTPX
|
|
3
3
|
include Callbacks
|
4
4
|
include Loggable
|
5
5
|
|
6
|
-
attr_reader streams: Hash[HTTP2Next::Stream
|
6
|
+
attr_reader streams: Hash[Request, HTTP2Next::Stream]
|
7
7
|
attr_reader pending: Array[Request]
|
8
8
|
|
9
9
|
@options: Options
|
@@ -13,7 +13,7 @@ module HTTPX
|
|
13
13
|
@pings: Array[String]
|
14
14
|
@buffer: Buffer
|
15
15
|
|
16
|
-
def interests: () -> io_interests
|
16
|
+
def interests: () -> io_interests?
|
17
17
|
|
18
18
|
def close: () -> void
|
19
19
|
|
@@ -23,6 +23,8 @@ module HTTPX
|
|
23
23
|
|
24
24
|
def <<: (String) -> void
|
25
25
|
|
26
|
+
def can_buffer_more_requests: () -> bool
|
27
|
+
|
26
28
|
def send: (Request) -> void
|
27
29
|
|
28
30
|
def consume: () -> void
|
@@ -41,7 +43,7 @@ module HTTPX
|
|
41
43
|
|
42
44
|
def headline_uri: (Request) -> String
|
43
45
|
|
44
|
-
def
|
46
|
+
def set_protocol_headers: (Request) -> void
|
45
47
|
|
46
48
|
def handle: (Request request, HTTP2Next::Stream stream) -> void
|
47
49
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module HTTPX
|
2
|
+
module Plugins
|
3
|
+
module AwsSdkAuthentication
|
4
|
+
class Credentials
|
5
|
+
include _SigV4Credentials
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.load_dependencies: (singleton(Session)) -> void
|
9
|
+
|
10
|
+
def self.extra_options: (Options) -> (Options)
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
def aws_sdk_authentication: (**untyped) -> instance
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module HTTPX
|
2
|
+
module Plugins
|
3
|
+
|
4
|
+
interface _SigV4Credentials
|
5
|
+
def username: () -> String
|
6
|
+
def password: () -> String
|
7
|
+
def security_token: () -> String?
|
8
|
+
end
|
9
|
+
|
10
|
+
module AWSSigV4
|
11
|
+
|
12
|
+
Credentials: _SigV4Credentials
|
13
|
+
|
14
|
+
|
15
|
+
class Signer
|
16
|
+
|
17
|
+
def sign!: (Request) -> void
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def initialize: (
|
22
|
+
service: String,
|
23
|
+
region: String,
|
24
|
+
?credentials: _SigV4Credentials,
|
25
|
+
?username: String,
|
26
|
+
?password: String,
|
27
|
+
?security_token: String,
|
28
|
+
?provider_prefix: String,
|
29
|
+
?header_provider_field: String,
|
30
|
+
?unsigned_headers: Array[String],
|
31
|
+
?apply_checksum_header: bool,
|
32
|
+
?algorithm: String
|
33
|
+
) -> untyped
|
34
|
+
|
35
|
+
|
36
|
+
def sha256_hexdigest: (bodyIO value) -> String
|
37
|
+
|
38
|
+
def hmac: (String key, String value) -> String
|
39
|
+
def hexhmac: (String key, String value) -> String
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
interface _SigV4Options
|
44
|
+
def sigv4_signer: () -> Signer?
|
45
|
+
def sigv4_signer=: (Signer) -> Signer
|
46
|
+
def with_sigv4_signer: (Signer) -> instance
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.extra_options: (Options) -> (Options & _SigV4Options)
|
50
|
+
def self.load_dependencies: (singleton(Session)) -> void
|
51
|
+
|
52
|
+
module InstanceMethods
|
53
|
+
def aws_sigv4_authentication: (**untyped) -> instance
|
54
|
+
end
|
55
|
+
|
56
|
+
module RequestMethods
|
57
|
+
def canonical_path: () -> String
|
58
|
+
|
59
|
+
def canonical_query: () -> String
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
type awsSigV4Session = Session & Plugins::AWSSigV4::InstanceMethods
|
64
|
+
end
|
65
|
+
end
|
@@ -11,7 +11,7 @@ module HTTPX
|
|
11
11
|
module InstanceMethods
|
12
12
|
private
|
13
13
|
|
14
|
-
def promise_headers:
|
14
|
+
def promise_headers: () -> Hash[HTTP2Next::Stream, Request]
|
15
15
|
def __on_promise_request: (Connection::HTTP2, HTTP2Next::Stream, headers_input) -> void
|
16
16
|
def __on_promise_response: (Connection::HTTP2, HTTP2Next::Stream, headers_input) -> void
|
17
17
|
end
|