httpx 1.5.1 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/doc/release_notes/1_6_0.md +50 -0
- data/doc/release_notes/1_6_1.md +17 -0
- data/lib/httpx/adapters/datadog.rb +23 -13
- data/lib/httpx/adapters/faraday.rb +14 -9
- data/lib/httpx/adapters/webmock.rb +1 -1
- data/lib/httpx/callbacks.rb +1 -1
- data/lib/httpx/connection/http1.rb +5 -6
- data/lib/httpx/connection/http2.rb +34 -18
- data/lib/httpx/connection.rb +19 -26
- data/lib/httpx/errors.rb +3 -1
- data/lib/httpx/io/ssl.rb +1 -4
- data/lib/httpx/io/tcp.rb +52 -21
- data/lib/httpx/io/unix.rb +4 -3
- data/lib/httpx/loggable.rb +4 -1
- data/lib/httpx/options.rb +248 -160
- data/lib/httpx/plugins/aws_sdk_authentication.rb +2 -0
- data/lib/httpx/plugins/aws_sigv4.rb +2 -0
- data/lib/httpx/plugins/callbacks.rb +13 -1
- data/lib/httpx/plugins/circuit_breaker.rb +2 -0
- data/lib/httpx/plugins/content_digest.rb +2 -0
- data/lib/httpx/plugins/cookies.rb +2 -2
- data/lib/httpx/plugins/digest_auth.rb +2 -0
- data/lib/httpx/plugins/expect.rb +2 -0
- data/lib/httpx/plugins/fiber_concurrency.rb +195 -0
- data/lib/httpx/plugins/follow_redirects.rb +2 -0
- data/lib/httpx/plugins/grpc.rb +2 -0
- data/lib/httpx/plugins/h2c.rb +26 -16
- data/lib/httpx/plugins/internal_telemetry.rb +0 -49
- data/lib/httpx/plugins/ntlm_auth.rb +2 -0
- data/lib/httpx/plugins/oauth.rb +10 -2
- data/lib/httpx/plugins/persistent.rb +27 -18
- data/lib/httpx/plugins/proxy/socks4.rb +1 -1
- data/lib/httpx/plugins/proxy/socks5.rb +1 -1
- data/lib/httpx/plugins/proxy/ssh.rb +2 -0
- data/lib/httpx/plugins/proxy.rb +61 -20
- data/lib/httpx/plugins/response_cache/file_store.rb +2 -2
- data/lib/httpx/plugins/response_cache.rb +2 -0
- data/lib/httpx/plugins/retries.rb +2 -0
- data/lib/httpx/plugins/ssrf_filter.rb +2 -2
- data/lib/httpx/plugins/stream_bidi.rb +3 -3
- data/lib/httpx/plugins/upgrade/h2.rb +11 -1
- data/lib/httpx/plugins/upgrade.rb +8 -0
- data/lib/httpx/pool.rb +15 -10
- data/lib/httpx/request/body.rb +8 -3
- data/lib/httpx/request.rb +22 -11
- data/lib/httpx/resolver/entry.rb +30 -0
- data/lib/httpx/resolver/https.rb +3 -1
- data/lib/httpx/resolver/multi.rb +16 -3
- data/lib/httpx/resolver/native.rb +15 -6
- data/lib/httpx/resolver/resolver.rb +15 -11
- data/lib/httpx/resolver/system.rb +5 -3
- data/lib/httpx/resolver.rb +49 -21
- data/lib/httpx/response/body.rb +1 -1
- data/lib/httpx/response/buffer.rb +13 -18
- data/lib/httpx/selector.rb +92 -34
- data/lib/httpx/session.rb +89 -30
- data/lib/httpx/session_extensions.rb +3 -2
- data/lib/httpx/transcoder/form.rb +1 -13
- data/lib/httpx/transcoder/multipart/mime_type_detector.rb +1 -1
- data/lib/httpx/transcoder/multipart.rb +14 -0
- data/lib/httpx/transcoder/utils/deflater.rb +1 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/callbacks.rbs +1 -1
- data/sig/chainable.rbs +1 -0
- data/sig/connection/http1.rbs +2 -0
- data/sig/connection/http2.rbs +5 -1
- data/sig/connection.rbs +6 -6
- data/sig/errors.rbs +3 -1
- data/sig/io/ssl.rbs +1 -1
- data/sig/io/tcp.rbs +13 -7
- data/sig/io/udp.rbs +7 -2
- data/sig/io/unix.rbs +0 -1
- data/sig/io.rbs +0 -3
- data/sig/options.rbs +64 -11
- data/sig/plugins/fiber_concurrency.rbs +51 -0
- data/sig/plugins/h2c.rbs +5 -1
- data/sig/plugins/oauth.rbs +15 -1
- data/sig/plugins/persistent.rbs +1 -1
- data/sig/plugins/proxy/socks4.rbs +1 -1
- data/sig/plugins/proxy/socks5.rbs +1 -1
- data/sig/plugins/proxy.rbs +5 -2
- data/sig/plugins/ssrf_filter.rbs +1 -1
- data/sig/plugins/stream_bidi.rbs +2 -2
- data/sig/request.rbs +4 -1
- data/sig/resolver/entry.rbs +13 -0
- data/sig/resolver/native.rbs +1 -0
- data/sig/resolver/resolver.rbs +2 -3
- data/sig/resolver/system.rbs +2 -2
- data/sig/resolver.rbs +12 -11
- data/sig/response.rbs +2 -2
- data/sig/selector.rbs +18 -10
- data/sig/session.rbs +4 -0
- data/sig/transcoder/form.rbs +3 -3
- data/sig/transcoder/multipart.rbs +9 -3
- metadata +11 -3
data/lib/httpx/options.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "socket"
|
4
|
-
|
5
3
|
module HTTPX
|
6
4
|
# Contains a set of options which are passed and shared across from session to its requests or
|
7
5
|
# responses.
|
@@ -15,70 +13,16 @@ module HTTPX
|
|
15
13
|
CONNECT_TIMEOUT = READ_TIMEOUT = WRITE_TIMEOUT = 60
|
16
14
|
REQUEST_TIMEOUT = OPERATION_TIMEOUT = nil
|
17
15
|
|
18
|
-
|
19
|
-
ip_address_families = begin
|
20
|
-
list = Socket.ip_address_list
|
21
|
-
if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? && !a.ipv6_unique_local? }
|
22
|
-
[Socket::AF_INET6, Socket::AF_INET]
|
23
|
-
else
|
24
|
-
[Socket::AF_INET]
|
25
|
-
end
|
26
|
-
rescue NotImplementedError
|
27
|
-
[Socket::AF_INET]
|
28
|
-
end.freeze
|
16
|
+
@options_names = []
|
29
17
|
|
30
|
-
|
31
|
-
|
32
|
-
name = mod.name || "#{mod.superclass.name}(plugin)"
|
33
|
-
name = "#{name}/#{pl}" if pl
|
34
|
-
mod.set_temporary_name(name)
|
35
|
-
end
|
36
|
-
end
|
18
|
+
class << self
|
19
|
+
attr_reader :options_names
|
37
20
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
:debug_redact => ENV.key?("HTTPX_DEBUG_REDACT"),
|
43
|
-
:ssl => EMPTY_HASH,
|
44
|
-
:http2_settings => { settings_enable_push: 0 }.freeze,
|
45
|
-
:fallback_protocol => "http/1.1",
|
46
|
-
:supported_compression_formats => %w[gzip deflate],
|
47
|
-
:decompress_response_body => true,
|
48
|
-
:compress_request_body => true,
|
49
|
-
:timeout => {
|
50
|
-
connect_timeout: CONNECT_TIMEOUT,
|
51
|
-
settings_timeout: SETTINGS_TIMEOUT,
|
52
|
-
close_handshake_timeout: CLOSE_HANDSHAKE_TIMEOUT,
|
53
|
-
operation_timeout: OPERATION_TIMEOUT,
|
54
|
-
keep_alive_timeout: KEEP_ALIVE_TIMEOUT,
|
55
|
-
read_timeout: READ_TIMEOUT,
|
56
|
-
write_timeout: WRITE_TIMEOUT,
|
57
|
-
request_timeout: REQUEST_TIMEOUT,
|
58
|
-
},
|
59
|
-
:headers_class => Class.new(Headers, &SET_TEMPORARY_NAME),
|
60
|
-
:headers => {},
|
61
|
-
:window_size => WINDOW_SIZE,
|
62
|
-
:buffer_size => BUFFER_SIZE,
|
63
|
-
:body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
|
64
|
-
:request_class => Class.new(Request, &SET_TEMPORARY_NAME),
|
65
|
-
:response_class => Class.new(Response, &SET_TEMPORARY_NAME),
|
66
|
-
:request_body_class => Class.new(Request::Body, &SET_TEMPORARY_NAME),
|
67
|
-
:response_body_class => Class.new(Response::Body, &SET_TEMPORARY_NAME),
|
68
|
-
:pool_class => Class.new(Pool, &SET_TEMPORARY_NAME),
|
69
|
-
:connection_class => Class.new(Connection, &SET_TEMPORARY_NAME),
|
70
|
-
:options_class => Class.new(self, &SET_TEMPORARY_NAME),
|
71
|
-
:transport => nil,
|
72
|
-
:addresses => nil,
|
73
|
-
:persistent => false,
|
74
|
-
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
75
|
-
:resolver_options => { cache: true }.freeze,
|
76
|
-
:pool_options => EMPTY_HASH,
|
77
|
-
:ip_families => ip_address_families,
|
78
|
-
:close_on_fork => false,
|
79
|
-
}.freeze
|
21
|
+
def inherited(klass)
|
22
|
+
super
|
23
|
+
klass.instance_variable_set(:@options_names, @options_names.dup)
|
24
|
+
end
|
80
25
|
|
81
|
-
class << self
|
82
26
|
def new(options = {})
|
83
27
|
# let enhanced options go through
|
84
28
|
return options if self == Options && options.class < self
|
@@ -87,14 +31,34 @@ module HTTPX
|
|
87
31
|
super
|
88
32
|
end
|
89
33
|
|
34
|
+
def freeze
|
35
|
+
@options_names.freeze
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
90
39
|
def method_added(meth)
|
91
40
|
super
|
92
41
|
|
93
42
|
return unless meth =~ /^option_(.+)$/
|
94
43
|
|
95
|
-
optname = Regexp.last_match(1)
|
44
|
+
optname = Regexp.last_match(1)
|
45
|
+
|
46
|
+
if optname =~ /^(.+[^_])_+with/
|
47
|
+
# ignore alias method chain generated methods.
|
48
|
+
# this is the case with RBS runtime tests.
|
49
|
+
# it relies on the "_with/_without" separator, which is the most used convention,
|
50
|
+
# however it shouldn't be used in practice in httpx given the plugin architecture
|
51
|
+
# as the main extension API.
|
52
|
+
orig_name = Regexp.last_match(1)
|
53
|
+
|
54
|
+
return if @options_names.include?(orig_name.to_sym)
|
55
|
+
end
|
56
|
+
|
57
|
+
optname = optname.to_sym
|
96
58
|
|
97
59
|
attr_reader(optname)
|
60
|
+
|
61
|
+
@options_names << optname unless @options_names.include?(optname)
|
98
62
|
end
|
99
63
|
end
|
100
64
|
|
@@ -103,7 +67,7 @@ module HTTPX
|
|
103
67
|
# :debug :: an object which log messages are written to (must respond to <tt><<</tt>)
|
104
68
|
# :debug_level :: the log level of messages (can be 1, 2, or 3).
|
105
69
|
# :debug_redact :: whether header/body payload should be redacted (defaults to <tt>false</tt>).
|
106
|
-
# :ssl :: a hash of options which can be set as params of OpenSSL::SSL::SSLContext (see HTTPX::
|
70
|
+
# :ssl :: a hash of options which can be set as params of OpenSSL::SSL::SSLContext (see HTTPX::SSL)
|
107
71
|
# :http2_settings :: a hash of options to be passed to a HTTP2::Connection (ex: <tt>{ max_concurrent_streams: 2 }</tt>)
|
108
72
|
# :fallback_protocol :: version of HTTP protocol to use by default in the absence of protocol negotiation
|
109
73
|
# like ALPN (defaults to <tt>"http/1.1"</tt>)
|
@@ -123,6 +87,11 @@ module HTTPX
|
|
123
87
|
# :request_body_class :: class used to instantiate a request body
|
124
88
|
# :response_body_class :: class used to instantiate a response body
|
125
89
|
# :connection_class :: class used to instantiate connections
|
90
|
+
# :http1_class :: class used to manage HTTP1 sessions
|
91
|
+
# :http2_class :: class used to imanage HTTP2 sessions
|
92
|
+
# :resolver_native_class :: class used to resolve names using pure ruby DNS implementation
|
93
|
+
# :resolver_system_class :: class used to resolve names using system-based (getaddrinfo) name resolution
|
94
|
+
# :resolver_https_class :: class used to resolve names using DoH
|
126
95
|
# :pool_class :: class used to instantiate the session connection pool
|
127
96
|
# :options_class :: class used to instantiate options
|
128
97
|
# :transport :: type of transport to use (set to "unix" for UNIX sockets)
|
@@ -143,99 +112,54 @@ module HTTPX
|
|
143
112
|
# it only works if the session is persistent (and ruby 3.1 or higher is used).
|
144
113
|
#
|
145
114
|
# This list of options are enhanced with each loaded plugin, see the plugin docs for details.
|
146
|
-
def initialize(options =
|
147
|
-
|
148
|
-
freeze
|
149
|
-
end
|
150
|
-
|
151
|
-
def freeze
|
152
|
-
@origin.freeze
|
153
|
-
@base_path.freeze
|
154
|
-
@timeout.freeze
|
155
|
-
@headers.freeze
|
156
|
-
@addresses.freeze
|
157
|
-
@supported_compression_formats.freeze
|
158
|
-
@ssl.freeze
|
159
|
-
@http2_settings.freeze
|
160
|
-
@pool_options.freeze
|
161
|
-
@resolver_options.freeze
|
162
|
-
@ip_families.freeze
|
163
|
-
super
|
164
|
-
end
|
115
|
+
def initialize(options = EMPTY_HASH)
|
116
|
+
options_names = self.class.options_names
|
165
117
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
def option_base_path(value)
|
171
|
-
String(value)
|
172
|
-
end
|
173
|
-
|
174
|
-
def option_headers(value)
|
175
|
-
headers_class.new(value)
|
176
|
-
end
|
177
|
-
|
178
|
-
def option_timeout(value)
|
179
|
-
Hash[value]
|
180
|
-
end
|
118
|
+
defaults =
|
119
|
+
case options
|
120
|
+
when Options
|
121
|
+
unknown_options = options.class.options_names - options_names
|
181
122
|
|
182
|
-
|
183
|
-
Array(value).map(&:to_s)
|
184
|
-
end
|
123
|
+
raise Error, "unknown option: #{unknown_options.first}" unless unknown_options.empty?
|
185
124
|
|
186
|
-
|
187
|
-
|
188
|
-
|
125
|
+
DEFAULT_OPTIONS.merge(options)
|
126
|
+
else
|
127
|
+
options.each_key do |k|
|
128
|
+
raise Error, "unknown option: #{k}" unless options_names.include?(k)
|
129
|
+
end
|
189
130
|
|
190
|
-
|
191
|
-
|
131
|
+
options.empty? ? DEFAULT_OPTIONS : DEFAULT_OPTIONS.merge(options)
|
132
|
+
end
|
192
133
|
|
193
|
-
|
194
|
-
|
195
|
-
end
|
134
|
+
options_names.each do |k|
|
135
|
+
v = defaults[k]
|
196
136
|
|
197
|
-
|
198
|
-
|
199
|
-
end
|
137
|
+
if v.nil?
|
138
|
+
instance_variable_set(:"@#{k}", v)
|
200
139
|
|
201
|
-
|
202
|
-
%i[
|
203
|
-
max_concurrent_requests max_requests window_size buffer_size
|
204
|
-
body_threshold_size debug_level
|
205
|
-
].each do |option|
|
206
|
-
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
207
|
-
# converts +v+ into an Integer before setting the +#{option}+ option.
|
208
|
-
def option_#{option}(value) # def option_max_requests(v)
|
209
|
-
value = Integer(value) unless value.infinite?
|
210
|
-
raise TypeError, ":#{option} must be positive" unless value.positive? # raise TypeError, ":max_requests must be positive" unless value.positive?
|
211
|
-
|
212
|
-
value
|
140
|
+
next
|
213
141
|
end
|
214
|
-
OUT
|
215
|
-
end
|
216
142
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
Hash[value]
|
223
|
-
end
|
224
|
-
OUT
|
143
|
+
value = __send__(:"option_#{k}", v)
|
144
|
+
instance_variable_set(:"@#{k}", value)
|
145
|
+
end
|
146
|
+
|
147
|
+
freeze
|
225
148
|
end
|
226
149
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
150
|
+
def freeze
|
151
|
+
self.class.options_names.each do |ivar|
|
152
|
+
# avoid freezing debug option, as when it's set, it's usually an
|
153
|
+
# object which cannot be frozen, like stderr or stdout. It's a
|
154
|
+
# documented exception then, and still does not defeat the purpose
|
155
|
+
# here, which is to make option objects shareable across ractors,
|
156
|
+
# and in most cases debug should be nil, or one of the objects
|
157
|
+
# which will eventually be shareable, like STDOUT or STDERR.
|
158
|
+
next if ivar == :debug
|
159
|
+
|
160
|
+
instance_variable_get(:"@#{ivar}").freeze
|
161
|
+
end
|
162
|
+
super
|
239
163
|
end
|
240
164
|
|
241
165
|
REQUEST_BODY_IVARS = %i[@headers].freeze
|
@@ -262,11 +186,12 @@ module HTTPX
|
|
262
186
|
def merge(other)
|
263
187
|
ivar_map = nil
|
264
188
|
other_ivars = case other
|
265
|
-
when
|
189
|
+
when Options
|
190
|
+
other.instance_variables
|
191
|
+
else
|
192
|
+
other = Hash[other] unless other.is_a?(Hash)
|
266
193
|
ivar_map = other.keys.to_h { |k| [:"@#{k}", k] }
|
267
194
|
ivar_map.keys
|
268
|
-
else
|
269
|
-
other.instance_variables
|
270
195
|
end
|
271
196
|
|
272
197
|
return self if other_ivars.empty?
|
@@ -297,70 +222,177 @@ module HTTPX
|
|
297
222
|
|
298
223
|
def to_hash
|
299
224
|
instance_variables.each_with_object({}) do |ivar, hs|
|
300
|
-
|
225
|
+
val = instance_variable_get(ivar)
|
226
|
+
|
227
|
+
next if val.nil?
|
228
|
+
|
229
|
+
hs[ivar[1..-1].to_sym] = val
|
301
230
|
end
|
302
231
|
end
|
303
232
|
|
304
233
|
def extend_with_plugin_classes(pl)
|
234
|
+
# extend request class
|
305
235
|
if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
|
306
236
|
@request_class = @request_class.dup
|
307
237
|
SET_TEMPORARY_NAME[@request_class, pl]
|
308
238
|
@request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
|
309
239
|
@request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
|
310
240
|
end
|
241
|
+
# extend response class
|
311
242
|
if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
|
312
243
|
@response_class = @response_class.dup
|
313
244
|
SET_TEMPORARY_NAME[@response_class, pl]
|
314
245
|
@response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
|
315
246
|
@response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
|
316
247
|
end
|
248
|
+
# extend headers class
|
317
249
|
if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
|
318
250
|
@headers_class = @headers_class.dup
|
319
251
|
SET_TEMPORARY_NAME[@headers_class, pl]
|
320
252
|
@headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
|
321
253
|
@headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
|
322
254
|
end
|
255
|
+
# extend request body class
|
323
256
|
if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
|
324
257
|
@request_body_class = @request_body_class.dup
|
325
258
|
SET_TEMPORARY_NAME[@request_body_class, pl]
|
326
259
|
@request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
|
327
260
|
@request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
|
328
261
|
end
|
262
|
+
# extend response body class
|
329
263
|
if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
|
330
264
|
@response_body_class = @response_body_class.dup
|
331
265
|
SET_TEMPORARY_NAME[@response_body_class, pl]
|
332
266
|
@response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
|
333
267
|
@response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
|
334
268
|
end
|
269
|
+
# extend connection pool class
|
335
270
|
if defined?(pl::PoolMethods)
|
336
271
|
@pool_class = @pool_class.dup
|
337
272
|
SET_TEMPORARY_NAME[@pool_class, pl]
|
338
273
|
@pool_class.__send__(:include, pl::PoolMethods)
|
339
274
|
end
|
275
|
+
# extend connection class
|
340
276
|
if defined?(pl::ConnectionMethods)
|
341
277
|
@connection_class = @connection_class.dup
|
342
278
|
SET_TEMPORARY_NAME[@connection_class, pl]
|
343
279
|
@connection_class.__send__(:include, pl::ConnectionMethods)
|
344
280
|
end
|
281
|
+
# extend http1 class
|
282
|
+
if defined?(pl::HTTP1Methods)
|
283
|
+
@http1_class = @http1_class.dup
|
284
|
+
SET_TEMPORARY_NAME[@http1_class, pl]
|
285
|
+
@http1_class.__send__(:include, pl::HTTP1Methods)
|
286
|
+
end
|
287
|
+
# extend http2 class
|
288
|
+
if defined?(pl::HTTP2Methods)
|
289
|
+
@http2_class = @http2_class.dup
|
290
|
+
SET_TEMPORARY_NAME[@http2_class, pl]
|
291
|
+
@http2_class.__send__(:include, pl::HTTP2Methods)
|
292
|
+
end
|
293
|
+
# extend native resolver class
|
294
|
+
if defined?(pl::ResolverNativeMethods)
|
295
|
+
@resolver_native_class = @resolver_native_class.dup
|
296
|
+
SET_TEMPORARY_NAME[@resolver_native_class, pl]
|
297
|
+
@resolver_native_class.__send__(:include, pl::ResolverNativeMethods)
|
298
|
+
end
|
299
|
+
# extend system resolver class
|
300
|
+
if defined?(pl::ResolverSystemMethods)
|
301
|
+
@resolver_system_class = @resolver_system_class.dup
|
302
|
+
SET_TEMPORARY_NAME[@resolver_system_class, pl]
|
303
|
+
@resolver_system_class.__send__(:include, pl::ResolverSystemMethods)
|
304
|
+
end
|
305
|
+
# extend https resolver class
|
306
|
+
if defined?(pl::ResolverHTTPSMethods)
|
307
|
+
@resolver_https_class = @resolver_https_class.dup
|
308
|
+
SET_TEMPORARY_NAME[@resolver_https_class, pl]
|
309
|
+
@resolver_https_class.__send__(:include, pl::ResolverHTTPSMethods)
|
310
|
+
end
|
311
|
+
|
345
312
|
return unless defined?(pl::OptionsMethods)
|
346
313
|
|
314
|
+
# extend option class
|
315
|
+
# works around lack of initialize_dup callback
|
347
316
|
@options_class = @options_class.dup
|
317
|
+
# (self.class.options_names)
|
348
318
|
@options_class.__send__(:include, pl::OptionsMethods)
|
349
319
|
end
|
350
320
|
|
351
321
|
private
|
352
322
|
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
323
|
+
# number options
|
324
|
+
%i[
|
325
|
+
max_concurrent_requests max_requests window_size buffer_size
|
326
|
+
body_threshold_size debug_level
|
327
|
+
].each do |option|
|
328
|
+
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
329
|
+
# converts +v+ into an Integer before setting the +#{option}+ option.
|
330
|
+
private def option_#{option}(value) # private def option_max_requests(v)
|
331
|
+
value = Integer(value) unless value.respond_to?(:infinite?) && value.infinite?
|
332
|
+
raise TypeError, ":#{option} must be positive" unless value.positive? # raise TypeError, ":max_requests must be positive" unless value.positive?
|
357
333
|
|
358
|
-
|
359
|
-
|
334
|
+
value
|
335
|
+
end
|
336
|
+
OUT
|
337
|
+
end
|
360
338
|
|
361
|
-
|
362
|
-
|
363
|
-
|
339
|
+
# hashable options
|
340
|
+
%i[ssl http2_settings resolver_options pool_options].each do |option|
|
341
|
+
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
342
|
+
# converts +v+ into an Hash before setting the +#{option}+ option.
|
343
|
+
private def option_#{option}(value) # def option_ssl(v)
|
344
|
+
Hash[value]
|
345
|
+
end
|
346
|
+
OUT
|
347
|
+
end
|
348
|
+
|
349
|
+
%i[
|
350
|
+
request_class response_class headers_class request_body_class
|
351
|
+
response_body_class connection_class http1_class http2_class
|
352
|
+
resolver_native_class resolver_system_class resolver_https_class options_class pool_class
|
353
|
+
io fallback_protocol debug debug_redact resolver_class
|
354
|
+
compress_request_body decompress_response_body
|
355
|
+
persistent close_on_fork
|
356
|
+
].each do |method_name|
|
357
|
+
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
358
|
+
# sets +v+ as the value of the +#{method_name}+ option
|
359
|
+
private def option_#{method_name}(v); v; end # private def option_smth(v); v; end
|
360
|
+
OUT
|
361
|
+
end
|
362
|
+
|
363
|
+
def option_origin(value)
|
364
|
+
URI(value)
|
365
|
+
end
|
366
|
+
|
367
|
+
def option_base_path(value)
|
368
|
+
String(value)
|
369
|
+
end
|
370
|
+
|
371
|
+
def option_headers(value)
|
372
|
+
headers_class.new(value)
|
373
|
+
end
|
374
|
+
|
375
|
+
def option_timeout(value)
|
376
|
+
Hash[value]
|
377
|
+
end
|
378
|
+
|
379
|
+
def option_supported_compression_formats(value)
|
380
|
+
Array(value).map(&:to_s)
|
381
|
+
end
|
382
|
+
|
383
|
+
def option_transport(value)
|
384
|
+
transport = value.to_s
|
385
|
+
raise TypeError, "#{transport} is an unsupported transport type" unless %w[unix].include?(transport)
|
386
|
+
|
387
|
+
transport
|
388
|
+
end
|
389
|
+
|
390
|
+
def option_addresses(value)
|
391
|
+
Array(value).map { |entry| Resolver::Entry.convert(entry) }
|
392
|
+
end
|
393
|
+
|
394
|
+
def option_ip_families(value)
|
395
|
+
Array(value)
|
364
396
|
end
|
365
397
|
|
366
398
|
def access_option(obj, k, ivar_map)
|
@@ -371,5 +403,61 @@ module HTTPX
|
|
371
403
|
obj.instance_variable_get(k)
|
372
404
|
end
|
373
405
|
end
|
406
|
+
|
407
|
+
SET_TEMPORARY_NAME = ->(klass, pl = nil) do
|
408
|
+
if klass.respond_to?(:set_temporary_name) # ruby 3.4 only
|
409
|
+
name = klass.name || "#{klass.superclass.name}(plugin)"
|
410
|
+
name = "#{name}/#{pl}" if pl
|
411
|
+
klass.set_temporary_name(name)
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
DEFAULT_OPTIONS = {
|
416
|
+
:max_requests => Float::INFINITY,
|
417
|
+
:debug => nil,
|
418
|
+
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
|
419
|
+
:debug_redact => ENV.key?("HTTPX_DEBUG_REDACT"),
|
420
|
+
:ssl => EMPTY_HASH,
|
421
|
+
:http2_settings => { settings_enable_push: 0 }.freeze,
|
422
|
+
:fallback_protocol => "http/1.1",
|
423
|
+
:supported_compression_formats => %w[gzip deflate],
|
424
|
+
:decompress_response_body => true,
|
425
|
+
:compress_request_body => true,
|
426
|
+
:timeout => {
|
427
|
+
connect_timeout: CONNECT_TIMEOUT,
|
428
|
+
settings_timeout: SETTINGS_TIMEOUT,
|
429
|
+
close_handshake_timeout: CLOSE_HANDSHAKE_TIMEOUT,
|
430
|
+
operation_timeout: OPERATION_TIMEOUT,
|
431
|
+
keep_alive_timeout: KEEP_ALIVE_TIMEOUT,
|
432
|
+
read_timeout: READ_TIMEOUT,
|
433
|
+
write_timeout: WRITE_TIMEOUT,
|
434
|
+
request_timeout: REQUEST_TIMEOUT,
|
435
|
+
}.freeze,
|
436
|
+
:headers_class => Class.new(Headers, &SET_TEMPORARY_NAME),
|
437
|
+
:headers => EMPTY_HASH,
|
438
|
+
:window_size => WINDOW_SIZE,
|
439
|
+
:buffer_size => BUFFER_SIZE,
|
440
|
+
:body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
|
441
|
+
:request_class => Class.new(Request, &SET_TEMPORARY_NAME),
|
442
|
+
:response_class => Class.new(Response, &SET_TEMPORARY_NAME),
|
443
|
+
:request_body_class => Class.new(Request::Body, &SET_TEMPORARY_NAME),
|
444
|
+
:response_body_class => Class.new(Response::Body, &SET_TEMPORARY_NAME),
|
445
|
+
:pool_class => Class.new(Pool, &SET_TEMPORARY_NAME),
|
446
|
+
:connection_class => Class.new(Connection, &SET_TEMPORARY_NAME),
|
447
|
+
:http1_class => Class.new(Connection::HTTP1, &SET_TEMPORARY_NAME),
|
448
|
+
:http2_class => Class.new(Connection::HTTP2, &SET_TEMPORARY_NAME),
|
449
|
+
:resolver_native_class => Class.new(Resolver::Native, &SET_TEMPORARY_NAME),
|
450
|
+
:resolver_system_class => Class.new(Resolver::System, &SET_TEMPORARY_NAME),
|
451
|
+
:resolver_https_class => Class.new(Resolver::HTTPS, &SET_TEMPORARY_NAME),
|
452
|
+
:options_class => Class.new(self, &SET_TEMPORARY_NAME),
|
453
|
+
:transport => nil,
|
454
|
+
:addresses => nil,
|
455
|
+
:persistent => false,
|
456
|
+
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
457
|
+
:resolver_options => { cache: true }.freeze,
|
458
|
+
:pool_options => EMPTY_HASH,
|
459
|
+
:ip_families => nil,
|
460
|
+
:close_on_fork => false,
|
461
|
+
}.freeze
|
374
462
|
end
|
375
463
|
end
|
@@ -32,6 +32,18 @@ module HTTPX
|
|
32
32
|
MOD
|
33
33
|
end
|
34
34
|
|
35
|
+
def plugin(*args, &blk)
|
36
|
+
super(*args).tap do |sess|
|
37
|
+
CALLBACKS.each do |cb|
|
38
|
+
next unless callbacks_for?(cb)
|
39
|
+
|
40
|
+
sess.callbacks(cb).concat(callbacks(cb))
|
41
|
+
end
|
42
|
+
|
43
|
+
sess.wrap(&blk) if blk
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
35
47
|
private
|
36
48
|
|
37
49
|
def branch(options, &blk)
|
@@ -85,7 +97,7 @@ module HTTPX
|
|
85
97
|
end
|
86
98
|
end
|
87
99
|
request.on(:response) do |res|
|
88
|
-
emit_or_callback_error(:response_completed, request, res)
|
100
|
+
emit_or_callback_error(:response_completed, request, res) if res.is_a?(Response)
|
89
101
|
end
|
90
102
|
end
|
91
103
|
|
@@ -105,6 +105,8 @@ module HTTPX
|
|
105
105
|
# :circuit_breaker_half_open_drip_rate :: the rate of requests a circuit allows to be performed when in an half-open state
|
106
106
|
# (defaults to <tt>1</tt>).
|
107
107
|
module OptionsMethods
|
108
|
+
private
|
109
|
+
|
108
110
|
def option_circuit_breaker_max_attempts(value)
|
109
111
|
attempts = Integer(value)
|
110
112
|
raise TypeError, ":circuit_breaker_max_attempts must be positive" unless attempts.positive?
|
@@ -43,6 +43,8 @@ module HTTPX
|
|
43
43
|
# :validate_content_digest :: whether a <tt>Content-Digest</tt> header in the response should be validated;
|
44
44
|
# can also be a callable object (i.e. <tt>->(res) { ... }</tt>, defaults to <tt>false</tt>)
|
45
45
|
module OptionsMethods
|
46
|
+
private
|
47
|
+
|
46
48
|
def option_content_digest_algorithm(value)
|
47
49
|
raise TypeError, ":content_digest_algorithm must be one of 'sha-256', 'sha-512'" unless SUPPORTED_ALGORITHMS.key?(value)
|
48
50
|
|
@@ -74,6 +74,8 @@ module HTTPX
|
|
74
74
|
#
|
75
75
|
# :cookies :: cookie jar for the session (can be a Hash, an Array, an instance of HTTPX::Plugins::Cookies::CookieJar)
|
76
76
|
module OptionsMethods
|
77
|
+
private
|
78
|
+
|
77
79
|
def option_headers(*)
|
78
80
|
value = super
|
79
81
|
|
@@ -90,8 +92,6 @@ module HTTPX
|
|
90
92
|
jar
|
91
93
|
end
|
92
94
|
|
93
|
-
private
|
94
|
-
|
95
95
|
def merge_cookie_in_jar(cookies, jar)
|
96
96
|
cookies.each do |ck|
|
97
97
|
ck.split(/ *; */).each do |cookie|
|
@@ -24,6 +24,8 @@ module HTTPX
|
|
24
24
|
#
|
25
25
|
# :digest :: instance of HTTPX::Plugins::Authentication::Digest, used to authenticate requests in the session.
|
26
26
|
module OptionsMethods
|
27
|
+
private
|
28
|
+
|
27
29
|
def option_digest(value)
|
28
30
|
raise TypeError, ":digest must be a #{Authentication::Digest}" unless value.is_a?(Authentication::Digest)
|
29
31
|
|
data/lib/httpx/plugins/expect.rb
CHANGED
@@ -26,6 +26,8 @@ module HTTPX
|
|
26
26
|
# before retrying without the Expect header (defaults to <tt>2</tt>).
|
27
27
|
# :expect_threshold_size :: min threshold (in bytes) of the request payload to enable the 100-continue negotiation on.
|
28
28
|
module OptionsMethods
|
29
|
+
private
|
30
|
+
|
29
31
|
def option_expect_timeout(value)
|
30
32
|
seconds = Float(value)
|
31
33
|
raise TypeError, ":expect_timeout must be positive" unless seconds.positive?
|