httpx 0.20.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +0 -48
- data/README.md +54 -45
- data/doc/release_notes/0_10_0.md +2 -2
- data/doc/release_notes/0_11_0.md +3 -5
- data/doc/release_notes/0_12_0.md +5 -5
- data/doc/release_notes/0_13_0.md +5 -5
- data/doc/release_notes/0_14_0.md +2 -2
- data/doc/release_notes/0_16_0.md +3 -3
- data/doc/release_notes/0_17_0.md +1 -1
- data/doc/release_notes/0_18_0.md +4 -4
- data/doc/release_notes/0_18_2.md +1 -1
- data/doc/release_notes/0_19_0.md +1 -1
- data/doc/release_notes/0_19_8.md +1 -1
- data/doc/release_notes/0_20_0.md +2 -2
- data/doc/release_notes/0_20_1.md +5 -0
- data/doc/release_notes/0_20_2.md +7 -0
- data/doc/release_notes/0_20_3.md +6 -0
- data/doc/release_notes/0_20_4.md +17 -0
- data/doc/release_notes/0_20_5.md +3 -0
- data/doc/release_notes/0_21_0.md +96 -0
- data/doc/release_notes/0_21_1.md +12 -0
- data/doc/release_notes/0_22_0.md +13 -0
- data/doc/release_notes/0_22_1.md +11 -0
- data/doc/release_notes/0_22_2.md +5 -0
- data/doc/release_notes/0_22_3.md +55 -0
- data/doc/release_notes/0_22_4.md +6 -0
- data/doc/release_notes/0_22_5.md +6 -0
- data/doc/release_notes/0_23_0.md +42 -0
- data/doc/release_notes/0_23_1.md +5 -0
- data/doc/release_notes/0_23_2.md +5 -0
- data/doc/release_notes/0_23_3.md +6 -0
- data/doc/release_notes/0_23_4.md +5 -0
- data/doc/release_notes/0_24_0.md +48 -0
- data/doc/release_notes/0_24_1.md +12 -0
- data/doc/release_notes/0_24_2.md +12 -0
- data/doc/release_notes/0_24_3.md +12 -0
- data/doc/release_notes/0_24_4.md +18 -0
- data/doc/release_notes/0_24_5.md +6 -0
- data/doc/release_notes/0_24_6.md +5 -0
- data/doc/release_notes/0_24_7.md +10 -0
- data/doc/release_notes/1_0_0.md +60 -0
- data/doc/release_notes/1_0_1.md +5 -0
- data/doc/release_notes/1_0_2.md +7 -0
- data/doc/release_notes/1_1_0.md +32 -0
- data/doc/release_notes/1_1_1.md +17 -0
- data/doc/release_notes/1_1_2.md +12 -0
- data/doc/release_notes/1_1_3.md +18 -0
- data/doc/release_notes/1_1_4.md +6 -0
- data/doc/release_notes/1_1_5.md +12 -0
- data/doc/release_notes/1_2_0.md +49 -0
- data/doc/release_notes/1_2_1.md +6 -0
- data/doc/release_notes/1_2_2.md +10 -0
- data/doc/release_notes/1_2_3.md +16 -0
- data/doc/release_notes/1_2_4.md +8 -0
- data/doc/release_notes/1_2_5.md +7 -0
- data/doc/release_notes/1_2_6.md +13 -0
- data/doc/release_notes/1_3_0.md +18 -0
- data/doc/release_notes/1_3_1.md +17 -0
- data/lib/httpx/adapters/datadog.rb +215 -122
- data/lib/httpx/adapters/faraday.rb +145 -107
- data/lib/httpx/adapters/sentry.rb +26 -7
- data/lib/httpx/adapters/webmock.rb +34 -18
- data/lib/httpx/altsvc.rb +63 -26
- data/lib/httpx/base64.rb +27 -0
- data/lib/httpx/buffer.rb +12 -0
- data/lib/httpx/callbacks.rb +5 -3
- data/lib/httpx/chainable.rb +54 -39
- data/lib/httpx/connection/http1.rb +75 -44
- data/lib/httpx/connection/http2.rb +31 -38
- data/lib/httpx/connection.rb +287 -117
- data/lib/httpx/domain_name.rb +10 -13
- data/lib/httpx/errors.rb +52 -2
- data/lib/httpx/extensions.rb +24 -131
- data/lib/httpx/io/ssl.rb +83 -77
- data/lib/httpx/io/tcp.rb +48 -71
- data/lib/httpx/io/udp.rb +18 -52
- data/lib/httpx/io/unix.rb +10 -15
- data/lib/httpx/io.rb +3 -9
- data/lib/httpx/loggable.rb +4 -19
- data/lib/httpx/options.rb +176 -118
- data/lib/httpx/parser/http1.rb +4 -0
- data/lib/httpx/plugins/{authentication → auth}/basic.rb +1 -5
- data/lib/httpx/plugins/{authentication → auth}/digest.rb +14 -14
- data/lib/httpx/plugins/{authentication → auth}/ntlm.rb +1 -3
- data/lib/httpx/plugins/{authentication → auth}/socks5.rb +0 -2
- data/lib/httpx/plugins/auth.rb +25 -0
- data/lib/httpx/plugins/aws_sdk_authentication.rb +4 -3
- data/lib/httpx/plugins/aws_sigv4.rb +12 -9
- data/lib/httpx/plugins/basic_auth.rb +29 -0
- data/lib/httpx/plugins/brotli.rb +50 -0
- data/lib/httpx/plugins/callbacks.rb +91 -0
- data/lib/httpx/plugins/circuit_breaker/circuit.rb +100 -0
- data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +53 -0
- data/lib/httpx/plugins/circuit_breaker.rb +148 -0
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +0 -2
- data/lib/httpx/plugins/cookies.rb +30 -17
- data/lib/httpx/plugins/{digest_authentication.rb → digest_auth.rb} +14 -12
- data/lib/httpx/plugins/expect.rb +21 -14
- data/lib/httpx/plugins/follow_redirects.rb +140 -41
- data/lib/httpx/plugins/grpc/call.rb +2 -3
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +88 -0
- data/lib/httpx/plugins/grpc/message.rb +7 -37
- data/lib/httpx/plugins/grpc.rb +36 -29
- data/lib/httpx/plugins/h2c.rb +26 -19
- data/lib/httpx/plugins/internal_telemetry.rb +16 -0
- data/lib/httpx/plugins/{ntlm_authentication.rb → ntlm_auth.rb} +7 -5
- data/lib/httpx/plugins/oauth.rb +175 -0
- data/lib/httpx/plugins/persistent.rb +1 -1
- data/lib/httpx/plugins/proxy/http.rb +23 -13
- data/lib/httpx/plugins/proxy/socks4.rb +9 -7
- data/lib/httpx/plugins/proxy/socks5.rb +11 -9
- data/lib/httpx/plugins/proxy.rb +80 -61
- data/lib/httpx/plugins/push_promise.rb +1 -1
- data/lib/httpx/plugins/rate_limiter.rb +5 -1
- data/lib/httpx/plugins/response_cache/file_store.rb +40 -0
- data/lib/httpx/plugins/response_cache/store.rb +62 -25
- data/lib/httpx/plugins/response_cache.rb +105 -12
- data/lib/httpx/plugins/retries.rb +87 -17
- data/lib/httpx/plugins/ssrf_filter.rb +145 -0
- data/lib/httpx/plugins/stream.rb +27 -23
- data/lib/httpx/plugins/upgrade/h2.rb +4 -4
- data/lib/httpx/plugins/upgrade.rb +8 -10
- data/lib/httpx/plugins/webdav.rb +80 -0
- data/lib/httpx/pool/synch_pool.rb +93 -0
- data/lib/httpx/pool.rb +102 -27
- data/lib/httpx/punycode.rb +9 -291
- data/lib/httpx/request/body.rb +154 -0
- data/lib/httpx/request.rb +130 -146
- data/lib/httpx/resolver/https.rb +62 -27
- data/lib/httpx/resolver/multi.rb +9 -13
- data/lib/httpx/resolver/native.rb +192 -76
- data/lib/httpx/resolver/resolver.rb +34 -9
- data/lib/httpx/resolver/system.rb +16 -11
- data/lib/httpx/resolver.rb +38 -16
- data/lib/httpx/response/body.rb +242 -0
- data/lib/httpx/response/buffer.rb +96 -0
- data/lib/httpx/response.rb +159 -217
- data/lib/httpx/selector.rb +9 -4
- data/lib/httpx/session.rb +137 -89
- data/lib/httpx/session_extensions.rb +4 -1
- data/lib/httpx/timers.rb +34 -8
- data/lib/httpx/transcoder/body.rb +0 -2
- data/lib/httpx/transcoder/chunker.rb +0 -1
- data/lib/httpx/transcoder/deflate.rb +37 -0
- data/lib/httpx/transcoder/form.rb +52 -33
- data/lib/httpx/transcoder/gzip.rb +74 -0
- data/lib/httpx/transcoder/json.rb +21 -8
- data/lib/httpx/transcoder/multipart/decoder.rb +139 -0
- data/lib/httpx/{plugins → transcoder}/multipart/encoder.rb +4 -4
- data/lib/httpx/{plugins → transcoder}/multipart/mime_type_detector.rb +1 -1
- data/lib/httpx/{plugins → transcoder}/multipart/part.rb +3 -2
- data/lib/httpx/transcoder/multipart.rb +17 -0
- data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
- data/lib/httpx/transcoder/utils/deflater.rb +72 -0
- data/lib/httpx/transcoder/utils/inflater.rb +19 -0
- data/lib/httpx/transcoder/xml.rb +52 -0
- data/lib/httpx/transcoder.rb +5 -6
- data/lib/httpx/utils.rb +36 -16
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +12 -14
- data/sig/altsvc.rbs +33 -0
- data/sig/buffer.rbs +2 -1
- data/sig/callbacks.rbs +3 -3
- data/sig/chainable.rbs +11 -9
- data/sig/connection/http1.rbs +8 -7
- data/sig/connection/http2.rbs +19 -19
- data/sig/connection.rbs +64 -24
- data/sig/errors.rbs +22 -3
- data/sig/httpx.rbs +5 -4
- data/sig/io/ssl.rbs +27 -0
- data/sig/io/tcp.rbs +60 -0
- data/sig/io/udp.rbs +20 -0
- data/sig/io/unix.rbs +27 -0
- data/sig/io.rbs +6 -0
- data/sig/options.rbs +32 -22
- data/sig/parser/http1.rbs +1 -1
- data/sig/plugins/{authentication → auth}/basic.rbs +0 -2
- data/sig/plugins/{authentication → auth}/digest.rbs +2 -1
- data/sig/plugins/auth.rbs +13 -0
- data/sig/plugins/{basic_authentication.rbs → basic_auth.rbs} +2 -2
- data/sig/plugins/brotli.rbs +22 -0
- data/sig/plugins/callbacks.rbs +38 -0
- data/sig/plugins/circuit_breaker.rbs +71 -0
- data/sig/plugins/compression.rbs +7 -5
- data/sig/plugins/cookies/jar.rbs +2 -2
- data/sig/plugins/cookies.rbs +2 -0
- data/sig/plugins/{digest_authentication.rbs → digest_auth.rbs} +2 -2
- data/sig/plugins/follow_redirects.rbs +18 -4
- data/sig/plugins/grpc/call.rbs +19 -0
- data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
- data/sig/plugins/grpc/message.rbs +17 -0
- data/sig/plugins/grpc.rbs +7 -32
- data/sig/plugins/h2c.rbs +1 -1
- data/sig/plugins/{ntlm_authentication.rbs → ntlm_auth.rbs} +2 -2
- data/sig/plugins/oauth.rbs +54 -0
- data/sig/plugins/proxy/http.rbs +3 -0
- data/sig/plugins/proxy/socks4.rbs +9 -6
- data/sig/plugins/proxy/socks5.rbs +10 -6
- data/sig/plugins/proxy/ssh.rbs +1 -1
- data/sig/plugins/proxy.rbs +13 -5
- data/sig/plugins/push_promise.rbs +3 -3
- data/sig/plugins/rate_limiter.rbs +1 -1
- data/sig/plugins/response_cache.rbs +36 -7
- data/sig/plugins/retries.rbs +30 -8
- data/sig/plugins/stream.rbs +24 -17
- data/sig/plugins/upgrade.rbs +5 -3
- data/sig/pool.rbs +10 -7
- data/sig/request/body.rbs +38 -0
- data/sig/request.rbs +15 -24
- data/sig/resolver/https.rbs +8 -3
- data/sig/resolver/native.rbs +17 -4
- data/sig/resolver/resolver.rbs +8 -6
- data/sig/resolver/system.rbs +2 -0
- data/sig/resolver.rbs +9 -5
- data/sig/response/body.rbs +53 -0
- data/sig/response/buffer.rbs +24 -0
- data/sig/response.rbs +24 -39
- data/sig/selector.rbs +1 -1
- data/sig/session.rbs +29 -18
- data/sig/timers.rbs +18 -8
- data/sig/transcoder/body.rbs +4 -3
- data/sig/transcoder/deflate.rbs +11 -0
- data/sig/transcoder/form.rbs +5 -3
- data/sig/transcoder/gzip.rbs +24 -0
- data/sig/transcoder/json.rbs +8 -3
- data/sig/{plugins → transcoder}/multipart.rbs +15 -19
- data/sig/transcoder/utils/body_reader.rbs +15 -0
- data/sig/transcoder/utils/deflater.rbs +29 -0
- data/sig/transcoder/utils/inflater.rbs +12 -0
- data/sig/transcoder/xml.rbs +22 -0
- data/sig/transcoder.rbs +24 -9
- data/sig/utils.rbs +8 -2
- metadata +163 -41
- data/lib/httpx/plugins/authentication.rb +0 -20
- data/lib/httpx/plugins/basic_authentication.rb +0 -30
- data/lib/httpx/plugins/compression/brotli.rb +0 -54
- data/lib/httpx/plugins/compression/deflate.rb +0 -49
- data/lib/httpx/plugins/compression/gzip.rb +0 -88
- data/lib/httpx/plugins/compression.rb +0 -164
- data/lib/httpx/plugins/multipart/decoder.rb +0 -187
- data/lib/httpx/plugins/multipart.rb +0 -84
- data/lib/httpx/registry.rb +0 -85
- data/sig/plugins/authentication.rbs +0 -11
- data/sig/plugins/compression/brotli.rbs +0 -21
- data/sig/plugins/compression/deflate.rbs +0 -17
- data/sig/plugins/compression/gzip.rbs +0 -29
- data/sig/registry.rbs +0 -12
- /data/sig/plugins/{authentication → auth}/ntlm.rbs +0 -0
- /data/sig/plugins/{authentication → auth}/socks5.rbs +0 -0
data/lib/httpx/options.rb
CHANGED
@@ -3,18 +3,22 @@
|
|
3
3
|
require "socket"
|
4
4
|
|
5
5
|
module HTTPX
|
6
|
+
# Contains a set of options which are passed and shared across from session to its requests or
|
7
|
+
# responses.
|
6
8
|
class Options
|
9
|
+
BUFFER_SIZE = 1 << 14
|
7
10
|
WINDOW_SIZE = 1 << 14 # 16K
|
8
11
|
MAX_BODY_THRESHOLD_SIZE = (1 << 10) * 112 # 112K
|
9
|
-
CONNECT_TIMEOUT = 60
|
10
|
-
OPERATION_TIMEOUT = 60
|
11
12
|
KEEP_ALIVE_TIMEOUT = 20
|
12
13
|
SETTINGS_TIMEOUT = 10
|
14
|
+
CLOSE_HANDSHAKE_TIMEOUT = 10
|
15
|
+
CONNECT_TIMEOUT = READ_TIMEOUT = WRITE_TIMEOUT = 60
|
16
|
+
REQUEST_TIMEOUT = OPERATION_TIMEOUT = nil
|
13
17
|
|
14
18
|
# https://github.com/ruby/resolv/blob/095f1c003f6073730500f02acbdbc55f83d70987/lib/resolv.rb#L408
|
15
19
|
ip_address_families = begin
|
16
20
|
list = Socket.ip_address_list
|
17
|
-
if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
|
21
|
+
if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? && !a.ipv6_unique_local? }
|
18
22
|
[Socket::AF_INET6, Socket::AF_INET]
|
19
23
|
else
|
20
24
|
[Socket::AF_INET]
|
@@ -24,29 +28,37 @@ module HTTPX
|
|
24
28
|
end
|
25
29
|
|
26
30
|
DEFAULT_OPTIONS = {
|
31
|
+
:max_requests => Float::INFINITY,
|
27
32
|
:debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
|
28
33
|
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
|
29
34
|
:ssl => {},
|
30
35
|
:http2_settings => { settings_enable_push: 0 },
|
31
36
|
:fallback_protocol => "http/1.1",
|
37
|
+
:supported_compression_formats => %w[gzip deflate],
|
38
|
+
:decompress_response_body => true,
|
39
|
+
:compress_request_body => true,
|
32
40
|
:timeout => {
|
33
41
|
connect_timeout: CONNECT_TIMEOUT,
|
34
42
|
settings_timeout: SETTINGS_TIMEOUT,
|
43
|
+
close_handshake_timeout: CLOSE_HANDSHAKE_TIMEOUT,
|
35
44
|
operation_timeout: OPERATION_TIMEOUT,
|
36
45
|
keep_alive_timeout: KEEP_ALIVE_TIMEOUT,
|
46
|
+
read_timeout: READ_TIMEOUT,
|
47
|
+
write_timeout: WRITE_TIMEOUT,
|
48
|
+
request_timeout: REQUEST_TIMEOUT,
|
37
49
|
},
|
50
|
+
:headers_class => Class.new(Headers),
|
38
51
|
:headers => {},
|
39
52
|
:window_size => WINDOW_SIZE,
|
53
|
+
:buffer_size => BUFFER_SIZE,
|
40
54
|
:body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
|
41
55
|
:request_class => Class.new(Request),
|
42
56
|
:response_class => Class.new(Response),
|
43
|
-
:headers_class => Class.new(Headers),
|
44
57
|
:request_body_class => Class.new(Request::Body),
|
45
58
|
:response_body_class => Class.new(Response::Body),
|
46
59
|
:connection_class => Class.new(Connection),
|
47
60
|
:options_class => Class.new(self),
|
48
61
|
:transport => nil,
|
49
|
-
:transport_options => nil,
|
50
62
|
:addresses => nil,
|
51
63
|
:persistent => false,
|
52
64
|
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
@@ -54,28 +66,6 @@ module HTTPX
|
|
54
66
|
:ip_families => ip_address_families,
|
55
67
|
}.freeze
|
56
68
|
|
57
|
-
begin
|
58
|
-
module HashExtensions
|
59
|
-
refine Hash do
|
60
|
-
def >=(other)
|
61
|
-
Hash[other] <= self
|
62
|
-
end
|
63
|
-
|
64
|
-
def <=(other)
|
65
|
-
other = Hash[other]
|
66
|
-
return false unless size <= other.size
|
67
|
-
|
68
|
-
each do |k, v|
|
69
|
-
v2 = other.fetch(k) { return false }
|
70
|
-
return false unless v2 == v
|
71
|
-
end
|
72
|
-
true
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
using HashExtensions
|
77
|
-
end unless Hash.method_defined?(:>=)
|
78
|
-
|
79
69
|
class << self
|
80
70
|
def new(options = {})
|
81
71
|
# let enhanced options go through
|
@@ -94,38 +84,50 @@ module HTTPX
|
|
94
84
|
|
95
85
|
attr_reader(optname)
|
96
86
|
end
|
97
|
-
|
98
|
-
def def_option(optname, *args, &block)
|
99
|
-
if args.size.zero? && !block
|
100
|
-
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
101
|
-
def option_#{optname}(v); v; end # def option_smth(v); v; end
|
102
|
-
OUT
|
103
|
-
return
|
104
|
-
end
|
105
|
-
|
106
|
-
deprecated_def_option(optname, *args, &block)
|
107
|
-
end
|
108
|
-
|
109
|
-
def deprecated_def_option(optname, layout = nil, &interpreter)
|
110
|
-
warn "DEPRECATION WARNING: using `def_option(#{optname})` for setting options is deprecated. " \
|
111
|
-
"Define module OptionsMethods and `def option_#{optname}(val)` instead."
|
112
|
-
|
113
|
-
if layout
|
114
|
-
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
115
|
-
def option_#{optname}(value) # def option_origin(v)
|
116
|
-
#{layout} # URI(v)
|
117
|
-
end # end
|
118
|
-
OUT
|
119
|
-
elsif interpreter
|
120
|
-
define_method(:"option_#{optname}") do |value|
|
121
|
-
instance_exec(value, &interpreter)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
87
|
end
|
126
88
|
|
89
|
+
# creates a new options instance from a given hash, which optionally define the following:
|
90
|
+
#
|
91
|
+
# :debug :: an object which log messages are written to (must respond to <tt><<</tt>)
|
92
|
+
# :debug_level :: the log level of messages (can be 1, 2, or 3).
|
93
|
+
# :ssl :: a hash of options which can be set as params of OpenSSL::SSL::SSLContext (see HTTPX::IO::SSL)
|
94
|
+
# :http2_settings :: a hash of options to be passed to a HTTP2::Connection (ex: <tt>{ max_concurrent_streams: 2 }</tt>)
|
95
|
+
# :fallback_protocol :: version of HTTP protocol to use by default in the absence of protocol negotiation
|
96
|
+
# like ALPN (defaults to <tt>"http/1.1"</tt>)
|
97
|
+
# :supported_compression_formats :: list of compressions supported by the transcoder layer (defaults to <tt>%w[gzip deflate]</tt>).
|
98
|
+
# :decompress_response_body :: whether to auto-decompress response body (defaults to <tt>true</tt>).
|
99
|
+
# :compress_request_body :: whether to auto-decompress response body (defaults to <tt>true</tt>)
|
100
|
+
# :timeout :: hash of timeout configurations (supports <tt>:connect_timeout</tt>, <tt>:settings_timeout</tt>,
|
101
|
+
# <tt>:operation_timeout</tt>, <tt>:keep_alive_timeout</tt>, <tt>:read_timeout</tt>, <tt>:write_timeout</tt>
|
102
|
+
# and <tt>:request_timeout</tt>
|
103
|
+
# :headers :: hash of HTTP headers (ex: <tt>{ "x-custom-foo" => "bar" }</tt>)
|
104
|
+
# :window_size :: number of bytes to read from a socket
|
105
|
+
# :buffer_size :: internal read and write buffer size in bytes
|
106
|
+
# :body_threshold_size :: maximum size in bytes of response payload that is buffered in memory.
|
107
|
+
# :request_class :: class used to instantiate a request
|
108
|
+
# :response_class :: class used to instantiate a response
|
109
|
+
# :headers_class :: class used to instantiate headers
|
110
|
+
# :request_body_class :: class used to instantiate a request body
|
111
|
+
# :response_body_class :: class used to instantiate a response body
|
112
|
+
# :connection_class :: class used to instantiate connections
|
113
|
+
# :options_class :: class used to instantiate options
|
114
|
+
# :transport :: type of transport to use (set to "unix" for UNIX sockets)
|
115
|
+
# :addresses :: bucket of peer addresses (can be a list of IP addresses, a hash of domain to list of adddresses;
|
116
|
+
# paths should be used for UNIX sockets instead)
|
117
|
+
# :io :: open socket, or domain/ip-to-socket hash, which requests should be sent to
|
118
|
+
# :persistent :: whether to persist connections in between requests (defaults to <tt>true</tt>)
|
119
|
+
# :resolver_class :: which resolver to use (defaults to <tt>:native</tt>, can also be <tt>:system<tt> for
|
120
|
+
# using getaddrinfo or <tt>:https</tt> for DoH resolver, or a custom class)
|
121
|
+
# :resolver_options :: hash of options passed to the resolver
|
122
|
+
# :ip_families :: which socket families are supported (system-dependent)
|
123
|
+
# :origin :: HTTP origin to set on requests with relative path (ex: "https://api.serv.com")
|
124
|
+
# :base_path :: path to prefix given relative paths with (ex: "/v2")
|
125
|
+
# :max_concurrent_requests :: max number of requests which can be set concurrently
|
126
|
+
# :max_requests :: max number of requests which can be made on socket before it reconnects.
|
127
|
+
#
|
128
|
+
# This list of options are enhanced with each loaded plugin, see the plugin docs for details.
|
127
129
|
def initialize(options = {})
|
128
|
-
|
130
|
+
do_initialize(options)
|
129
131
|
freeze
|
130
132
|
end
|
131
133
|
|
@@ -136,6 +138,7 @@ module HTTPX
|
|
136
138
|
@timeout.freeze
|
137
139
|
@headers.freeze
|
138
140
|
@addresses.freeze
|
141
|
+
@supported_compression_formats.freeze
|
139
142
|
end
|
140
143
|
|
141
144
|
def option_origin(value)
|
@@ -147,18 +150,15 @@ module HTTPX
|
|
147
150
|
end
|
148
151
|
|
149
152
|
def option_headers(value)
|
150
|
-
|
153
|
+
headers_class.new(value)
|
151
154
|
end
|
152
155
|
|
153
156
|
def option_timeout(value)
|
154
|
-
|
155
|
-
|
156
|
-
if timeouts.key?(:loop_timeout)
|
157
|
-
warn ":loop_timeout is deprecated, use :operation_timeout instead"
|
158
|
-
timeouts[:operation_timeout] = timeouts.delete(:loop_timeout)
|
159
|
-
end
|
157
|
+
Hash[value]
|
158
|
+
end
|
160
159
|
|
161
|
-
|
160
|
+
def option_supported_compression_formats(value)
|
161
|
+
Array(value).map(&:to_s)
|
162
162
|
end
|
163
163
|
|
164
164
|
def option_max_concurrent_requests(value)
|
@@ -174,16 +174,31 @@ module HTTPX
|
|
174
174
|
end
|
175
175
|
|
176
176
|
def option_window_size(value)
|
177
|
-
Integer(value)
|
177
|
+
value = Integer(value)
|
178
|
+
|
179
|
+
raise TypeError, ":window_size must be positive" unless value.positive?
|
180
|
+
|
181
|
+
value
|
182
|
+
end
|
183
|
+
|
184
|
+
def option_buffer_size(value)
|
185
|
+
value = Integer(value)
|
186
|
+
|
187
|
+
raise TypeError, ":buffer_size must be positive" unless value.positive?
|
188
|
+
|
189
|
+
value
|
178
190
|
end
|
179
191
|
|
180
192
|
def option_body_threshold_size(value)
|
181
|
-
Integer(value)
|
193
|
+
bytes = Integer(value)
|
194
|
+
raise TypeError, ":body_threshold_size must be positive" unless bytes.positive?
|
195
|
+
|
196
|
+
bytes
|
182
197
|
end
|
183
198
|
|
184
199
|
def option_transport(value)
|
185
200
|
transport = value.to_s
|
186
|
-
raise TypeError, "
|
201
|
+
raise TypeError, "#{transport} is an unsupported transport type" unless %w[unix].include?(transport)
|
187
202
|
|
188
203
|
transport
|
189
204
|
end
|
@@ -197,53 +212,82 @@ module HTTPX
|
|
197
212
|
end
|
198
213
|
|
199
214
|
%i[
|
200
|
-
|
215
|
+
ssl http2_settings
|
201
216
|
request_class response_class headers_class request_body_class
|
202
217
|
response_body_class connection_class options_class
|
203
|
-
io fallback_protocol debug debug_level
|
218
|
+
io fallback_protocol debug debug_level resolver_class resolver_options
|
219
|
+
compress_request_body decompress_response_body
|
204
220
|
persistent
|
205
221
|
].each do |method_name|
|
206
|
-
|
222
|
+
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
223
|
+
# sets +v+ as the value of #{method_name}
|
224
|
+
def option_#{method_name}(v); v; end # def option_smth(v); v; end
|
225
|
+
OUT
|
207
226
|
end
|
208
227
|
|
209
|
-
|
210
|
-
private_constant :REQUEST_IVARS
|
228
|
+
REQUEST_BODY_IVARS = %i[@headers].freeze
|
211
229
|
|
212
230
|
def ==(other)
|
213
|
-
|
231
|
+
super || options_equals?(other)
|
232
|
+
end
|
233
|
+
|
234
|
+
def options_equals?(other, ignore_ivars = REQUEST_BODY_IVARS)
|
235
|
+
# headers and other request options do not play a role, as they are
|
236
|
+
# relevant only for the request.
|
237
|
+
ivars = instance_variables - ignore_ivars
|
238
|
+
other_ivars = other.instance_variables - ignore_ivars
|
239
|
+
|
240
|
+
return false if ivars.size != other_ivars.size
|
241
|
+
|
242
|
+
return false if ivars.sort != other_ivars.sort
|
243
|
+
|
214
244
|
ivars.all? do |ivar|
|
215
|
-
|
216
|
-
when :@headers
|
217
|
-
# currently, this is used to pick up an available matching connection.
|
218
|
-
# the headers do not play a role, as they are relevant only for the request.
|
219
|
-
true
|
220
|
-
when *REQUEST_IVARS
|
221
|
-
true
|
222
|
-
else
|
223
|
-
instance_variable_get(ivar) == other.instance_variable_get(ivar)
|
224
|
-
end
|
245
|
+
instance_variable_get(ivar) == other.instance_variable_get(ivar)
|
225
246
|
end
|
226
247
|
end
|
227
248
|
|
249
|
+
OTHER_LOOKUP = ->(obj, k, ivar_map) {
|
250
|
+
case obj
|
251
|
+
when Hash
|
252
|
+
obj[ivar_map[k]]
|
253
|
+
else
|
254
|
+
obj.instance_variable_get(k)
|
255
|
+
end
|
256
|
+
}
|
228
257
|
def merge(other)
|
229
|
-
|
258
|
+
ivar_map = nil
|
259
|
+
other_ivars = case other
|
260
|
+
when Hash
|
261
|
+
ivar_map = other.keys.to_h { |k| [:"@#{k}", k] }
|
262
|
+
ivar_map.keys
|
263
|
+
else
|
264
|
+
other.instance_variables
|
265
|
+
end
|
230
266
|
|
231
|
-
|
232
|
-
return self if h2.empty?
|
267
|
+
return self if other_ivars.empty?
|
233
268
|
|
234
|
-
|
269
|
+
return self if other_ivars.all? { |ivar| instance_variable_get(ivar) == OTHER_LOOKUP[other, ivar, ivar_map] }
|
235
270
|
|
236
|
-
|
271
|
+
opts = dup
|
237
272
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
273
|
+
other_ivars.each do |ivar|
|
274
|
+
v = OTHER_LOOKUP[other, ivar, ivar_map]
|
275
|
+
|
276
|
+
unless v
|
277
|
+
opts.instance_variable_set(ivar, v)
|
278
|
+
next
|
243
279
|
end
|
280
|
+
|
281
|
+
v = opts.__send__(:"option_#{ivar[1..-1]}", v)
|
282
|
+
|
283
|
+
orig_v = instance_variable_get(ivar)
|
284
|
+
|
285
|
+
v = orig_v.merge(v) if orig_v.respond_to?(:merge) && v.respond_to?(:merge)
|
286
|
+
|
287
|
+
opts.instance_variable_set(ivar, v)
|
244
288
|
end
|
245
289
|
|
246
|
-
|
290
|
+
opts
|
247
291
|
end
|
248
292
|
|
249
293
|
def to_hash
|
@@ -252,40 +296,54 @@ module HTTPX
|
|
252
296
|
end
|
253
297
|
end
|
254
298
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
299
|
+
def extend_with_plugin_classes(pl)
|
300
|
+
if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
|
301
|
+
@request_class = @request_class.dup
|
302
|
+
@request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
|
303
|
+
@request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
|
260
304
|
end
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
305
|
+
if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
|
306
|
+
@response_class = @response_class.dup
|
307
|
+
@response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
|
308
|
+
@response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
|
309
|
+
end
|
310
|
+
if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
|
311
|
+
@headers_class = @headers_class.dup
|
312
|
+
@headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
|
313
|
+
@headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
|
314
|
+
end
|
315
|
+
if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
|
316
|
+
@request_body_class = @request_body_class.dup
|
317
|
+
@request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
|
318
|
+
@request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
|
273
319
|
end
|
320
|
+
if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
|
321
|
+
@response_body_class = @response_body_class.dup
|
322
|
+
@response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
|
323
|
+
@response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
|
324
|
+
end
|
325
|
+
if defined?(pl::ConnectionMethods)
|
326
|
+
@connection_class = @connection_class.dup
|
327
|
+
@connection_class.__send__(:include, pl::ConnectionMethods)
|
328
|
+
end
|
329
|
+
return unless defined?(pl::OptionsMethods)
|
330
|
+
|
331
|
+
@options_class = @options_class.dup
|
332
|
+
@options_class.__send__(:include, pl::OptionsMethods)
|
274
333
|
end
|
275
334
|
|
276
335
|
private
|
277
336
|
|
278
|
-
def
|
337
|
+
def do_initialize(options = {})
|
279
338
|
defaults = DEFAULT_OPTIONS.merge(options)
|
280
339
|
defaults.each do |k, v|
|
281
340
|
next if v.nil?
|
282
341
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
end
|
342
|
+
option_method_name = :"option_#{k}"
|
343
|
+
raise Error, "unknown option: #{k}" unless respond_to?(option_method_name)
|
344
|
+
|
345
|
+
value = __send__(option_method_name, v)
|
346
|
+
instance_variable_set(:"@#{k}", value)
|
289
347
|
end
|
290
348
|
end
|
291
349
|
end
|
data/lib/httpx/parser/http1.rb
CHANGED
@@ -75,6 +75,7 @@ module HTTPX
|
|
75
75
|
buffer = @buffer
|
76
76
|
|
77
77
|
while (idx = buffer.index("\n"))
|
78
|
+
# @type var line: String
|
78
79
|
line = buffer.byteslice(0..idx)
|
79
80
|
raise Error, "wrong header format" if line.start_with?("\s", "\t")
|
80
81
|
|
@@ -101,9 +102,11 @@ module HTTPX
|
|
101
102
|
separator_index = line.index(":")
|
102
103
|
raise Error, "wrong header format" unless separator_index
|
103
104
|
|
105
|
+
# @type var key: String
|
104
106
|
key = line.byteslice(0..(separator_index - 1))
|
105
107
|
|
106
108
|
key.rstrip! # was lstripped previously!
|
109
|
+
# @type var value: String
|
107
110
|
value = line.byteslice((separator_index + 1)..-1)
|
108
111
|
value.strip!
|
109
112
|
raise Error, "wrong header format" if value.nil?
|
@@ -118,6 +121,7 @@ module HTTPX
|
|
118
121
|
@observer.on_data(chunk)
|
119
122
|
end
|
120
123
|
elsif @content_length
|
124
|
+
# @type var data: String
|
121
125
|
data = @buffer.byteslice(0, @content_length)
|
122
126
|
@buffer = @buffer.byteslice(@content_length..-1) || "".b
|
123
127
|
@content_length -= data.bytesize
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "base64"
|
3
|
+
require "httpx/base64"
|
4
4
|
|
5
5
|
module HTTPX
|
6
6
|
module Plugins
|
@@ -11,10 +11,6 @@ module HTTPX
|
|
11
11
|
@password = password
|
12
12
|
end
|
13
13
|
|
14
|
-
def can_authenticate?(authenticate)
|
15
|
-
authenticate && /Basic .*/.match?(authenticate)
|
16
|
-
end
|
17
|
-
|
18
14
|
def authenticate(*)
|
19
15
|
"Basic #{Base64.strict_encode64("#{@user}:#{@password}")}"
|
20
16
|
end
|
@@ -8,12 +8,11 @@ module HTTPX
|
|
8
8
|
module Plugins
|
9
9
|
module Authentication
|
10
10
|
class Digest
|
11
|
-
|
12
|
-
|
13
|
-
def initialize(user, password, **)
|
11
|
+
def initialize(user, password, hashed: false, **)
|
14
12
|
@user = user
|
15
13
|
@password = password
|
16
14
|
@nonce = 0
|
15
|
+
@hashed = hashed
|
17
16
|
end
|
18
17
|
|
19
18
|
def can_authenticate?(authenticate)
|
@@ -21,7 +20,7 @@ module HTTPX
|
|
21
20
|
end
|
22
21
|
|
23
22
|
def authenticate(request, authenticate)
|
24
|
-
"Digest #{generate_header(request.verb
|
23
|
+
"Digest #{generate_header(request.verb, request.path, authenticate)}"
|
25
24
|
end
|
26
25
|
|
27
26
|
private
|
@@ -30,9 +29,9 @@ module HTTPX
|
|
30
29
|
# discard first token, it's Digest
|
31
30
|
auth_info = authenticate[/^(\w+) (.*)/, 2]
|
32
31
|
|
33
|
-
params =
|
34
|
-
|
35
|
-
|
32
|
+
params = auth_info.split(/ *, */)
|
33
|
+
.to_h { |val| val.split("=", 2) }
|
34
|
+
.transform_values { |v| v.delete("\"") }
|
36
35
|
nonce = params["nonce"]
|
37
36
|
nc = next_nonce
|
38
37
|
|
@@ -45,7 +44,6 @@ module HTTPX
|
|
45
44
|
raise DigestError, "unknown algorithm \"#{alg}\"" unless algorithm
|
46
45
|
|
47
46
|
sess = Regexp.last_match(2)
|
48
|
-
params.delete("algorithm")
|
49
47
|
else
|
50
48
|
algorithm = ::Digest::MD5
|
51
49
|
end
|
@@ -56,11 +54,13 @@ module HTTPX
|
|
56
54
|
end
|
57
55
|
|
58
56
|
a1 = if sess
|
59
|
-
[
|
60
|
-
|
61
|
-
|
57
|
+
[
|
58
|
+
(@hashed ? @password : algorithm.hexdigest("#{@user}:#{params["realm"]}:#{@password}")),
|
59
|
+
nonce,
|
60
|
+
cnonce,
|
61
|
+
].join ":"
|
62
62
|
else
|
63
|
-
"#{@user}:#{params["realm"]}:#{@password}"
|
63
|
+
@hashed ? @password : "#{@user}:#{params["realm"]}:#{@password}"
|
64
64
|
end
|
65
65
|
|
66
66
|
ha1 = algorithm.hexdigest(a1)
|
@@ -77,11 +77,11 @@ module HTTPX
|
|
77
77
|
%(response="#{algorithm.hexdigest(request_digest)}"),
|
78
78
|
]
|
79
79
|
header << %(realm="#{params["realm"]}") if params.key?("realm")
|
80
|
-
header << %(algorithm=#{params["algorithm"]}
|
81
|
-
header << %(opaque="#{params["opaque"]}") if params.key?("opaque")
|
80
|
+
header << %(algorithm=#{params["algorithm"]}) if params.key?("algorithm")
|
82
81
|
header << %(cnonce="#{cnonce}") if cnonce
|
83
82
|
header << %(nc=#{nc})
|
84
83
|
header << %(qop=#{qop}) if qop
|
84
|
+
header << %(opaque="#{params["opaque"]}") if params.key?("opaque")
|
85
85
|
header.join ", "
|
86
86
|
end
|
87
87
|
|
@@ -1,14 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "base64"
|
3
|
+
require "httpx/base64"
|
4
4
|
require "ntlm"
|
5
5
|
|
6
6
|
module HTTPX
|
7
7
|
module Plugins
|
8
8
|
module Authentication
|
9
9
|
class Ntlm
|
10
|
-
using RegexpExtensions unless Regexp.method_defined?(:match?)
|
11
|
-
|
12
10
|
def initialize(user, password, domain: nil)
|
13
11
|
@user = user
|
14
12
|
@password = password
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTPX
|
4
|
+
module Plugins
|
5
|
+
#
|
6
|
+
# This plugin adds a shim +authorization+ method to the session, which will fill
|
7
|
+
# the HTTP Authorization header, and another, +bearer_auth+, which fill the "Bearer " prefix
|
8
|
+
# in its value.
|
9
|
+
#
|
10
|
+
# https://gitlab.com/os85/httpx/wikis/Auth#auth
|
11
|
+
#
|
12
|
+
module Auth
|
13
|
+
module InstanceMethods
|
14
|
+
def authorization(token)
|
15
|
+
with(headers: { "authorization" => token })
|
16
|
+
end
|
17
|
+
|
18
|
+
def bearer_auth(token)
|
19
|
+
authorization("Bearer #{token}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
register_plugin :auth, Auth
|
24
|
+
end
|
25
|
+
end
|
@@ -20,9 +20,7 @@ module HTTPX
|
|
20
20
|
true
|
21
21
|
end
|
22
22
|
|
23
|
-
def method_missing(*)
|
24
|
-
nil
|
25
|
-
end
|
23
|
+
def method_missing(*); end
|
26
24
|
end
|
27
25
|
|
28
26
|
#
|
@@ -74,6 +72,9 @@ module HTTPX
|
|
74
72
|
end
|
75
73
|
end
|
76
74
|
|
75
|
+
# adds support for the following options:
|
76
|
+
#
|
77
|
+
# :aws_profile :: AWS account profile to retrieve credentials from.
|
77
78
|
module OptionsMethods
|
78
79
|
def option_aws_profile(value)
|
79
80
|
String(value)
|