httpx 0.20.0 → 1.3.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/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)
|