httpx 1.1.5 → 1.2.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 +5 -5
- data/doc/release_notes/1_2_0.md +49 -0
- data/lib/httpx/adapters/webmock.rb +25 -3
- data/lib/httpx/altsvc.rb +57 -2
- data/lib/httpx/chainable.rb +40 -29
- data/lib/httpx/connection/http1.rb +27 -22
- data/lib/httpx/connection/http2.rb +7 -3
- data/lib/httpx/connection.rb +45 -60
- data/lib/httpx/extensions.rb +0 -15
- data/lib/httpx/options.rb +84 -27
- data/lib/httpx/plugins/aws_sigv4.rb +2 -2
- data/lib/httpx/plugins/basic_auth.rb +1 -1
- data/lib/httpx/plugins/callbacks.rb +91 -0
- data/lib/httpx/plugins/circuit_breaker.rb +2 -0
- data/lib/httpx/plugins/cookies.rb +19 -9
- data/lib/httpx/plugins/digest_auth.rb +1 -1
- data/lib/httpx/plugins/follow_redirects.rb +11 -0
- data/lib/httpx/plugins/grpc.rb +2 -2
- data/lib/httpx/plugins/h2c.rb +20 -8
- data/lib/httpx/plugins/proxy/socks4.rb +2 -2
- data/lib/httpx/plugins/proxy/socks5.rb +2 -2
- data/lib/httpx/plugins/proxy.rb +14 -32
- data/lib/httpx/plugins/rate_limiter.rb +1 -1
- data/lib/httpx/plugins/retries.rb +4 -0
- data/lib/httpx/plugins/ssrf_filter.rb +142 -0
- data/lib/httpx/plugins/stream.rb +1 -1
- data/lib/httpx/plugins/upgrade/h2.rb +1 -1
- data/lib/httpx/plugins/upgrade.rb +1 -1
- data/lib/httpx/plugins/webdav.rb +1 -1
- data/lib/httpx/pool.rb +32 -28
- data/lib/httpx/request/body.rb +3 -3
- data/lib/httpx/request.rb +3 -5
- data/lib/httpx/resolver/https.rb +3 -2
- data/lib/httpx/resolver/native.rb +1 -0
- data/lib/httpx/resolver/resolver.rb +17 -6
- data/lib/httpx/session.rb +13 -82
- data/lib/httpx/timers.rb +3 -10
- data/lib/httpx/transcoder.rb +1 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/altsvc.rbs +33 -0
- data/sig/chainable.rbs +1 -0
- data/sig/connection/http1.rbs +2 -1
- data/sig/connection.rbs +16 -16
- data/sig/options.rbs +10 -2
- data/sig/plugins/callbacks.rbs +38 -0
- data/sig/plugins/cookies.rbs +2 -0
- data/sig/plugins/follow_redirects.rbs +2 -0
- data/sig/plugins/proxy/socks4.rbs +2 -1
- data/sig/plugins/proxy/socks5.rbs +2 -1
- data/sig/plugins/proxy.rbs +11 -1
- data/sig/pool.rbs +1 -3
- data/sig/resolver/resolver.rbs +3 -1
- data/sig/session.rbs +4 -4
- metadata +10 -4
data/lib/httpx/options.rb
CHANGED
@@ -11,6 +11,7 @@ module HTTPX
|
|
11
11
|
MAX_BODY_THRESHOLD_SIZE = (1 << 10) * 112 # 112K
|
12
12
|
KEEP_ALIVE_TIMEOUT = 20
|
13
13
|
SETTINGS_TIMEOUT = 10
|
14
|
+
CLOSE_HANDSHAKE_TIMEOUT = 10
|
14
15
|
CONNECT_TIMEOUT = READ_TIMEOUT = WRITE_TIMEOUT = 60
|
15
16
|
REQUEST_TIMEOUT = OPERATION_TIMEOUT = nil
|
16
17
|
|
@@ -39,6 +40,7 @@ module HTTPX
|
|
39
40
|
:timeout => {
|
40
41
|
connect_timeout: CONNECT_TIMEOUT,
|
41
42
|
settings_timeout: SETTINGS_TIMEOUT,
|
43
|
+
close_handshake_timeout: CLOSE_HANDSHAKE_TIMEOUT,
|
42
44
|
operation_timeout: OPERATION_TIMEOUT,
|
43
45
|
keep_alive_timeout: KEEP_ALIVE_TIMEOUT,
|
44
46
|
read_timeout: READ_TIMEOUT,
|
@@ -226,44 +228,69 @@ module HTTPX
|
|
226
228
|
OUT
|
227
229
|
end
|
228
230
|
|
229
|
-
|
230
|
-
private_constant :REQUEST_IVARS
|
231
|
+
REQUEST_BODY_IVARS = %i[@headers @params @form @xml @json @body].freeze
|
231
232
|
|
232
233
|
def ==(other)
|
233
|
-
|
234
|
+
super || options_equals?(other)
|
235
|
+
end
|
236
|
+
|
237
|
+
def options_equals?(other, ignore_ivars = REQUEST_BODY_IVARS)
|
238
|
+
# headers and other request options do not play a role, as they are
|
239
|
+
# relevant only for the request.
|
240
|
+
ivars = instance_variables - ignore_ivars
|
241
|
+
other_ivars = other.instance_variables - ignore_ivars
|
242
|
+
|
243
|
+
return false if ivars.size != other_ivars.size
|
244
|
+
|
245
|
+
return false if ivars.sort != other_ivars.sort
|
246
|
+
|
234
247
|
ivars.all? do |ivar|
|
235
|
-
|
236
|
-
when :@headers
|
237
|
-
# currently, this is used to pick up an available matching connection.
|
238
|
-
# the headers do not play a role, as they are relevant only for the request.
|
239
|
-
true
|
240
|
-
when *REQUEST_IVARS
|
241
|
-
true
|
242
|
-
else
|
243
|
-
instance_variable_get(ivar) == other.instance_variable_get(ivar)
|
244
|
-
end
|
248
|
+
instance_variable_get(ivar) == other.instance_variable_get(ivar)
|
245
249
|
end
|
246
250
|
end
|
247
251
|
|
252
|
+
OTHER_LOOKUP = ->(obj, k, ivar_map) {
|
253
|
+
case obj
|
254
|
+
when Hash
|
255
|
+
obj[ivar_map[k]]
|
256
|
+
else
|
257
|
+
obj.instance_variable_get(k)
|
258
|
+
end
|
259
|
+
}
|
248
260
|
def merge(other)
|
249
|
-
|
261
|
+
ivar_map = nil
|
262
|
+
other_ivars = case other
|
263
|
+
when Hash
|
264
|
+
ivar_map = other.keys.to_h { |k| [:"@#{k}", k] }
|
265
|
+
ivar_map.keys
|
266
|
+
else
|
267
|
+
other.instance_variables
|
268
|
+
end
|
269
|
+
|
270
|
+
return self if other_ivars.empty?
|
250
271
|
|
251
|
-
|
252
|
-
return self if h2.empty?
|
272
|
+
return self if other_ivars.all? { |ivar| instance_variable_get(ivar) == OTHER_LOOKUP[other, ivar, ivar_map] }
|
253
273
|
|
254
|
-
|
274
|
+
opts = dup
|
255
275
|
|
256
|
-
|
276
|
+
other_ivars.each do |ivar|
|
277
|
+
v = OTHER_LOOKUP[other, ivar, ivar_map]
|
257
278
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
else
|
262
|
-
v2
|
279
|
+
unless v
|
280
|
+
opts.instance_variable_set(ivar, v)
|
281
|
+
next
|
263
282
|
end
|
283
|
+
|
284
|
+
v = opts.__send__(:"option_#{ivar[1..-1]}", v)
|
285
|
+
|
286
|
+
orig_v = instance_variable_get(ivar)
|
287
|
+
|
288
|
+
v = orig_v.merge(v) if orig_v.respond_to?(:merge) && v.respond_to?(:merge)
|
289
|
+
|
290
|
+
opts.instance_variable_set(ivar, v)
|
264
291
|
end
|
265
292
|
|
266
|
-
|
293
|
+
opts
|
267
294
|
end
|
268
295
|
|
269
296
|
def to_hash
|
@@ -272,10 +299,40 @@ module HTTPX
|
|
272
299
|
end
|
273
300
|
end
|
274
301
|
|
275
|
-
def
|
276
|
-
|
277
|
-
|
302
|
+
def extend_with_plugin_classes(pl)
|
303
|
+
if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
|
304
|
+
@request_class = @request_class.dup
|
305
|
+
@request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
|
306
|
+
@request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
|
307
|
+
end
|
308
|
+
if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
|
309
|
+
@response_class = @response_class.dup
|
310
|
+
@response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
|
311
|
+
@response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
|
278
312
|
end
|
313
|
+
if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
|
314
|
+
@headers_class = @headers_class.dup
|
315
|
+
@headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
|
316
|
+
@headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
|
317
|
+
end
|
318
|
+
if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
|
319
|
+
@request_body_class = @request_body_class.dup
|
320
|
+
@request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
|
321
|
+
@request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
|
322
|
+
end
|
323
|
+
if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
|
324
|
+
@response_body_class = @response_body_class.dup
|
325
|
+
@response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
|
326
|
+
@response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
|
327
|
+
end
|
328
|
+
if defined?(pl::ConnectionMethods)
|
329
|
+
@connection_class = @connection_class.dup
|
330
|
+
@connection_class.__send__(:include, pl::ConnectionMethods)
|
331
|
+
end
|
332
|
+
return unless defined?(pl::OptionsMethods)
|
333
|
+
|
334
|
+
@options_class = @options_class.dup
|
335
|
+
@options_class.__send__(:include, pl::OptionsMethods)
|
279
336
|
end
|
280
337
|
|
281
338
|
private
|
@@ -5,7 +5,7 @@ module HTTPX
|
|
5
5
|
#
|
6
6
|
# This plugin adds AWS Sigv4 authentication.
|
7
7
|
#
|
8
|
-
# https://docs.aws.amazon.com/
|
8
|
+
# https://docs.aws.amazon.com/IAM/latest/UserGuide/signing-elements.html
|
9
9
|
#
|
10
10
|
# https://gitlab.com/os85/httpx/wikis/AWS-SigV4
|
11
11
|
#
|
@@ -185,7 +185,7 @@ module HTTPX
|
|
185
185
|
def canonical_query
|
186
186
|
params = query.split("&")
|
187
187
|
# params = params.map { |p| p.match(/=/) ? p : p + '=' }
|
188
|
-
# From: https://docs.aws.amazon.com/
|
188
|
+
# From: https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html#create-canonical-request
|
189
189
|
# Sort the parameter names by character code point in ascending order.
|
190
190
|
# Parameters with duplicate names should be sorted by value.
|
191
191
|
#
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module HTTPX
|
4
4
|
module Plugins
|
5
5
|
#
|
6
|
-
# This plugin adds helper methods to implement HTTP Basic Auth (https://
|
6
|
+
# This plugin adds helper methods to implement HTTP Basic Auth (https://datatracker.ietf.org/doc/html/rfc7617)
|
7
7
|
#
|
8
8
|
# https://gitlab.com/os85/httpx/wikis/Auth#basic-auth
|
9
9
|
#
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTPX
|
4
|
+
module Plugins
|
5
|
+
#
|
6
|
+
# This plugin adds suppoort for callbacks around the request/response lifecycle.
|
7
|
+
#
|
8
|
+
# https://gitlab.com/os85/httpx/-/wikis/Events
|
9
|
+
#
|
10
|
+
module Callbacks
|
11
|
+
# connection closed user-space errors happen after errors can be surfaced to requests,
|
12
|
+
# so they need to pierce through the scheduler, which is only possible by simulating an
|
13
|
+
# interrupt.
|
14
|
+
class CallbackError < Exception; end # rubocop:disable Lint/InheritException
|
15
|
+
|
16
|
+
module InstanceMethods
|
17
|
+
include HTTPX::Callbacks
|
18
|
+
|
19
|
+
%i[
|
20
|
+
connection_opened connection_closed
|
21
|
+
request_error
|
22
|
+
request_started request_body_chunk request_completed
|
23
|
+
response_started response_body_chunk response_completed
|
24
|
+
].each do |meth|
|
25
|
+
class_eval(<<-MOD, __FILE__, __LINE__ + 1)
|
26
|
+
def on_#{meth}(&blk) # def on_connection_opened(&blk)
|
27
|
+
on(:#{meth}, &blk) # on(:connection_opened, &blk)
|
28
|
+
end # end
|
29
|
+
MOD
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def init_connection(uri, options)
|
35
|
+
connection = super
|
36
|
+
connection.on(:open) do
|
37
|
+
emit_or_callback_error(:connection_opened, connection.origin, connection.io.socket)
|
38
|
+
end
|
39
|
+
connection.on(:close) do
|
40
|
+
emit_or_callback_error(:connection_closed, connection.origin) if connection.used?
|
41
|
+
end
|
42
|
+
|
43
|
+
connection
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_request_callbacks(request)
|
47
|
+
super
|
48
|
+
|
49
|
+
request.on(:headers) do
|
50
|
+
emit_or_callback_error(:request_started, request)
|
51
|
+
end
|
52
|
+
request.on(:body_chunk) do |chunk|
|
53
|
+
emit_or_callback_error(:request_body_chunk, request, chunk)
|
54
|
+
end
|
55
|
+
request.on(:done) do
|
56
|
+
emit_or_callback_error(:request_completed, request)
|
57
|
+
end
|
58
|
+
|
59
|
+
request.on(:response_started) do |res|
|
60
|
+
if res.is_a?(Response)
|
61
|
+
emit_or_callback_error(:response_started, request, res)
|
62
|
+
res.on(:chunk_received) do |chunk|
|
63
|
+
emit_or_callback_error(:response_body_chunk, request, res, chunk)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
emit_or_callback_error(:request_error, request, res.error)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
request.on(:response) do |res|
|
70
|
+
emit_or_callback_error(:response_completed, request, res)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def emit_or_callback_error(*args)
|
75
|
+
emit(*args)
|
76
|
+
rescue StandardError => e
|
77
|
+
ex = CallbackError.new(e.message)
|
78
|
+
ex.set_backtrace(e.backtrace)
|
79
|
+
raise ex
|
80
|
+
end
|
81
|
+
|
82
|
+
def receive_requests(*)
|
83
|
+
super
|
84
|
+
rescue CallbackError => e
|
85
|
+
raise e.cause
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
register_plugin :callbacks, Callbacks
|
90
|
+
end
|
91
|
+
end
|
@@ -71,22 +71,32 @@ module HTTPX
|
|
71
71
|
end
|
72
72
|
|
73
73
|
module OptionsMethods
|
74
|
-
def
|
75
|
-
super
|
74
|
+
def option_headers(*)
|
75
|
+
value = super
|
76
|
+
|
77
|
+
merge_cookie_in_jar(value.delete("cookie"), @cookies) if defined?(@cookies) && value.key?("cookie")
|
76
78
|
|
77
|
-
|
79
|
+
value
|
80
|
+
end
|
78
81
|
|
79
|
-
|
82
|
+
def option_cookies(value)
|
83
|
+
jar = value.is_a?(Jar) ? value : Jar.new(value)
|
84
|
+
|
85
|
+
merge_cookie_in_jar(@headers.delete("cookie"), jar) if defined?(@headers) && @headers.key?("cookie")
|
86
|
+
|
87
|
+
jar
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def merge_cookie_in_jar(cookies, jar)
|
93
|
+
cookies.each do |ck|
|
80
94
|
ck.split(/ *; */).each do |cookie|
|
81
95
|
name, value = cookie.split("=", 2)
|
82
|
-
|
96
|
+
jar.add(Cookie.new(name, value))
|
83
97
|
end
|
84
98
|
end
|
85
99
|
end
|
86
|
-
|
87
|
-
def option_cookies(value)
|
88
|
-
value.is_a?(Jar) ? value : Jar.new(value)
|
89
|
-
end
|
90
100
|
end
|
91
101
|
end
|
92
102
|
register_plugin :cookies, Cookies
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module HTTPX
|
4
4
|
module Plugins
|
5
5
|
#
|
6
|
-
# This plugin adds helper methods to implement HTTP Digest Auth (https://
|
6
|
+
# This plugin adds helper methods to implement HTTP Digest Auth (https://datatracker.ietf.org/doc/html/rfc7616)
|
7
7
|
#
|
8
8
|
# https://gitlab.com/os85/httpx/wikis/Auth#digest-auth
|
9
9
|
#
|
@@ -34,6 +34,12 @@ module HTTPX
|
|
34
34
|
def option_allow_auth_to_other_origins(value)
|
35
35
|
value
|
36
36
|
end
|
37
|
+
|
38
|
+
def option_redirect_on(value)
|
39
|
+
raise TypeError, ":redirect_on must be callable" unless value.respond_to?(:call)
|
40
|
+
|
41
|
+
value
|
42
|
+
end
|
37
43
|
end
|
38
44
|
|
39
45
|
module InstanceMethods
|
@@ -57,6 +63,11 @@ module HTTPX
|
|
57
63
|
# build redirect request
|
58
64
|
redirect_uri = __get_location_from_response(response)
|
59
65
|
|
66
|
+
if options.redirect_on
|
67
|
+
redirect_allowed = options.redirect_on.call(redirect_uri)
|
68
|
+
return response unless redirect_allowed
|
69
|
+
end
|
70
|
+
|
60
71
|
if response.status == 305 && options.respond_to?(:proxy)
|
61
72
|
# The requested resource MUST be accessed through the proxy given by
|
62
73
|
# the Location field. The Location field gives the URI of the proxy.
|
data/lib/httpx/plugins/grpc.rb
CHANGED
@@ -261,14 +261,14 @@ module HTTPX
|
|
261
261
|
headers["grpc-timeout"] = "#{deadline}m"
|
262
262
|
end
|
263
263
|
|
264
|
-
headers = headers.merge(metadata) if metadata
|
264
|
+
headers = headers.merge(metadata.transform_keys(&:to_s)) if metadata
|
265
265
|
|
266
266
|
# prepare compressor
|
267
267
|
compression = @options.grpc_compression == true ? "gzip" : @options.grpc_compression
|
268
268
|
|
269
269
|
headers["grpc-encoding"] = compression if compression
|
270
270
|
|
271
|
-
headers.merge!(@options.call_credentials.call) if @options.call_credentials
|
271
|
+
headers.merge!(@options.call_credentials.call.transform_keys(&:to_s)) if @options.call_credentials
|
272
272
|
|
273
273
|
build_request("POST", uri, headers: headers, body: input)
|
274
274
|
end
|
data/lib/httpx/plugins/h2c.rb
CHANGED
@@ -4,9 +4,9 @@ module HTTPX
|
|
4
4
|
module Plugins
|
5
5
|
#
|
6
6
|
# This plugin adds support for upgrading a plaintext HTTP/1.1 connection to HTTP/2
|
7
|
-
# (https://
|
7
|
+
# (https://datatracker.ietf.org/doc/html/rfc7540#section-3.2)
|
8
8
|
#
|
9
|
-
# https://gitlab.com/os85/httpx/wikis/Upgrade#h2c
|
9
|
+
# https://gitlab.com/os85/httpx/wikis/Connection-Upgrade#h2c
|
10
10
|
#
|
11
11
|
module H2C
|
12
12
|
VALID_H2C_VERBS = %w[GET OPTIONS HEAD].freeze
|
@@ -73,22 +73,34 @@ module HTTPX
|
|
73
73
|
@inflight -= prev_parser.requests.size
|
74
74
|
end
|
75
75
|
|
76
|
-
|
77
|
-
@parser = H2CParser.new(@write_buffer, parser_options)
|
76
|
+
@parser = H2CParser.new(@write_buffer, @options)
|
78
77
|
set_parser_callbacks(@parser)
|
79
78
|
@inflight += 1
|
80
79
|
@parser.upgrade(request, response)
|
81
80
|
@upgrade_protocol = "h2c"
|
82
81
|
|
83
|
-
if request.options.max_concurrent_requests != @options.max_concurrent_requests
|
84
|
-
@options = @options.merge(max_concurrent_requests: nil)
|
85
|
-
end
|
86
|
-
|
87
82
|
prev_parser.requests.each do |req|
|
88
83
|
req.transition(:idle)
|
89
84
|
send(req)
|
90
85
|
end
|
91
86
|
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def send_request_to_parser(request)
|
91
|
+
super
|
92
|
+
|
93
|
+
return unless request.headers["upgrade"] == "h2c" && parser.is_a?(Connection::HTTP1)
|
94
|
+
|
95
|
+
max_concurrent_requests = parser.max_concurrent_requests
|
96
|
+
|
97
|
+
return if max_concurrent_requests == 1
|
98
|
+
|
99
|
+
parser.max_concurrent_requests = 1
|
100
|
+
request.once(:response) do
|
101
|
+
parser.max_concurrent_requests = max_concurrent_requests
|
102
|
+
end
|
103
|
+
end
|
92
104
|
end
|
93
105
|
end
|
94
106
|
register_plugin(:h2c, H2C)
|
@@ -4,7 +4,7 @@ require "resolv"
|
|
4
4
|
require "ipaddr"
|
5
5
|
|
6
6
|
module HTTPX
|
7
|
-
class Socks4Error <
|
7
|
+
class Socks4Error < HTTPProxyError; end
|
8
8
|
|
9
9
|
module Plugins
|
10
10
|
module Proxy
|
@@ -85,7 +85,7 @@ module HTTPX
|
|
85
85
|
end
|
86
86
|
|
87
87
|
class SocksParser
|
88
|
-
include Callbacks
|
88
|
+
include HTTPX::Callbacks
|
89
89
|
|
90
90
|
def initialize(buffer, options)
|
91
91
|
@buffer = buffer
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module HTTPX
|
4
|
-
class Socks5Error <
|
4
|
+
class Socks5Error < HTTPProxyError; end
|
5
5
|
|
6
6
|
module Plugins
|
7
7
|
module Proxy
|
@@ -137,7 +137,7 @@ module HTTPX
|
|
137
137
|
end
|
138
138
|
|
139
139
|
class SocksParser
|
140
|
-
include Callbacks
|
140
|
+
include HTTPX::Callbacks
|
141
141
|
|
142
142
|
def initialize(buffer, options)
|
143
143
|
@buffer = buffer
|
data/lib/httpx/plugins/proxy.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module HTTPX
|
4
|
-
class HTTPProxyError <
|
4
|
+
class HTTPProxyError < ConnectionError; end
|
5
5
|
|
6
6
|
module Plugins
|
7
7
|
#
|
@@ -143,7 +143,7 @@ module HTTPX
|
|
143
143
|
proxy = Parameters.new(**proxy_opts)
|
144
144
|
|
145
145
|
proxy_options = options.merge(proxy: proxy)
|
146
|
-
connection = pool.find_connection(uri, proxy_options) ||
|
146
|
+
connection = pool.find_connection(uri, proxy_options) || init_connection(uri, proxy_options)
|
147
147
|
unless connections.nil? || connections.include?(connection)
|
148
148
|
connections << connection
|
149
149
|
set_connection_callbacks(connection, connections, options)
|
@@ -151,19 +151,15 @@ module HTTPX
|
|
151
151
|
connection
|
152
152
|
end
|
153
153
|
|
154
|
-
def build_connection(uri, options)
|
155
|
-
proxy = options.proxy
|
156
|
-
return super unless proxy
|
157
|
-
|
158
|
-
init_connection("tcp", uri, options)
|
159
|
-
end
|
160
|
-
|
161
154
|
def fetch_response(request, connections, options)
|
162
155
|
response = super
|
163
156
|
|
164
|
-
if response.is_a?(ErrorResponse) &&
|
165
|
-
__proxy_error?(response) && !@_proxy_uris.empty?
|
157
|
+
if response.is_a?(ErrorResponse) && proxy_error?(request, response)
|
166
158
|
@_proxy_uris.shift
|
159
|
+
|
160
|
+
# return last error response if no more proxies to try
|
161
|
+
return response if @_proxy_uris.empty?
|
162
|
+
|
167
163
|
log { "failed connecting to proxy, trying next..." }
|
168
164
|
request.transition(:idle)
|
169
165
|
send_request(request, connections, options)
|
@@ -172,13 +168,7 @@ module HTTPX
|
|
172
168
|
response
|
173
169
|
end
|
174
170
|
|
175
|
-
def
|
176
|
-
return if options.proxy
|
177
|
-
|
178
|
-
super
|
179
|
-
end
|
180
|
-
|
181
|
-
def __proxy_error?(response)
|
171
|
+
def proxy_error?(_request, response)
|
182
172
|
error = response.error
|
183
173
|
case error
|
184
174
|
when NativeResolveError
|
@@ -235,14 +225,6 @@ module HTTPX
|
|
235
225
|
end
|
236
226
|
end
|
237
227
|
|
238
|
-
def send(request)
|
239
|
-
return super unless (
|
240
|
-
@options.proxy && @state != :idle && connecting?
|
241
|
-
)
|
242
|
-
|
243
|
-
(@proxy_pending ||= []) << request
|
244
|
-
end
|
245
|
-
|
246
228
|
def connecting?
|
247
229
|
return super unless @options.proxy
|
248
230
|
|
@@ -271,6 +253,12 @@ module HTTPX
|
|
271
253
|
|
272
254
|
private
|
273
255
|
|
256
|
+
def initialize_type(uri, options)
|
257
|
+
return super unless options.proxy
|
258
|
+
|
259
|
+
"tcp"
|
260
|
+
end
|
261
|
+
|
274
262
|
def connect
|
275
263
|
return super unless @options.proxy
|
276
264
|
|
@@ -278,12 +266,6 @@ module HTTPX
|
|
278
266
|
when :idle
|
279
267
|
transition(:connecting)
|
280
268
|
when :connected
|
281
|
-
if @proxy_pending
|
282
|
-
while (req = @proxy_pendind.shift)
|
283
|
-
send(req)
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
269
|
transition(:open)
|
288
270
|
end
|
289
271
|
end
|
@@ -9,7 +9,7 @@ module HTTPX
|
|
9
9
|
# * when the server is unavailable (503);
|
10
10
|
# * when a 3xx request comes with a "retry-after" value
|
11
11
|
#
|
12
|
-
# https://gitlab.com/os85/httpx/wikis/
|
12
|
+
# https://gitlab.com/os85/httpx/wikis/Rate-Limiter
|
13
13
|
#
|
14
14
|
module RateLimiter
|
15
15
|
class << self
|
@@ -132,6 +132,10 @@ module HTTPX
|
|
132
132
|
RETRYABLE_ERRORS.any? { |klass| ex.is_a?(klass) }
|
133
133
|
end
|
134
134
|
|
135
|
+
def proxy_error?(request, response)
|
136
|
+
super && !request.retries.positive?
|
137
|
+
end
|
138
|
+
|
135
139
|
#
|
136
140
|
# Atttempt to set the request to perform a partial range request.
|
137
141
|
# This happens if the peer server accepts byte-range requests, and
|