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
@@ -7,69 +7,110 @@ require "faraday"
|
|
7
7
|
module Faraday
|
8
8
|
class Adapter
|
9
9
|
class HTTPX < Faraday::Adapter
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
else
|
14
|
-
Faraday::Error::SSLError
|
15
|
-
end
|
10
|
+
module RequestMixin
|
11
|
+
def build_connection(env)
|
12
|
+
return @connection if defined?(@connection)
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
Faraday::Error::ConnectionFailed
|
21
|
-
end
|
22
|
-
# :nocov:
|
14
|
+
@connection = ::HTTPX.plugin(:persistent).plugin(ReasonPlugin)
|
15
|
+
@connection = @connection.with(@connection_options) unless @connection_options.empty?
|
16
|
+
connection_opts = options_from_env(env)
|
23
17
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
18
|
+
if (bind = env.request.bind)
|
19
|
+
@bind = TCPSocket.new(bind[:host], bind[:port])
|
20
|
+
connection_opts[:io] = @bind
|
21
|
+
end
|
22
|
+
@connection = @connection.with(connection_opts)
|
23
|
+
|
24
|
+
if (proxy = env.request.proxy)
|
25
|
+
proxy_options = { uri: proxy.uri }
|
26
|
+
proxy_options[:username] = proxy.user if proxy.user
|
27
|
+
proxy_options[:password] = proxy.password if proxy.password
|
28
|
+
|
29
|
+
@connection = @connection.plugin(:proxy).with(proxy: proxy_options)
|
30
30
|
end
|
31
|
+
@connection = @connection.plugin(OnDataPlugin) if env.request.stream_response?
|
32
|
+
|
33
|
+
@connection = @config_block.call(@connection) || @connection if @config_block
|
34
|
+
@connection
|
31
35
|
end
|
32
|
-
using RequestOptionsExtensions
|
33
|
-
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
+
def close
|
38
|
+
@connection.close if @connection
|
39
|
+
@bind.close if @bind
|
40
|
+
end
|
37
41
|
|
38
42
|
private
|
39
43
|
|
44
|
+
def connect(env, &blk)
|
45
|
+
connection(env, &blk)
|
46
|
+
rescue ::HTTPX::TLSError => e
|
47
|
+
raise Faraday::SSLError, e
|
48
|
+
rescue Errno::ECONNABORTED,
|
49
|
+
Errno::ECONNREFUSED,
|
50
|
+
Errno::ECONNRESET,
|
51
|
+
Errno::EHOSTUNREACH,
|
52
|
+
Errno::EINVAL,
|
53
|
+
Errno::ENETUNREACH,
|
54
|
+
Errno::EPIPE,
|
55
|
+
::HTTPX::ConnectionError => e
|
56
|
+
raise Faraday::ConnectionFailed, e
|
57
|
+
end
|
58
|
+
|
40
59
|
def build_request(env)
|
41
60
|
meth = env[:method]
|
42
61
|
|
43
62
|
request_options = {
|
44
63
|
headers: env.request_headers,
|
45
64
|
body: env.body,
|
65
|
+
**options_from_env(env),
|
46
66
|
}
|
47
|
-
[meth, env.url, request_options]
|
67
|
+
[meth.to_s.upcase, env.url, request_options]
|
48
68
|
end
|
49
69
|
|
50
70
|
def options_from_env(env)
|
51
|
-
timeout_options = {
|
52
|
-
|
53
|
-
|
54
|
-
|
71
|
+
timeout_options = {}
|
72
|
+
req_opts = env.request
|
73
|
+
if (sec = request_timeout(:read, req_opts))
|
74
|
+
timeout_options[:read_timeout] = sec
|
75
|
+
end
|
55
76
|
|
56
|
-
|
57
|
-
|
77
|
+
if (sec = request_timeout(:write, req_opts))
|
78
|
+
timeout_options[:write_timeout] = sec
|
79
|
+
end
|
80
|
+
|
81
|
+
if (sec = request_timeout(:open, req_opts))
|
82
|
+
timeout_options[:connect_timeout] = sec
|
83
|
+
end
|
84
|
+
|
85
|
+
{
|
86
|
+
ssl: ssl_options_from_env(env),
|
58
87
|
timeout: timeout_options,
|
59
88
|
}
|
89
|
+
end
|
90
|
+
|
91
|
+
if defined?(::OpenSSL)
|
92
|
+
def ssl_options_from_env(env)
|
93
|
+
ssl_options = {}
|
94
|
+
|
95
|
+
unless env.ssl.verify.nil?
|
96
|
+
ssl_options[:verify_mode] = env.ssl.verify ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
97
|
+
end
|
60
98
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
99
|
+
ssl_options[:ca_file] = env.ssl.ca_file if env.ssl.ca_file
|
100
|
+
ssl_options[:ca_path] = env.ssl.ca_path if env.ssl.ca_path
|
101
|
+
ssl_options[:cert_store] = env.ssl.cert_store if env.ssl.cert_store
|
102
|
+
ssl_options[:cert] = env.ssl.client_cert if env.ssl.client_cert
|
103
|
+
ssl_options[:key] = env.ssl.client_key if env.ssl.client_key
|
104
|
+
ssl_options[:ssl_version] = env.ssl.version if env.ssl.version
|
105
|
+
ssl_options[:verify_depth] = env.ssl.verify_depth if env.ssl.verify_depth
|
106
|
+
ssl_options[:min_version] = env.ssl.min_version if env.ssl.min_version
|
107
|
+
ssl_options[:max_version] = env.ssl.max_version if env.ssl.max_version
|
108
|
+
ssl_options
|
109
|
+
end
|
110
|
+
else
|
111
|
+
def ssl_options_from_env(*)
|
112
|
+
{}
|
113
|
+
end
|
73
114
|
end
|
74
115
|
end
|
75
116
|
|
@@ -100,32 +141,17 @@ module Faraday
|
|
100
141
|
end
|
101
142
|
|
102
143
|
module ReasonPlugin
|
103
|
-
|
104
|
-
|
105
|
-
require "webrick"
|
106
|
-
end
|
107
|
-
else
|
108
|
-
def self.load_dependencies(*)
|
109
|
-
require "net/http/status"
|
110
|
-
end
|
144
|
+
def self.load_dependencies(*)
|
145
|
+
require "net/http/status"
|
111
146
|
end
|
147
|
+
|
112
148
|
module ResponseMethods
|
113
|
-
|
114
|
-
|
115
|
-
WEBrick::HTTPStatus::StatusMessage.fetch(@status)
|
116
|
-
end
|
117
|
-
else
|
118
|
-
def reason
|
119
|
-
Net::HTTP::STATUS_CODES.fetch(@status)
|
120
|
-
end
|
149
|
+
def reason
|
150
|
+
Net::HTTP::STATUS_CODES.fetch(@status)
|
121
151
|
end
|
122
152
|
end
|
123
153
|
end
|
124
154
|
|
125
|
-
def self.session
|
126
|
-
@session ||= ::HTTPX.plugin(:compression).plugin(:persistent).plugin(ReasonPlugin)
|
127
|
-
end
|
128
|
-
|
129
155
|
class ParallelManager
|
130
156
|
class ResponseHandler < SimpleDelegator
|
131
157
|
attr_reader :env
|
@@ -158,8 +184,9 @@ module Faraday
|
|
158
184
|
|
159
185
|
include RequestMixin
|
160
186
|
|
161
|
-
def initialize
|
187
|
+
def initialize(options)
|
162
188
|
@handlers = []
|
189
|
+
@connection_options = options
|
163
190
|
end
|
164
191
|
|
165
192
|
def enqueue(request)
|
@@ -169,85 +196,96 @@ module Faraday
|
|
169
196
|
end
|
170
197
|
|
171
198
|
def run
|
199
|
+
return unless @handlers.last
|
200
|
+
|
172
201
|
env = @handlers.last.env
|
173
202
|
|
174
|
-
|
175
|
-
|
176
|
-
session = session.plugin(OnDataPlugin) if env.request.stream_response?
|
203
|
+
connect(env) do |session|
|
204
|
+
requests = @handlers.map { |handler| session.build_request(*build_request(handler.env)) }
|
177
205
|
|
178
|
-
|
206
|
+
if env.request.stream_response?
|
207
|
+
requests.each do |request|
|
208
|
+
request.response_on_data = env.request.on_data
|
209
|
+
end
|
210
|
+
end
|
179
211
|
|
180
|
-
|
181
|
-
|
182
|
-
|
212
|
+
responses = session.request(*requests)
|
213
|
+
Array(responses).each_with_index do |response, index|
|
214
|
+
handler = @handlers[index]
|
215
|
+
handler.on_response.call(response)
|
216
|
+
handler.on_complete.call(handler.env) if handler.on_complete
|
183
217
|
end
|
184
218
|
end
|
219
|
+
rescue ::HTTPX::TimeoutError => e
|
220
|
+
raise Faraday::TimeoutError, e
|
221
|
+
end
|
185
222
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
223
|
+
# from Faraday::Adapter#connection
|
224
|
+
def connection(env)
|
225
|
+
conn = build_connection(env)
|
226
|
+
return conn unless block_given?
|
227
|
+
|
228
|
+
yield conn
|
229
|
+
end
|
230
|
+
|
231
|
+
private
|
232
|
+
|
233
|
+
# from Faraday::Adapter#request_timeout
|
234
|
+
def request_timeout(type, options)
|
235
|
+
key = Faraday::Adapter::TIMEOUT_KEYS[type]
|
236
|
+
options[key] || options[:timeout]
|
192
237
|
end
|
193
238
|
end
|
194
239
|
|
195
240
|
self.supports_parallel = true
|
196
241
|
|
197
242
|
class << self
|
198
|
-
def setup_parallel_manager
|
199
|
-
ParallelManager.new
|
243
|
+
def setup_parallel_manager(options = {})
|
244
|
+
ParallelManager.new(options)
|
200
245
|
end
|
201
246
|
end
|
202
247
|
|
203
|
-
def initialize(app, options = {})
|
204
|
-
super(app)
|
205
|
-
@session_options = options
|
206
|
-
end
|
207
|
-
|
208
248
|
def call(env)
|
209
249
|
super
|
210
250
|
if parallel?(env)
|
211
251
|
handler = env[:parallel_manager].enqueue(env)
|
212
252
|
handler.on_response do |response|
|
213
|
-
response.
|
214
|
-
|
215
|
-
|
253
|
+
if response.is_a?(::HTTPX::Response)
|
254
|
+
save_response(env, response.status, response.body.to_s, response.headers, response.reason) do |response_headers|
|
255
|
+
response_headers.merge!(response.headers)
|
256
|
+
end
|
257
|
+
else
|
258
|
+
env[:error] = response.error
|
259
|
+
save_response(env, 0, "", {}, nil)
|
216
260
|
end
|
217
261
|
end
|
218
262
|
return handler
|
219
263
|
end
|
220
264
|
|
221
|
-
|
222
|
-
session = session.with(@session_options) unless @session_options.empty?
|
223
|
-
session = session.with(options_from_env(env))
|
224
|
-
session = session.plugin(:proxy).with(proxy: { uri: env.request.proxy }) if env.request.proxy
|
225
|
-
session = session.plugin(OnDataPlugin) if env.request.stream_response?
|
226
|
-
|
227
|
-
request = session.build_request(*build_request(env))
|
228
|
-
|
229
|
-
request.response_on_data = env.request.on_data if env.request.stream_response?
|
230
|
-
|
231
|
-
response = session.request(request)
|
232
|
-
response.raise_for_status unless response.is_a?(::HTTPX::Response)
|
265
|
+
response = connect_and_request(env)
|
233
266
|
save_response(env, response.status, response.body.to_s, response.headers, response.reason) do |response_headers|
|
234
267
|
response_headers.merge!(response.headers)
|
235
268
|
end
|
236
269
|
@app.call(env)
|
237
|
-
rescue ::HTTPX::TLSError => e
|
238
|
-
raise SSL_ERROR, e
|
239
|
-
rescue Errno::ECONNABORTED,
|
240
|
-
Errno::ECONNREFUSED,
|
241
|
-
Errno::ECONNRESET,
|
242
|
-
Errno::EHOSTUNREACH,
|
243
|
-
Errno::EINVAL,
|
244
|
-
Errno::ENETUNREACH,
|
245
|
-
Errno::EPIPE => e
|
246
|
-
raise CONNECTION_FAILED_ERROR, e
|
247
270
|
end
|
248
271
|
|
249
272
|
private
|
250
273
|
|
274
|
+
def connect_and_request(env)
|
275
|
+
connect(env) do |session|
|
276
|
+
request = session.build_request(*build_request(env))
|
277
|
+
|
278
|
+
request.response_on_data = env.request.on_data if env.request.stream_response?
|
279
|
+
|
280
|
+
response = session.request(request)
|
281
|
+
# do not call #raise_for_status for HTTP 4xx or 5xx, as faraday has a middleware for that.
|
282
|
+
response.raise_for_status unless response.is_a?(::HTTPX::Response)
|
283
|
+
response
|
284
|
+
end
|
285
|
+
rescue ::HTTPX::TimeoutError => e
|
286
|
+
raise Faraday::TimeoutError, e
|
287
|
+
end
|
288
|
+
|
251
289
|
def parallel?(env)
|
252
290
|
env[:parallel_manager]
|
253
291
|
end
|
@@ -27,6 +27,11 @@ module HTTPX::Plugins
|
|
27
27
|
def set_sentry_trace_header(request, sentry_span)
|
28
28
|
return unless sentry_span
|
29
29
|
|
30
|
+
config = ::Sentry.configuration
|
31
|
+
url = request.uri.to_s
|
32
|
+
|
33
|
+
return unless config.propagate_traces && config.trace_propagation_targets.any? { |target| url.match?(target) }
|
34
|
+
|
30
35
|
trace = ::Sentry.get_current_client.generate_sentry_trace(sentry_span)
|
31
36
|
request.headers[::Sentry::SENTRY_TRACE_HEADER_NAME] = trace if trace
|
32
37
|
end
|
@@ -43,8 +48,8 @@ module HTTPX::Plugins
|
|
43
48
|
|
44
49
|
request_info = extract_request_info(req)
|
45
50
|
|
46
|
-
data = if
|
47
|
-
{ error: res.message, **request_info }
|
51
|
+
data = if res.is_a?(HTTPX::ErrorResponse)
|
52
|
+
{ error: res.error.message, **request_info }
|
48
53
|
else
|
49
54
|
{ status: res.status, **request_info }
|
50
55
|
end
|
@@ -63,7 +68,11 @@ module HTTPX::Plugins
|
|
63
68
|
|
64
69
|
request_info = extract_request_info(req)
|
65
70
|
sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
|
66
|
-
|
71
|
+
if res.is_a?(HTTPX::ErrorResponse)
|
72
|
+
sentry_span.set_data(:error, res.error.message)
|
73
|
+
else
|
74
|
+
sentry_span.set_data(:status, res.status)
|
75
|
+
end
|
67
76
|
sentry_span.set_timestamp(::Sentry.utc_now.to_f)
|
68
77
|
end
|
69
78
|
|
@@ -71,7 +80,7 @@ module HTTPX::Plugins
|
|
71
80
|
uri = req.uri
|
72
81
|
|
73
82
|
result = {
|
74
|
-
method: req.verb
|
83
|
+
method: req.verb,
|
75
84
|
}
|
76
85
|
|
77
86
|
if ::Sentry.configuration.send_default_pii
|
@@ -85,17 +94,27 @@ module HTTPX::Plugins
|
|
85
94
|
end
|
86
95
|
end
|
87
96
|
|
97
|
+
module RequestMethods
|
98
|
+
def __sentry_enable_trace!
|
99
|
+
return if @__sentry_enable_trace
|
100
|
+
|
101
|
+
Tracer.call(self)
|
102
|
+
@__sentry_enable_trace = true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
88
106
|
module ConnectionMethods
|
89
107
|
def send(request)
|
90
|
-
|
108
|
+
request.__sentry_enable_trace!
|
109
|
+
|
91
110
|
super
|
92
111
|
end
|
93
112
|
end
|
94
113
|
end
|
95
114
|
end
|
96
115
|
|
97
|
-
Sentry.register_patch do
|
98
|
-
sentry_session =
|
116
|
+
Sentry.register_patch(:httpx) do
|
117
|
+
sentry_session = HTTPX.plugin(HTTPX::Plugins::Sentry)
|
99
118
|
|
100
119
|
HTTPX.send(:remove_const, :Session)
|
101
120
|
HTTPX.send(:const_set, :Session, sentry_session.class)
|
@@ -2,13 +2,8 @@
|
|
2
2
|
|
3
3
|
module WebMock
|
4
4
|
module HttpLibAdapters
|
5
|
-
|
6
|
-
|
7
|
-
HTTP_REASONS = WEBrick::HTTPStatus::StatusMessage
|
8
|
-
else
|
9
|
-
require "net/http/status"
|
10
|
-
HTTP_REASONS = Net::HTTP::STATUS_CODES
|
11
|
-
end
|
5
|
+
require "net/http/status"
|
6
|
+
HTTP_REASONS = Net::HTTP::STATUS_CODES
|
12
7
|
|
13
8
|
#
|
14
9
|
# HTTPX plugin for webmock.
|
@@ -23,7 +18,7 @@ module WebMock
|
|
23
18
|
uri.path = uri.normalized_path.gsub("[^:]//", "/")
|
24
19
|
|
25
20
|
WebMock::RequestSignature.new(
|
26
|
-
request.verb,
|
21
|
+
request.verb.downcase.to_sym,
|
27
22
|
uri.to_s,
|
28
23
|
body: request.body.each.to_a.join,
|
29
24
|
headers: request.headers.to_h
|
@@ -43,30 +38,50 @@ module WebMock
|
|
43
38
|
|
44
39
|
return build_error_response(request, webmock_response.exception) if webmock_response.exception
|
45
40
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
41
|
+
request.options.response_class.new(request,
|
42
|
+
webmock_response.status[0],
|
43
|
+
"2.0",
|
44
|
+
webmock_response.headers).tap do |res|
|
45
|
+
res.mocked = true
|
46
|
+
end
|
52
47
|
end
|
53
48
|
|
54
49
|
def build_error_response(request, exception)
|
55
|
-
HTTPX::ErrorResponse.new(request, exception
|
50
|
+
HTTPX::ErrorResponse.new(request, exception)
|
56
51
|
end
|
57
52
|
end
|
58
53
|
|
59
54
|
module InstanceMethods
|
60
|
-
def
|
55
|
+
def init_connection(*)
|
61
56
|
connection = super
|
62
57
|
connection.once(:unmock_connection) do
|
58
|
+
unless connection.addresses
|
59
|
+
connection.__send__(:callbacks)[:connect_error].clear
|
60
|
+
pool.__send__(:unregister_connection, connection)
|
61
|
+
end
|
63
62
|
pool.__send__(:resolve_connection, connection)
|
64
|
-
pool.__send__(:unregister_connection, connection) unless connection.addresses
|
65
63
|
end
|
66
64
|
connection
|
67
65
|
end
|
68
66
|
end
|
69
67
|
|
68
|
+
module ResponseMethods
|
69
|
+
attr_accessor :mocked
|
70
|
+
|
71
|
+
def initialize(*)
|
72
|
+
super
|
73
|
+
@mocked = false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module ResponseBodyMethods
|
78
|
+
def decode_chunk(chunk)
|
79
|
+
return chunk if @response.mocked
|
80
|
+
|
81
|
+
super
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
70
85
|
module ConnectionMethods
|
71
86
|
def initialize(*)
|
72
87
|
super
|
@@ -95,6 +110,7 @@ module WebMock
|
|
95
110
|
log { "mocking #{request.uri} with #{mock_response.inspect}" }
|
96
111
|
request.response = response
|
97
112
|
request.emit(:response, response)
|
113
|
+
response << mock_response.body.dup unless response.is_a?(HTTPX::ErrorResponse)
|
98
114
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
99
115
|
if WebMock::CallbackRegistry.any_callbacks?
|
100
116
|
request.on(:response) do |resp|
|
@@ -122,7 +138,7 @@ module WebMock
|
|
122
138
|
|
123
139
|
class << self
|
124
140
|
def enable!
|
125
|
-
@original_session
|
141
|
+
@original_session ||= HTTPX::Session
|
126
142
|
|
127
143
|
webmock_session = HTTPX.plugin(Plugin)
|
128
144
|
|
data/lib/httpx/altsvc.rb
CHANGED
@@ -4,7 +4,59 @@ require "strscan"
|
|
4
4
|
|
5
5
|
module HTTPX
|
6
6
|
module AltSvc
|
7
|
-
|
7
|
+
# makes connections able to accept requests destined to primary service.
|
8
|
+
module ConnectionMixin
|
9
|
+
using URIExtensions
|
10
|
+
|
11
|
+
def send(request)
|
12
|
+
request.headers["alt-used"] = @origin.authority if @parser && !@write_buffer.full? && match_altsvcs?(request.uri)
|
13
|
+
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def match?(uri, options)
|
18
|
+
return false if !used? && (@state == :closing || @state == :closed)
|
19
|
+
|
20
|
+
match_altsvcs?(uri) && match_altsvc_options?(uri, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# checks if this is connection is an alternative service of
|
26
|
+
# +uri+
|
27
|
+
def match_altsvcs?(uri)
|
28
|
+
@origins.any? { |origin| altsvc_match?(uri, origin) } ||
|
29
|
+
AltSvc.cached_altsvc(@origin).any? do |altsvc|
|
30
|
+
origin = altsvc["origin"]
|
31
|
+
altsvc_match?(origin, uri.origin)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def match_altsvc_options?(uri, options)
|
36
|
+
return @options == options unless @options.ssl.all? do |k, v|
|
37
|
+
v == (k == :hostname ? uri.host : options.ssl[k])
|
38
|
+
end
|
39
|
+
|
40
|
+
@options.options_equals?(options, Options::REQUEST_BODY_IVARS + %i[@ssl])
|
41
|
+
end
|
42
|
+
|
43
|
+
def altsvc_match?(uri, other_uri)
|
44
|
+
other_uri = URI(other_uri)
|
45
|
+
|
46
|
+
uri.origin == other_uri.origin || begin
|
47
|
+
case uri.scheme
|
48
|
+
when "h2"
|
49
|
+
(other_uri.scheme == "https" || other_uri.scheme == "h2") &&
|
50
|
+
uri.host == other_uri.host &&
|
51
|
+
uri.port == other_uri.port
|
52
|
+
else
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
@altsvc_mutex = Thread::Mutex.new
|
8
60
|
@altsvcs = Hash.new { |h, k| h[k] = [] }
|
9
61
|
|
10
62
|
module_function
|
@@ -46,7 +98,7 @@ module HTTPX
|
|
46
98
|
|
47
99
|
altsvc = response.headers["alt-svc"]
|
48
100
|
|
49
|
-
# https://
|
101
|
+
# https://datatracker.ietf.org/doc/html/rfc7838#section-3
|
50
102
|
# A field value containing the special value "clear" indicates that the
|
51
103
|
# origin requests all alternatives for that origin to be invalidated
|
52
104
|
# (including those specified in the same response, in case of an
|
@@ -79,9 +131,9 @@ module HTTPX
|
|
79
131
|
scanner.skip(/;/)
|
80
132
|
break if scanner.eos? || scanner.scan(/ *, */)
|
81
133
|
end
|
82
|
-
alt_params = Hash[alt_params.map { |field| field.split("=") }]
|
134
|
+
alt_params = Hash[alt_params.map { |field| field.split("=", 2) }]
|
83
135
|
|
84
|
-
alt_proto, alt_authority = alt_service.split("=")
|
136
|
+
alt_proto, alt_authority = alt_service.split("=", 2)
|
85
137
|
alt_origin = parse_altsvc_origin(alt_proto, alt_authority)
|
86
138
|
return unless alt_origin
|
87
139
|
|
@@ -98,29 +150,14 @@ module HTTPX
|
|
98
150
|
end
|
99
151
|
end
|
100
152
|
|
101
|
-
|
102
|
-
|
103
|
-
def parse_altsvc_origin(alt_proto, alt_origin)
|
104
|
-
alt_scheme = parse_altsvc_scheme(alt_proto) or return
|
105
|
-
|
106
|
-
alt_origin = alt_origin[1..-2] if alt_origin.start_with?("\"") && alt_origin.end_with?("\"")
|
107
|
-
if alt_origin.start_with?(":")
|
108
|
-
alt_origin = "#{alt_scheme}://dummy#{alt_origin}"
|
109
|
-
uri = URI.parse(alt_origin)
|
110
|
-
uri.host = nil
|
111
|
-
uri
|
112
|
-
else
|
113
|
-
URI.parse("#{alt_scheme}://#{alt_origin}")
|
114
|
-
end
|
115
|
-
end
|
116
|
-
else
|
117
|
-
def parse_altsvc_origin(alt_proto, alt_origin)
|
118
|
-
alt_scheme = parse_altsvc_scheme(alt_proto) or return
|
119
|
-
alt_origin = alt_origin[1..-2] if alt_origin.start_with?("\"") && alt_origin.end_with?("\"")
|
153
|
+
def parse_altsvc_origin(alt_proto, alt_origin)
|
154
|
+
alt_scheme = parse_altsvc_scheme(alt_proto)
|
120
155
|
|
121
|
-
|
122
|
-
|
156
|
+
return unless alt_scheme
|
157
|
+
|
158
|
+
alt_origin = alt_origin[1..-2] if alt_origin.start_with?("\"") && alt_origin.end_with?("\"")
|
159
|
+
|
160
|
+
URI.parse("#{alt_scheme}://#{alt_origin}")
|
123
161
|
end
|
124
|
-
# :nocov:
|
125
162
|
end
|
126
163
|
end
|
data/lib/httpx/base64.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if RUBY_VERSION < "3.3.0"
|
4
|
+
require "base64"
|
5
|
+
elsif !defined?(Base64)
|
6
|
+
module HTTPX
|
7
|
+
# require "base64" will not be a default gem after ruby 3.4.0
|
8
|
+
module Base64
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def decode64(str)
|
12
|
+
str.unpack1("m")
|
13
|
+
end
|
14
|
+
|
15
|
+
def strict_encode64(bin)
|
16
|
+
[bin].pack("m0")
|
17
|
+
end
|
18
|
+
|
19
|
+
def urlsafe_encode64(bin, padding: true)
|
20
|
+
str = strict_encode64(bin)
|
21
|
+
str.chomp!("==") or str.chomp!("=") unless padding
|
22
|
+
str.tr!("+/", "-_")
|
23
|
+
str
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/httpx/buffer.rb
CHANGED
@@ -3,6 +3,14 @@
|
|
3
3
|
require "forwardable"
|
4
4
|
|
5
5
|
module HTTPX
|
6
|
+
# Internal class to abstract a string buffer, by wrapping a string and providing the
|
7
|
+
# minimum possible API and functionality required.
|
8
|
+
#
|
9
|
+
# buffer = Buffer.new(640)
|
10
|
+
# buffer.full? #=> false
|
11
|
+
# buffer << "aa"
|
12
|
+
# buffer.capacity #=> 638
|
13
|
+
#
|
6
14
|
class Buffer
|
7
15
|
extend Forwardable
|
8
16
|
|
@@ -31,6 +39,10 @@ module HTTPX
|
|
31
39
|
@buffer.bytesize >= @limit
|
32
40
|
end
|
33
41
|
|
42
|
+
def capacity
|
43
|
+
@limit - @buffer.bytesize
|
44
|
+
end
|
45
|
+
|
34
46
|
def shift!(fin)
|
35
47
|
@buffer = @buffer.byteslice(fin..-1) || "".b
|
36
48
|
end
|