httpx 1.8.4 → 1.9.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/1_8_1.md +1 -1
- data/doc/release_notes/1_8_2.md +4 -4
- data/doc/release_notes/1_8_3.md +3 -5
- data/doc/release_notes/1_8_4.md +1 -1
- data/doc/release_notes/1_9_0.md +75 -0
- data/doc/release_notes/1_9_1.md +32 -0
- data/lib/httpx/adapters/faraday.rb +1 -1
- data/lib/httpx/adapters/webmock.rb +15 -2
- data/lib/httpx/altsvc.rb +29 -15
- data/lib/httpx/chainable.rb +4 -1
- data/lib/httpx/connection/http1.rb +34 -35
- data/lib/httpx/connection/http2.rb +146 -33
- data/lib/httpx/connection.rb +282 -162
- data/lib/httpx/headers.rb +2 -2
- data/lib/httpx/io/tcp.rb +42 -21
- data/lib/httpx/options.rb +86 -35
- data/lib/httpx/parser/http1.rb +3 -6
- data/lib/httpx/plugins/auth/digest.rb +1 -2
- data/lib/httpx/plugins/auth.rb +11 -2
- data/lib/httpx/plugins/aws_sdk_authentication.rb +7 -3
- data/lib/httpx/plugins/aws_sigv4.rb +1 -1
- data/lib/httpx/plugins/basic_auth.rb +2 -0
- data/lib/httpx/plugins/cache.rb +1 -1
- data/lib/httpx/plugins/callbacks.rb +8 -6
- data/lib/httpx/plugins/circuit_breaker.rb +1 -0
- data/lib/httpx/plugins/content_digest.rb +3 -5
- data/lib/httpx/plugins/digest_auth.rb +2 -0
- data/lib/httpx/plugins/expect.rb +10 -1
- data/lib/httpx/plugins/fiber_concurrency.rb +59 -16
- data/lib/httpx/plugins/follow_redirects.rb +1 -1
- data/lib/httpx/plugins/grpc.rb +21 -0
- data/lib/httpx/plugins/h2c.rb +12 -11
- data/lib/httpx/plugins/hedging.rb +284 -0
- data/lib/httpx/plugins/ntlm_auth.rb +5 -3
- data/lib/httpx/plugins/ntlm_v2_auth.rb +5 -3
- data/lib/httpx/plugins/oauth.rb +2 -2
- data/lib/httpx/plugins/proxy/http.rb +67 -26
- data/lib/httpx/plugins/proxy/socks5.rb +4 -4
- data/lib/httpx/plugins/proxy/ssh.rb +30 -11
- data/lib/httpx/plugins/proxy.rb +68 -54
- data/lib/httpx/plugins/push_promise.rb +4 -2
- data/lib/httpx/plugins/query.rb +1 -0
- data/lib/httpx/plugins/retries.rb +2 -2
- data/lib/httpx/plugins/server_sent_events.rb +1 -0
- data/lib/httpx/plugins/ssrf_filter.rb +1 -1
- data/lib/httpx/plugins/stream.rb +12 -10
- data/lib/httpx/plugins/stream_bidi.rb +4 -0
- data/lib/httpx/plugins/tracing.rb +99 -11
- data/lib/httpx/plugins/upgrade/h2.rb +3 -3
- data/lib/httpx/plugins/upgrade.rb +2 -0
- data/lib/httpx/plugins/webdav.rb +8 -0
- data/lib/httpx/request/body.rb +2 -1
- data/lib/httpx/request.rb +6 -6
- data/lib/httpx/resolver/https.rb +3 -2
- data/lib/httpx/resolver/native.rb +19 -9
- data/lib/httpx/resolver/resolver.rb +2 -2
- data/lib/httpx/resolver/system.rb +4 -0
- data/lib/httpx/resolver.rb +10 -6
- data/lib/httpx/response.rb +19 -7
- data/lib/httpx/selector.rb +111 -10
- data/lib/httpx/session.rb +36 -10
- data/lib/httpx/transcoder/json.rb +1 -1
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +1 -0
- data/sig/altsvc.rbs +3 -3
- data/sig/callbacks.rbs +1 -0
- data/sig/chainable.rbs +3 -1
- data/sig/connection/http1.rbs +4 -2
- data/sig/connection/http2.rbs +23 -17
- data/sig/connection.rbs +29 -7
- data/sig/headers.rbs +1 -1
- data/sig/httpx.rbs +2 -0
- data/sig/io/tcp.rbs +5 -0
- data/sig/options.rbs +43 -12
- data/sig/parser/http1.rbs +1 -1
- data/sig/plugins/auth/digest.rbs +0 -1
- data/sig/plugins/auth.rbs +12 -5
- data/sig/plugins/expect.rbs +6 -0
- data/sig/plugins/fiber_concurrency.rbs +10 -1
- data/sig/plugins/hedging.rbs +44 -0
- data/sig/plugins/proxy/http.rbs +9 -2
- data/sig/plugins/proxy.rbs +3 -2
- data/sig/plugins/retries.rbs +2 -2
- data/sig/plugins/stream_bidi.rbs +0 -2
- data/sig/plugins/tracing.rbs +22 -5
- data/sig/request/body.rbs +1 -1
- data/sig/resolver/entry.rbs +2 -2
- data/sig/resolver/https.rbs +2 -0
- data/sig/resolver/native.rbs +3 -0
- data/sig/resolver/resolver.rbs +1 -1
- data/sig/resolver/system.rbs +2 -0
- data/sig/resolver.rbs +1 -1
- data/sig/response.rbs +1 -2
- data/sig/selector.rbs +17 -3
- data/sig/session.rbs +8 -6
- metadata +7 -1
|
@@ -10,19 +10,57 @@ module HTTPX
|
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
# adds support for the following options:
|
|
14
|
+
#
|
|
15
|
+
# :proxy_headers :: hash of HTTP headers to send while connecting to the proxy.
|
|
16
|
+
# :enable_proxy_tunnel :: when <tt>true</tt>, it forces the establishment of the CONNECT proxy
|
|
17
|
+
# tunnel, in cases where it wouldn't otherwise normally establish it
|
|
18
|
+
# (i.e. if the request is an http:// request).
|
|
19
|
+
# :connect_request_class :: class of the request object used for the CONNECT tunnel request.
|
|
20
|
+
module OptionsMethods
|
|
21
|
+
def extend_with_plugin_classes(pl)
|
|
22
|
+
super
|
|
23
|
+
|
|
24
|
+
@connect_request_class = @request_class.dup
|
|
25
|
+
Options::SET_TEMPORARY_NAME[@connect_request_class, pl]
|
|
26
|
+
@connect_request_class.__send__(:include, ConnectRequestMethods)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def option_connect_request_class(val)
|
|
32
|
+
val
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def option_proxy_headers(value)
|
|
36
|
+
value = value.dup if value.frozen?
|
|
37
|
+
|
|
38
|
+
headers_class.new(value)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def option_enable_proxy_tunnel(value) # rubocop:disable Naming/PredicateMethod
|
|
42
|
+
!!value
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
13
46
|
module InstanceMethods
|
|
47
|
+
# returns a new session with the proxy authentication scheme set to <tt>"basic"</tt>, for HTTP Basic Auth.
|
|
14
48
|
def with_proxy_basic_auth(opts)
|
|
15
49
|
with(proxy: opts.merge(scheme: "basic"))
|
|
16
50
|
end
|
|
17
51
|
|
|
52
|
+
# returns a new session with the proxy authentication scheme set to <tt>"digest"</tt>, for HTTP Digest Auth.
|
|
18
53
|
def with_proxy_digest_auth(opts)
|
|
19
54
|
with(proxy: opts.merge(scheme: "digest"))
|
|
20
55
|
end
|
|
21
56
|
|
|
57
|
+
# returns a new session with the proxy authentication scheme set to <tt>"ntlm"</tt>, for NTLM Auth.
|
|
22
58
|
def with_proxy_ntlm_auth(opts)
|
|
23
59
|
with(proxy: opts.merge(scheme: "ntlm"))
|
|
24
60
|
end
|
|
25
61
|
|
|
62
|
+
private
|
|
63
|
+
|
|
26
64
|
def fetch_response(request, selector, options)
|
|
27
65
|
response = super
|
|
28
66
|
|
|
@@ -51,17 +89,21 @@ module HTTPX
|
|
|
51
89
|
super
|
|
52
90
|
end
|
|
53
91
|
|
|
54
|
-
def
|
|
92
|
+
def handle_connect_error(*)
|
|
55
93
|
if @state == :connecting
|
|
56
94
|
# proxy connect related requests should not be reenqueed
|
|
57
95
|
@parser.reset
|
|
58
|
-
@inflight -= @parser.pending.size
|
|
59
|
-
@parser.pending.clear
|
|
60
96
|
end
|
|
61
97
|
|
|
62
98
|
super
|
|
63
99
|
end
|
|
64
100
|
|
|
101
|
+
def on_error(error, *)
|
|
102
|
+
error = error.to_connection_error if error.is_a?(RequestTimeoutError) && connecting?
|
|
103
|
+
|
|
104
|
+
super
|
|
105
|
+
end
|
|
106
|
+
|
|
65
107
|
private
|
|
66
108
|
|
|
67
109
|
def purge_after_closed
|
|
@@ -83,12 +125,12 @@ module HTTPX
|
|
|
83
125
|
@tunnel_parser || begin
|
|
84
126
|
if @parser
|
|
85
127
|
# in case this happens, requests from @parser need to be reenqueued for delivery.
|
|
86
|
-
|
|
128
|
+
@parser.reset_requests
|
|
87
129
|
@parser = nil
|
|
88
130
|
end
|
|
89
131
|
|
|
90
132
|
@tunnel_parser = @parser = parser =
|
|
91
|
-
parser_type(@io.protocol).new(@write_buffer, @options.merge(max_concurrent_requests: 1))
|
|
133
|
+
parser_type(@io.protocol).new(@write_buffer, @pending, @options.merge(max_concurrent_requests: 1))
|
|
92
134
|
parser.extend(ProxyParser)
|
|
93
135
|
parser.on(:response, &method(:__http_on_connect))
|
|
94
136
|
parser.on(:close) do
|
|
@@ -96,11 +138,12 @@ module HTTPX
|
|
|
96
138
|
|
|
97
139
|
reset
|
|
98
140
|
end
|
|
141
|
+
parser.on(:error, &method(:on_parser_error))
|
|
99
142
|
parser.on(:reset) do
|
|
100
|
-
if parser.
|
|
143
|
+
if parser.empty?
|
|
101
144
|
reset
|
|
102
145
|
else
|
|
103
|
-
|
|
146
|
+
parser.reset_requests
|
|
104
147
|
|
|
105
148
|
initial_state = @state
|
|
106
149
|
|
|
@@ -121,7 +164,7 @@ module HTTPX
|
|
|
121
164
|
if initial_state == :connecting
|
|
122
165
|
parser = tunnel_parser
|
|
123
166
|
parser.reset
|
|
124
|
-
if @pending.first.is_a?(
|
|
167
|
+
if @pending.first.is_a?(@options.connect_request_class)
|
|
125
168
|
connect_request = @pending.shift # this happened when reenqueing
|
|
126
169
|
end
|
|
127
170
|
end
|
|
@@ -129,14 +172,11 @@ module HTTPX
|
|
|
129
172
|
idling
|
|
130
173
|
|
|
131
174
|
@tunnel_parser = @parser = parser
|
|
132
|
-
if connect_request
|
|
133
|
-
@inflight += 1
|
|
134
|
-
parser.send(connect_request)
|
|
135
|
-
end
|
|
175
|
+
parser.send(connect_request) if connect_request
|
|
136
176
|
transition(:connecting)
|
|
137
177
|
end
|
|
138
178
|
end
|
|
139
|
-
__http_proxy_connect
|
|
179
|
+
__http_proxy_connect
|
|
140
180
|
end
|
|
141
181
|
return if @state == :connected
|
|
142
182
|
when :connected
|
|
@@ -155,27 +195,29 @@ module HTTPX
|
|
|
155
195
|
super
|
|
156
196
|
end
|
|
157
197
|
|
|
158
|
-
def __http_proxy_connect
|
|
198
|
+
def __http_proxy_connect
|
|
159
199
|
req = @pending.first
|
|
160
|
-
|
|
200
|
+
enable_proxy_tunnel = (
|
|
201
|
+
req.options.enable_proxy_tunnel.nil? && req && req.uri.scheme == "https"
|
|
202
|
+
) || req.options.enable_proxy_tunnel
|
|
203
|
+
|
|
204
|
+
if enable_proxy_tunnel
|
|
161
205
|
# if the first request after CONNECT is to an https address, it is assumed that
|
|
162
206
|
# all requests in the queue are not only ALL HTTPS, but they also share the certificate,
|
|
163
207
|
# and therefore, will share the connection.
|
|
164
208
|
#
|
|
165
|
-
connect_request =
|
|
166
|
-
|
|
167
|
-
parser.send(connect_request)
|
|
209
|
+
connect_request = @options.connect_request_class.new(req.uri, @options)
|
|
210
|
+
send(connect_request)
|
|
168
211
|
else
|
|
169
212
|
handle_transition(:connected)
|
|
170
213
|
end
|
|
171
214
|
end
|
|
172
215
|
|
|
173
216
|
def __http_on_connect(request, response)
|
|
174
|
-
@inflight -= 1
|
|
175
217
|
if response.is_a?(Response) && response.status == 200
|
|
176
218
|
req = @pending.first
|
|
177
219
|
request_uri = req.uri
|
|
178
|
-
@io = ProxySSL.new(@io, request_uri, @options)
|
|
220
|
+
@io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
|
|
179
221
|
transition(:connected)
|
|
180
222
|
throw(:called)
|
|
181
223
|
elsif response.is_a?(Response) &&
|
|
@@ -185,11 +227,9 @@ module HTTPX
|
|
|
185
227
|
|
|
186
228
|
request.transition(:idle)
|
|
187
229
|
request.headers["proxy-authorization"] = @options.proxy.authenticate(request, response.headers["proxy-authenticate"])
|
|
188
|
-
|
|
189
|
-
@inflight += 1
|
|
230
|
+
send(request)
|
|
190
231
|
else
|
|
191
|
-
|
|
192
|
-
while (req = pending.shift)
|
|
232
|
+
while (req = @pending.shift)
|
|
193
233
|
response.finish!
|
|
194
234
|
req.response = response
|
|
195
235
|
req.emit_response(response)
|
|
@@ -219,10 +259,11 @@ module HTTPX
|
|
|
219
259
|
end
|
|
220
260
|
end
|
|
221
261
|
|
|
222
|
-
|
|
262
|
+
module ConnectRequestMethods
|
|
223
263
|
def initialize(uri, options)
|
|
224
264
|
super("CONNECT", uri, options)
|
|
225
|
-
@headers.
|
|
265
|
+
@headers = options.headers_class.new
|
|
266
|
+
merge_headers(options.proxy_headers) if options.proxy_headers
|
|
226
267
|
end
|
|
227
268
|
|
|
228
269
|
def path
|
|
@@ -42,10 +42,6 @@ module HTTPX
|
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
def connecting?
|
|
46
|
-
super || @state == :authenticating || @state == :negotiating
|
|
47
|
-
end
|
|
48
|
-
|
|
49
45
|
def interests
|
|
50
46
|
if @state == :connecting || @state == :authenticating || @state == :negotiating
|
|
51
47
|
return @write_buffer.empty? ? :r : :w
|
|
@@ -56,6 +52,10 @@ module HTTPX
|
|
|
56
52
|
|
|
57
53
|
private
|
|
58
54
|
|
|
55
|
+
def proxy_connecting?
|
|
56
|
+
super || @state == :authenticating || @state == :negotiating
|
|
57
|
+
end
|
|
58
|
+
|
|
59
59
|
def handle_transition(nextstate)
|
|
60
60
|
return super unless @options.proxy && @options.proxy.uri.scheme == "socks5"
|
|
61
61
|
|
|
@@ -21,31 +21,50 @@ module HTTPX
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
module InstanceMethods
|
|
24
|
+
def initialize(*)
|
|
25
|
+
super
|
|
26
|
+
@_gateway = nil
|
|
27
|
+
end
|
|
28
|
+
|
|
24
29
|
def request(*args, **options)
|
|
25
30
|
raise ArgumentError, "must perform at least one request" if args.empty?
|
|
26
31
|
|
|
27
32
|
requests = args.first.is_a?(Request) ? args : build_requests(*args, options)
|
|
28
33
|
|
|
29
|
-
request = requests.first
|
|
34
|
+
request = requests.first
|
|
35
|
+
|
|
36
|
+
return super unless request
|
|
30
37
|
|
|
31
38
|
request_options = request.options
|
|
32
39
|
|
|
33
40
|
return super unless request_options.proxy
|
|
34
41
|
|
|
35
|
-
ssh_options = request_options.proxy
|
|
36
|
-
ssh_uris = ssh_options.delete(:uri)
|
|
37
|
-
|
|
42
|
+
ssh_options = request_options.proxy.dup
|
|
43
|
+
ssh_uris = Array(ssh_options.delete(:uri))
|
|
44
|
+
|
|
45
|
+
proxy_ns = 0
|
|
46
|
+
|
|
47
|
+
begin
|
|
48
|
+
ssh_uri = URI(ssh_uris[proxy_ns])
|
|
49
|
+
|
|
50
|
+
return super unless ssh_uri.scheme == "ssh"
|
|
51
|
+
|
|
52
|
+
ssh_username = ssh_options.delete(:username)
|
|
53
|
+
ssh_options[:port] ||= ssh_uri.port || 22
|
|
54
|
+
if request_options.debug
|
|
55
|
+
ssh_options[:verbose] = request_options.debug_level == 2 ? :debug : :info
|
|
56
|
+
end
|
|
38
57
|
|
|
39
|
-
|
|
58
|
+
request_uri = URI(requests.first.uri)
|
|
59
|
+
@_gateway = Net::SSH::Gateway.new(ssh_uri.host, ssh_username, ssh_options)
|
|
60
|
+
rescue StandardError => e
|
|
61
|
+
log { "failed connecting to ssh proxy, trying next..." }
|
|
62
|
+
proxy_ns += 1
|
|
63
|
+
raise e if proxy_ns >= ssh_uris.size
|
|
40
64
|
|
|
41
|
-
|
|
42
|
-
ssh_options[:port] ||= ssh_uri.port || 22
|
|
43
|
-
if request_options.debug
|
|
44
|
-
ssh_options[:verbose] = request_options.debug_level == 2 ? :debug : :info
|
|
65
|
+
retry
|
|
45
66
|
end
|
|
46
67
|
|
|
47
|
-
request_uri = URI(requests.first.uri)
|
|
48
|
-
@_gateway = Net::SSH::Gateway.new(ssh_uri.host, ssh_username, ssh_options)
|
|
49
68
|
begin
|
|
50
69
|
@_gateway.open(request_uri.host, request_uri.port) do |local_port|
|
|
51
70
|
io = build_gateway_socket(local_port, request_uri, request_options)
|
data/lib/httpx/plugins/proxy.rb
CHANGED
|
@@ -11,7 +11,7 @@ module HTTPX
|
|
|
11
11
|
#
|
|
12
12
|
# * HTTP proxies
|
|
13
13
|
# * HTTPS proxies
|
|
14
|
-
# * Socks4
|
|
14
|
+
# * Socks4 proxies (also supports Socks4a)
|
|
15
15
|
# * Socks5 proxies
|
|
16
16
|
#
|
|
17
17
|
# https://gitlab.com/os85/httpx/wikis/Proxy
|
|
@@ -19,6 +19,7 @@ module HTTPX
|
|
|
19
19
|
module Proxy
|
|
20
20
|
class ProxyConnectionError < ProxyError; end
|
|
21
21
|
|
|
22
|
+
# :nodoc:
|
|
22
23
|
PROXY_ERRORS = [TimeoutError, IOError, SystemCallError, Error].freeze
|
|
23
24
|
|
|
24
25
|
class << self
|
|
@@ -39,21 +40,24 @@ module HTTPX
|
|
|
39
40
|
end
|
|
40
41
|
end
|
|
41
42
|
|
|
43
|
+
# Manages the proxy parameters and the proxy authentication flow.
|
|
42
44
|
class Parameters
|
|
43
45
|
attr_reader :uri, :username, :password, :scheme, :no_proxy
|
|
44
46
|
|
|
45
|
-
def initialize(uri: nil, scheme: nil, username: nil, password: nil, no_proxy: nil, **extra)
|
|
47
|
+
def initialize(uri: nil, ns: 0, scheme: nil, username: nil, password: nil, no_proxy: nil, **extra)
|
|
46
48
|
@no_proxy = Array(no_proxy) if no_proxy
|
|
47
49
|
@uris = Array(uri)
|
|
48
|
-
uri = @uris
|
|
50
|
+
uri = @uris[ns]
|
|
49
51
|
|
|
50
52
|
@username = username
|
|
51
53
|
@password = password
|
|
52
54
|
|
|
53
|
-
@
|
|
55
|
+
@initial_credentials = @username && @password
|
|
56
|
+
|
|
57
|
+
@ns = ns
|
|
54
58
|
|
|
55
59
|
if uri
|
|
56
|
-
@uri =
|
|
60
|
+
@uri = URI(uri)
|
|
57
61
|
@username ||= @uri.user
|
|
58
62
|
@password ||= @uri.password
|
|
59
63
|
end
|
|
@@ -74,22 +78,15 @@ module HTTPX
|
|
|
74
78
|
end
|
|
75
79
|
|
|
76
80
|
def shift
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return unless scheme != @scheme
|
|
88
|
-
|
|
89
|
-
@scheme = scheme
|
|
90
|
-
@username = username || @uri.user
|
|
91
|
-
@password = password || @uri.password
|
|
92
|
-
@authenticator = load_authenticator(scheme, @username, @password)
|
|
81
|
+
return if @ns >= @uris.size - 1
|
|
82
|
+
|
|
83
|
+
Parameters.new(
|
|
84
|
+
uri: @uris,
|
|
85
|
+
ns: @ns + 1,
|
|
86
|
+
username: (@username if @initial_credentials),
|
|
87
|
+
password: (@password if @initial_credentials),
|
|
88
|
+
no_proxy: @no_proxy
|
|
89
|
+
)
|
|
93
90
|
end
|
|
94
91
|
|
|
95
92
|
def can_authenticate?(...)
|
|
@@ -144,8 +141,26 @@ module HTTPX
|
|
|
144
141
|
|
|
145
142
|
# adds support for the following options:
|
|
146
143
|
#
|
|
147
|
-
# :proxy :: proxy options
|
|
148
|
-
#
|
|
144
|
+
# :proxy :: hash of proxy options, where a URI an be passed containing most of the requred information,
|
|
145
|
+
# or instead the different proxy options can be passed independently.
|
|
146
|
+
#
|
|
147
|
+
# The following proxy options are supported:
|
|
148
|
+
#
|
|
149
|
+
# :uri :: proxy origin URI, or list of URIs; in the case of the latter, any failed attempt to connect to a list item
|
|
150
|
+
# will retry for the next item of the list, until all elements are exhausted or it times out meanwhile.
|
|
151
|
+
# <tt>:username</tt> and <tt>:password</tt> will be inferred from it when available. The URI scheme will identify
|
|
152
|
+
# the proxy type. (ex: <tt>"http://proxi-uri:8980"</tt>, <tt>"http://user:pass@proxy-uri:8181"</tt>,
|
|
153
|
+
# <tt>"socks5://user:pass@socks-proxy-uri:10300"</tt>, <tt>["http://proxi-uri:8980", "http://user:pass@proxy-uri:8181"]</tt>).
|
|
154
|
+
# :scheme :: identifies the authentication scheme to use with the proxy, if necessary; defaults to <tt>"basic"</tt>, for basic auth,
|
|
155
|
+
# can also be <tt>"digest"</tt> or <tt>"ntml"</tt>). Your recommended to use session methods like HTTP::InstanceMethods#with_proxy_basic_auth
|
|
156
|
+
# to set these instead.
|
|
157
|
+
# :username :: the username to use when authenticating with the proxy
|
|
158
|
+
# :password :: the password to use when authenticating with the proxy
|
|
159
|
+
# :no_proxy :: A list of hostnames (or regex patterns) for which the proxy should be bypassed
|
|
160
|
+
# (ex: <tt>["example.com", "localhost", /.*\.google\.com/]</tt>). Can also receive ["*"] as a catch-all.
|
|
161
|
+
#
|
|
162
|
+
# if you systems setting environment variables like `HTTP_PROXY` or `NO_PROXY` though, you won't need to set
|
|
163
|
+
# most of the above.
|
|
149
164
|
module OptionsMethods
|
|
150
165
|
private
|
|
151
166
|
|
|
@@ -161,25 +176,31 @@ module HTTPX
|
|
|
161
176
|
end
|
|
162
177
|
|
|
163
178
|
module InstanceMethods
|
|
164
|
-
def
|
|
165
|
-
|
|
179
|
+
def initialize(*)
|
|
180
|
+
super
|
|
181
|
+
@proxy_parameters = @options.proxy
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def initialize_dup(other)
|
|
185
|
+
@proxy_parameters = other.instance_variable_get(:@proxy_parameters)
|
|
186
|
+
super
|
|
187
|
+
end
|
|
166
188
|
|
|
189
|
+
def find_connection(request_uri, selector, options)
|
|
167
190
|
if (next_proxy = request_uri.find_proxy)
|
|
168
191
|
return super(request_uri, selector, options.merge(proxy: Parameters.new(uri: next_proxy)))
|
|
169
192
|
end
|
|
170
193
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return super unless proxy
|
|
194
|
+
return super unless @proxy_parameters
|
|
174
195
|
|
|
175
|
-
next_proxy =
|
|
196
|
+
next_proxy = @proxy_parameters.uri
|
|
176
197
|
|
|
177
198
|
raise ProxyError, "Failed to connect to proxy" unless next_proxy
|
|
178
199
|
|
|
179
200
|
raise ProxyError,
|
|
180
201
|
"#{next_proxy.scheme}: unsupported proxy protocol" unless options.supported_proxy_protocols.include?(next_proxy.scheme)
|
|
181
202
|
|
|
182
|
-
if (no_proxy =
|
|
203
|
+
if (no_proxy = @proxy_parameters.no_proxy)
|
|
183
204
|
no_proxy = no_proxy.join(",") if no_proxy.is_a?(Array)
|
|
184
205
|
|
|
185
206
|
unless no_proxy != "*" && # NO_PROXY=* bypasses proxy use
|
|
@@ -189,7 +210,7 @@ module HTTPX
|
|
|
189
210
|
end
|
|
190
211
|
end
|
|
191
212
|
|
|
192
|
-
super(request_uri, selector, options.merge(proxy:
|
|
213
|
+
super(request_uri, selector, options.merge(proxy: @proxy_parameters))
|
|
193
214
|
end
|
|
194
215
|
|
|
195
216
|
private
|
|
@@ -201,10 +222,10 @@ module HTTPX
|
|
|
201
222
|
response = super
|
|
202
223
|
|
|
203
224
|
if response.is_a?(ErrorResponse) && proxy_error?(request, response, options)
|
|
204
|
-
options.proxy.shift
|
|
225
|
+
@proxy_parameters = options.proxy.shift
|
|
205
226
|
|
|
206
227
|
# return last error response if no more proxies to try
|
|
207
|
-
return response
|
|
228
|
+
return response unless @proxy_parameters
|
|
208
229
|
|
|
209
230
|
log { "failed connecting to proxy, trying next..." }
|
|
210
231
|
request.transition(:idle)
|
|
@@ -222,22 +243,22 @@ module HTTPX
|
|
|
222
243
|
end
|
|
223
244
|
end
|
|
224
245
|
|
|
225
|
-
def proxy_error?(_request, response,
|
|
226
|
-
|
|
246
|
+
def proxy_error?(_request, response, _options)
|
|
247
|
+
proxy_parameters = @proxy_parameters
|
|
248
|
+
|
|
249
|
+
return false unless proxy_parameters
|
|
227
250
|
|
|
228
251
|
error = response.error
|
|
229
252
|
case error
|
|
230
253
|
when NativeResolveError
|
|
231
|
-
proxy_uri =
|
|
254
|
+
proxy_uri = proxy_parameters.uri
|
|
232
255
|
|
|
233
256
|
unresolved_host = error.host
|
|
234
257
|
|
|
235
258
|
# failed resolving proxy domain
|
|
236
259
|
unresolved_host == proxy_uri.host
|
|
237
260
|
when ResolveError
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
error.message.end_with?(proxy_uri.to_s)
|
|
261
|
+
error.message.end_with?(proxy_parameters.uri.to_s)
|
|
241
262
|
when ProxyConnectionError
|
|
242
263
|
# timeout errors connecting to proxy
|
|
243
264
|
true
|
|
@@ -256,7 +277,7 @@ module HTTPX
|
|
|
256
277
|
|
|
257
278
|
# redefining the connection origin as the proxy's URI,
|
|
258
279
|
# as this will be used as the tcp peer ip.
|
|
259
|
-
@proxy_uri =
|
|
280
|
+
@proxy_uri = @options.proxy.uri
|
|
260
281
|
end
|
|
261
282
|
|
|
262
283
|
def peer
|
|
@@ -266,7 +287,7 @@ module HTTPX
|
|
|
266
287
|
def connecting?
|
|
267
288
|
return super unless @options.proxy
|
|
268
289
|
|
|
269
|
-
super ||
|
|
290
|
+
super || proxy_connecting?
|
|
270
291
|
end
|
|
271
292
|
|
|
272
293
|
def call
|
|
@@ -288,15 +309,6 @@ module HTTPX
|
|
|
288
309
|
raise e
|
|
289
310
|
end
|
|
290
311
|
|
|
291
|
-
def reset
|
|
292
|
-
return super unless @options.proxy
|
|
293
|
-
|
|
294
|
-
@state = :open
|
|
295
|
-
|
|
296
|
-
super
|
|
297
|
-
# emit(:close)
|
|
298
|
-
end
|
|
299
|
-
|
|
300
312
|
private
|
|
301
313
|
|
|
302
314
|
def initialize_type(uri, options)
|
|
@@ -305,6 +317,10 @@ module HTTPX
|
|
|
305
317
|
"tcp"
|
|
306
318
|
end
|
|
307
319
|
|
|
320
|
+
def proxy_connecting?
|
|
321
|
+
@state == :connecting || @state == :connected
|
|
322
|
+
end
|
|
323
|
+
|
|
308
324
|
def connect
|
|
309
325
|
return super unless @options.proxy
|
|
310
326
|
|
|
@@ -312,7 +328,7 @@ module HTTPX
|
|
|
312
328
|
when :idle
|
|
313
329
|
transition(:connecting)
|
|
314
330
|
when :connected
|
|
315
|
-
|
|
331
|
+
super
|
|
316
332
|
end
|
|
317
333
|
end
|
|
318
334
|
|
|
@@ -321,9 +337,7 @@ module HTTPX
|
|
|
321
337
|
|
|
322
338
|
case nextstate
|
|
323
339
|
when :closing
|
|
324
|
-
|
|
325
|
-
# and it'll think that the current state is open
|
|
326
|
-
@state = :open if @state == :connecting
|
|
340
|
+
@parser = nil if proxy_connecting?
|
|
327
341
|
end
|
|
328
342
|
super
|
|
329
343
|
end
|
|
@@ -12,8 +12,10 @@ module HTTPX
|
|
|
12
12
|
#
|
|
13
13
|
module PushPromise
|
|
14
14
|
def self.extra_options(options)
|
|
15
|
-
options.merge(
|
|
16
|
-
|
|
15
|
+
options.merge(
|
|
16
|
+
http2_settings: { settings_enable_push: 1 },
|
|
17
|
+
max_concurrent_requests: 1
|
|
18
|
+
)
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
module ResponseMethods
|
data/lib/httpx/plugins/query.rb
CHANGED
|
@@ -165,7 +165,7 @@ module HTTPX
|
|
|
165
165
|
# retry-after must be calculated before prepare_to_retry, as it relies on
|
|
166
166
|
# state changed byit.
|
|
167
167
|
retry_after = when_to_retry(request, response, options)
|
|
168
|
-
prepare_to_retry(request, response)
|
|
168
|
+
prepare_to_retry(request, response, retry_after)
|
|
169
169
|
|
|
170
170
|
if retry_after&.positive?
|
|
171
171
|
retry_start = Utils.now
|
|
@@ -207,7 +207,7 @@ module HTTPX
|
|
|
207
207
|
RETRYABLE_ERRORS.any? { |klass| ex.is_a?(klass) } && !ex.is_a?(TotalRequestTimeoutError)
|
|
208
208
|
end
|
|
209
209
|
|
|
210
|
-
def prepare_to_retry(request, response)
|
|
210
|
+
def prepare_to_retry(request, response, _retry_after)
|
|
211
211
|
request.retries -= 1 unless can_reconnect?(request, response)
|
|
212
212
|
request.transition(:idle)
|
|
213
213
|
end
|
data/lib/httpx/plugins/stream.rb
CHANGED
|
@@ -125,12 +125,12 @@ module HTTPX
|
|
|
125
125
|
# https://gitlab.com/os85/httpx/wikis/Stream
|
|
126
126
|
#
|
|
127
127
|
module Stream
|
|
128
|
-
STREAM_REQUEST_OPTIONS = { timeout: {
|
|
128
|
+
STREAM_REQUEST_OPTIONS = { timeout: { operation_timeout: 60 }.freeze }.freeze
|
|
129
129
|
|
|
130
130
|
def self.extra_options(options)
|
|
131
131
|
options.merge(
|
|
132
132
|
stream: false,
|
|
133
|
-
timeout: {
|
|
133
|
+
timeout: { operation_timeout: 60 },
|
|
134
134
|
stream_response_class: Class.new(StreamResponse, &Options::SET_TEMPORARY_NAME).freeze
|
|
135
135
|
)
|
|
136
136
|
end
|
|
@@ -140,14 +140,6 @@ module HTTPX
|
|
|
140
140
|
# :stream :: whether the request to process should be handled as a stream (defaults to <tt>false</tt>).
|
|
141
141
|
# :stream_response_class :: Class used to build the stream response object.
|
|
142
142
|
module OptionsMethods
|
|
143
|
-
def option_stream(val)
|
|
144
|
-
val
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def option_stream_response_class(value)
|
|
148
|
-
value
|
|
149
|
-
end
|
|
150
|
-
|
|
151
143
|
def extend_with_plugin_classes(pl)
|
|
152
144
|
return super unless defined?(pl::StreamResponseMethods)
|
|
153
145
|
|
|
@@ -157,6 +149,16 @@ module HTTPX
|
|
|
157
149
|
|
|
158
150
|
super
|
|
159
151
|
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
def option_stream(val)
|
|
156
|
+
val
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def option_stream_response_class(value)
|
|
160
|
+
value
|
|
161
|
+
end
|
|
160
162
|
end
|
|
161
163
|
|
|
162
164
|
module InstanceMethods
|