httpx-patched 1.6.2.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 +7 -0
- data/LICENSE.txt +191 -0
- data/README.md +162 -0
- data/doc/release_notes/0_0_1.md +7 -0
- data/doc/release_notes/0_0_2.md +9 -0
- data/doc/release_notes/0_0_3.md +9 -0
- data/doc/release_notes/0_0_4.md +7 -0
- data/doc/release_notes/0_0_5.md +5 -0
- data/doc/release_notes/0_10_0.md +66 -0
- data/doc/release_notes/0_10_1.md +37 -0
- data/doc/release_notes/0_10_2.md +5 -0
- data/doc/release_notes/0_11_0.md +74 -0
- data/doc/release_notes/0_11_1.md +5 -0
- data/doc/release_notes/0_11_2.md +5 -0
- data/doc/release_notes/0_11_3.md +5 -0
- data/doc/release_notes/0_12_0.md +55 -0
- data/doc/release_notes/0_13_0.md +58 -0
- data/doc/release_notes/0_13_1.md +5 -0
- data/doc/release_notes/0_13_2.md +9 -0
- data/doc/release_notes/0_14_0.md +79 -0
- data/doc/release_notes/0_14_1.md +7 -0
- data/doc/release_notes/0_14_2.md +6 -0
- data/doc/release_notes/0_14_3.md +5 -0
- data/doc/release_notes/0_14_4.md +5 -0
- data/doc/release_notes/0_14_5.md +11 -0
- data/doc/release_notes/0_15_0.md +53 -0
- data/doc/release_notes/0_15_1.md +8 -0
- data/doc/release_notes/0_15_2.md +9 -0
- data/doc/release_notes/0_15_3.md +5 -0
- data/doc/release_notes/0_15_4.md +5 -0
- data/doc/release_notes/0_16_0.md +93 -0
- data/doc/release_notes/0_16_1.md +5 -0
- data/doc/release_notes/0_17_0.md +49 -0
- data/doc/release_notes/0_18_0.md +69 -0
- data/doc/release_notes/0_18_1.md +12 -0
- data/doc/release_notes/0_18_2.md +10 -0
- data/doc/release_notes/0_18_3.md +7 -0
- data/doc/release_notes/0_18_4.md +14 -0
- data/doc/release_notes/0_18_5.md +10 -0
- data/doc/release_notes/0_18_6.md +5 -0
- data/doc/release_notes/0_18_7.md +5 -0
- data/doc/release_notes/0_19_0.md +39 -0
- data/doc/release_notes/0_19_1.md +5 -0
- data/doc/release_notes/0_19_2.md +7 -0
- data/doc/release_notes/0_19_3.md +6 -0
- data/doc/release_notes/0_19_4.md +14 -0
- data/doc/release_notes/0_19_5.md +13 -0
- data/doc/release_notes/0_19_6.md +5 -0
- data/doc/release_notes/0_19_7.md +5 -0
- data/doc/release_notes/0_19_8.md +5 -0
- data/doc/release_notes/0_1_0.md +9 -0
- data/doc/release_notes/0_20_0.md +36 -0
- 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/0_2_0.md +5 -0
- data/doc/release_notes/0_2_1.md +16 -0
- data/doc/release_notes/0_3_0.md +12 -0
- data/doc/release_notes/0_3_1.md +6 -0
- data/doc/release_notes/0_4_0.md +51 -0
- data/doc/release_notes/0_4_1.md +3 -0
- data/doc/release_notes/0_5_0.md +15 -0
- data/doc/release_notes/0_5_1.md +14 -0
- data/doc/release_notes/0_6_0.md +5 -0
- data/doc/release_notes/0_6_1.md +6 -0
- data/doc/release_notes/0_6_2.md +6 -0
- data/doc/release_notes/0_6_3.md +13 -0
- data/doc/release_notes/0_6_4.md +21 -0
- data/doc/release_notes/0_6_5.md +22 -0
- data/doc/release_notes/0_6_6.md +19 -0
- data/doc/release_notes/0_6_7.md +5 -0
- data/doc/release_notes/0_7_0.md +46 -0
- data/doc/release_notes/0_8_0.md +27 -0
- data/doc/release_notes/0_8_1.md +8 -0
- data/doc/release_notes/0_8_2.md +7 -0
- data/doc/release_notes/0_9_0.md +38 -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/doc/release_notes/1_3_2.md +6 -0
- data/doc/release_notes/1_3_3.md +5 -0
- data/doc/release_notes/1_3_4.md +6 -0
- data/doc/release_notes/1_4_0.md +43 -0
- data/doc/release_notes/1_4_1.md +19 -0
- data/doc/release_notes/1_4_2.md +20 -0
- data/doc/release_notes/1_4_3.md +11 -0
- data/doc/release_notes/1_4_4.md +14 -0
- data/doc/release_notes/1_5_0.md +126 -0
- data/doc/release_notes/1_5_1.md +6 -0
- data/doc/release_notes/1_6_0.md +50 -0
- data/doc/release_notes/1_6_1.md +17 -0
- data/doc/release_notes/1_6_2.md +11 -0
- data/lib/httpx/adapters/datadog.rb +359 -0
- data/lib/httpx/adapters/faraday.rb +303 -0
- data/lib/httpx/adapters/sentry.rb +121 -0
- data/lib/httpx/adapters/webmock.rb +175 -0
- data/lib/httpx/altsvc.rb +163 -0
- data/lib/httpx/base64.rb +27 -0
- data/lib/httpx/buffer.rb +61 -0
- data/lib/httpx/callbacks.rb +35 -0
- data/lib/httpx/chainable.rb +106 -0
- data/lib/httpx/connection/http1.rb +399 -0
- data/lib/httpx/connection/http2.rb +468 -0
- data/lib/httpx/connection.rb +954 -0
- data/lib/httpx/domain_name.rb +145 -0
- data/lib/httpx/errors.rb +111 -0
- data/lib/httpx/extensions.rb +59 -0
- data/lib/httpx/headers.rb +176 -0
- data/lib/httpx/io/ssl.rb +163 -0
- data/lib/httpx/io/tcp.rb +239 -0
- data/lib/httpx/io/udp.rb +62 -0
- data/lib/httpx/io/unix.rb +71 -0
- data/lib/httpx/io.rb +11 -0
- data/lib/httpx/loggable.rb +56 -0
- data/lib/httpx/options.rb +463 -0
- data/lib/httpx/parser/http1.rb +186 -0
- data/lib/httpx/plugins/auth/basic.rb +20 -0
- data/lib/httpx/plugins/auth/digest.rb +102 -0
- data/lib/httpx/plugins/auth/ntlm.rb +35 -0
- data/lib/httpx/plugins/auth/socks5.rb +22 -0
- data/lib/httpx/plugins/auth.rb +25 -0
- data/lib/httpx/plugins/aws_sdk_authentication.rb +111 -0
- data/lib/httpx/plugins/aws_sigv4.rb +239 -0
- data/lib/httpx/plugins/basic_auth.rb +29 -0
- data/lib/httpx/plugins/brotli.rb +50 -0
- data/lib/httpx/plugins/callbacks.rb +127 -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 +147 -0
- data/lib/httpx/plugins/content_digest.rb +204 -0
- data/lib/httpx/plugins/cookies/cookie.rb +174 -0
- data/lib/httpx/plugins/cookies/jar.rb +95 -0
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +143 -0
- data/lib/httpx/plugins/cookies.rb +107 -0
- data/lib/httpx/plugins/digest_auth.rb +67 -0
- data/lib/httpx/plugins/expect.rb +120 -0
- data/lib/httpx/plugins/fiber_concurrency.rb +195 -0
- data/lib/httpx/plugins/follow_redirects.rb +233 -0
- data/lib/httpx/plugins/grpc/call.rb +63 -0
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +90 -0
- data/lib/httpx/plugins/grpc/message.rb +55 -0
- data/lib/httpx/plugins/grpc.rb +282 -0
- data/lib/httpx/plugins/h2c.rb +127 -0
- data/lib/httpx/plugins/internal_telemetry.rb +107 -0
- data/lib/httpx/plugins/ntlm_auth.rb +62 -0
- data/lib/httpx/plugins/oauth.rb +183 -0
- data/lib/httpx/plugins/persistent.rb +82 -0
- data/lib/httpx/plugins/proxy/http.rb +184 -0
- data/lib/httpx/plugins/proxy/socks4.rb +135 -0
- data/lib/httpx/plugins/proxy/socks5.rb +194 -0
- data/lib/httpx/plugins/proxy/ssh.rb +94 -0
- data/lib/httpx/plugins/proxy.rb +349 -0
- data/lib/httpx/plugins/push_promise.rb +81 -0
- data/lib/httpx/plugins/query.rb +35 -0
- data/lib/httpx/plugins/rate_limiter.rb +55 -0
- data/lib/httpx/plugins/response_cache/file_store.rb +140 -0
- data/lib/httpx/plugins/response_cache/store.rb +33 -0
- data/lib/httpx/plugins/response_cache.rb +333 -0
- data/lib/httpx/plugins/retries.rb +230 -0
- data/lib/httpx/plugins/ssrf_filter.rb +145 -0
- data/lib/httpx/plugins/stream.rb +183 -0
- data/lib/httpx/plugins/stream_bidi.rb +315 -0
- data/lib/httpx/plugins/upgrade/h2.rb +64 -0
- data/lib/httpx/plugins/upgrade.rb +86 -0
- data/lib/httpx/plugins/webdav.rb +86 -0
- data/lib/httpx/plugins/xml.rb +76 -0
- data/lib/httpx/pmatch_extensions.rb +33 -0
- data/lib/httpx/pool.rb +190 -0
- data/lib/httpx/punycode.rb +22 -0
- data/lib/httpx/request/body.rb +158 -0
- data/lib/httpx/request.rb +328 -0
- data/lib/httpx/resolver/entry.rb +30 -0
- data/lib/httpx/resolver/https.rb +256 -0
- data/lib/httpx/resolver/multi.rb +102 -0
- data/lib/httpx/resolver/native.rb +547 -0
- data/lib/httpx/resolver/resolver.rb +173 -0
- data/lib/httpx/resolver/system.rb +255 -0
- data/lib/httpx/resolver.rb +189 -0
- data/lib/httpx/response/body.rb +242 -0
- data/lib/httpx/response/buffer.rb +115 -0
- data/lib/httpx/response.rb +304 -0
- data/lib/httpx/selector.rb +282 -0
- data/lib/httpx/session.rb +612 -0
- data/lib/httpx/session_extensions.rb +30 -0
- data/lib/httpx/timers.rb +133 -0
- data/lib/httpx/transcoder/body.rb +43 -0
- data/lib/httpx/transcoder/chunker.rb +115 -0
- data/lib/httpx/transcoder/deflate.rb +37 -0
- data/lib/httpx/transcoder/form.rb +68 -0
- data/lib/httpx/transcoder/gzip.rb +71 -0
- data/lib/httpx/transcoder/json.rb +71 -0
- data/lib/httpx/transcoder/multipart/decoder.rb +141 -0
- data/lib/httpx/transcoder/multipart/encoder.rb +120 -0
- data/lib/httpx/transcoder/multipart/mime_type_detector.rb +78 -0
- data/lib/httpx/transcoder/multipart/part.rb +35 -0
- data/lib/httpx/transcoder/multipart.rb +31 -0
- data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
- data/lib/httpx/transcoder/utils/deflater.rb +75 -0
- data/lib/httpx/transcoder.rb +91 -0
- data/lib/httpx/utils.rb +75 -0
- data/lib/httpx/version.rb +5 -0
- data/lib/httpx.rb +66 -0
- data/sig/altsvc.rbs +33 -0
- data/sig/buffer.rbs +27 -0
- data/sig/callbacks.rbs +15 -0
- data/sig/chainable.rbs +55 -0
- data/sig/connection/http1.rbs +85 -0
- data/sig/connection/http2.rbs +116 -0
- data/sig/connection.rbs +169 -0
- data/sig/domain_name.rbs +17 -0
- data/sig/errors.rbs +69 -0
- data/sig/headers.rbs +49 -0
- data/sig/httpx.rbs +27 -0
- data/sig/io/ssl.rbs +27 -0
- data/sig/io/tcp.rbs +72 -0
- data/sig/io/udp.rbs +25 -0
- data/sig/io/unix.rbs +26 -0
- data/sig/io.rbs +3 -0
- data/sig/loggable.rbs +17 -0
- data/sig/options.rbs +202 -0
- data/sig/parser/http1.rbs +59 -0
- data/sig/plugins/auth/basic.rbs +17 -0
- data/sig/plugins/auth/digest.rbs +25 -0
- data/sig/plugins/auth/ntlm.rbs +20 -0
- data/sig/plugins/auth/socks5.rbs +18 -0
- data/sig/plugins/auth.rbs +13 -0
- data/sig/plugins/aws_sdk_authentication.rbs +43 -0
- data/sig/plugins/aws_sigv4.rbs +78 -0
- data/sig/plugins/basic_auth.rbs +15 -0
- 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 +57 -0
- data/sig/plugins/content_digest.rbs +51 -0
- data/sig/plugins/cookies/cookie.rbs +55 -0
- data/sig/plugins/cookies/jar.rbs +26 -0
- data/sig/plugins/cookies/set_cookie_parser.rbs +22 -0
- data/sig/plugins/cookies.rbs +28 -0
- data/sig/plugins/digest_auth.rbs +21 -0
- data/sig/plugins/expect.rbs +15 -0
- data/sig/plugins/fiber_concurrency.rbs +51 -0
- data/sig/plugins/follow_redirects.rbs +47 -0
- data/sig/plugins/grpc/call.rbs +23 -0
- data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
- data/sig/plugins/grpc/message.rbs +17 -0
- data/sig/plugins/grpc.rbs +65 -0
- data/sig/plugins/h2c.rbs +27 -0
- data/sig/plugins/ntlm_auth.rbs +21 -0
- data/sig/plugins/oauth.rbs +68 -0
- data/sig/plugins/persistent.rbs +14 -0
- data/sig/plugins/proxy/http.rbs +30 -0
- data/sig/plugins/proxy/socks4.rbs +37 -0
- data/sig/plugins/proxy/socks5.rbs +49 -0
- data/sig/plugins/proxy/ssh.rbs +18 -0
- data/sig/plugins/proxy.rbs +70 -0
- data/sig/plugins/push_promise.rbs +23 -0
- data/sig/plugins/query.rbs +18 -0
- data/sig/plugins/rate_limiter.rbs +13 -0
- data/sig/plugins/response_cache/file_store.rbs +19 -0
- data/sig/plugins/response_cache/store.rbs +13 -0
- data/sig/plugins/response_cache.rbs +86 -0
- data/sig/plugins/retries.rbs +66 -0
- data/sig/plugins/ssrf_filter.rbs +26 -0
- data/sig/plugins/stream.rbs +54 -0
- data/sig/plugins/stream_bidi.rbs +68 -0
- data/sig/plugins/upgrade/h2.rbs +9 -0
- data/sig/plugins/upgrade.rbs +29 -0
- data/sig/plugins/webdav.rbs +23 -0
- data/sig/plugins/xml.rbs +37 -0
- data/sig/pool.rbs +51 -0
- data/sig/punycode.rbs +5 -0
- data/sig/request/body.rbs +34 -0
- data/sig/request.rbs +88 -0
- data/sig/resolver/entry.rbs +13 -0
- data/sig/resolver/https.rbs +45 -0
- data/sig/resolver/multi.rbs +32 -0
- data/sig/resolver/native.rbs +74 -0
- data/sig/resolver/resolver.rbs +64 -0
- data/sig/resolver/system.rbs +34 -0
- data/sig/resolver.rbs +48 -0
- data/sig/response/body.rbs +52 -0
- data/sig/response/buffer.rbs +23 -0
- data/sig/response.rbs +103 -0
- data/sig/selector.rbs +68 -0
- data/sig/session.rbs +104 -0
- data/sig/timers.rbs +54 -0
- data/sig/transcoder/body.rbs +24 -0
- data/sig/transcoder/chunker.rbs +49 -0
- data/sig/transcoder/deflate.rbs +12 -0
- data/sig/transcoder/form.rbs +34 -0
- data/sig/transcoder/gzip.rbs +27 -0
- data/sig/transcoder/json.rbs +28 -0
- data/sig/transcoder/multipart.rbs +103 -0
- data/sig/transcoder/utils/body_reader.rbs +15 -0
- data/sig/transcoder/utils/deflater.rbs +28 -0
- data/sig/transcoder.rbs +43 -0
- data/sig/utils.rbs +19 -0
- metadata +518 -0
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
# Class implementing the APIs being used publicly.
|
|
5
|
+
#
|
|
6
|
+
# HTTPX.get(..) #=> delegating to an internal HTTPX::Session object.
|
|
7
|
+
# HTTPX.plugin(..).get(..) #=> creating an intermediate HTTPX::Session with plugin, then sending the GET request
|
|
8
|
+
class Session
|
|
9
|
+
include Loggable
|
|
10
|
+
include Chainable
|
|
11
|
+
|
|
12
|
+
# initializes the session with a set of +options+, which will be shared by all
|
|
13
|
+
# requests sent from it.
|
|
14
|
+
#
|
|
15
|
+
# When pass a block, it'll yield itself to it, then closes after the block is evaluated.
|
|
16
|
+
def initialize(options = EMPTY_HASH, &blk)
|
|
17
|
+
@options = self.class.default_options.merge(options)
|
|
18
|
+
@persistent = @options.persistent
|
|
19
|
+
@pool = @options.pool_class.new(@options.pool_options)
|
|
20
|
+
@wrapped = false
|
|
21
|
+
@closing = false
|
|
22
|
+
INSTANCES[self] = self if @persistent && @options.close_on_fork && INSTANCES
|
|
23
|
+
wrap(&blk) if blk
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Yields itself the block, then closes it after the block is evaluated.
|
|
27
|
+
#
|
|
28
|
+
# session.wrap do |http|
|
|
29
|
+
# http.get("https://wikipedia.com")
|
|
30
|
+
# end # wikipedia connection closes here
|
|
31
|
+
def wrap
|
|
32
|
+
prev_wrapped = @wrapped
|
|
33
|
+
@wrapped = true
|
|
34
|
+
was_initialized = false
|
|
35
|
+
current_selector = get_current_selector do
|
|
36
|
+
selector = Selector.new
|
|
37
|
+
|
|
38
|
+
set_current_selector(selector)
|
|
39
|
+
|
|
40
|
+
was_initialized = true
|
|
41
|
+
|
|
42
|
+
selector
|
|
43
|
+
end
|
|
44
|
+
begin
|
|
45
|
+
yield self
|
|
46
|
+
ensure
|
|
47
|
+
unless prev_wrapped
|
|
48
|
+
if @persistent
|
|
49
|
+
deactivate(current_selector)
|
|
50
|
+
else
|
|
51
|
+
close(current_selector)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
@wrapped = prev_wrapped
|
|
55
|
+
set_current_selector(nil) if was_initialized
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# closes all the active connections from the session.
|
|
60
|
+
#
|
|
61
|
+
# when called directly without specifying +selector+, all available connections
|
|
62
|
+
# will be picked up from the connection pool and closed. Connections in use
|
|
63
|
+
# by other sessions, or same session in a different thread, will not be reaped.
|
|
64
|
+
def close(selector = Selector.new)
|
|
65
|
+
# throw resolvers away from the pool
|
|
66
|
+
@pool.reset_resolvers
|
|
67
|
+
|
|
68
|
+
# preparing to throw away connections
|
|
69
|
+
while (connection = @pool.pop_connection)
|
|
70
|
+
next if connection.state == :closed
|
|
71
|
+
|
|
72
|
+
select_connection(connection, selector)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
selector_close(selector)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# performs one, or multple requests; it accepts:
|
|
79
|
+
#
|
|
80
|
+
# 1. one or multiple HTTPX::Request objects;
|
|
81
|
+
# 2. an HTTP verb, then a sequence of URIs or URI/options tuples;
|
|
82
|
+
# 3. one or multiple HTTP verb / uri / (optional) options tuples;
|
|
83
|
+
#
|
|
84
|
+
# when present, the set of +options+ kwargs is applied to all of the
|
|
85
|
+
# sent requests.
|
|
86
|
+
#
|
|
87
|
+
# respectively returns a single HTTPX::Response response, or all of them in an Array, in the same order.
|
|
88
|
+
#
|
|
89
|
+
# resp1 = session.request(req1)
|
|
90
|
+
# resp1, resp2 = session.request(req1, req2)
|
|
91
|
+
# resp1 = session.request("GET", "https://server.org/a")
|
|
92
|
+
# resp1, resp2 = session.request("GET", ["https://server.org/a", "https://server.org/b"])
|
|
93
|
+
# resp1, resp2 = session.request(["GET", "https://server.org/a"], ["GET", "https://server.org/b"])
|
|
94
|
+
# resp1 = session.request("POST", "https://server.org/a", form: { "foo" => "bar" })
|
|
95
|
+
# resp1, resp2 = session.request(["POST", "https://server.org/a", form: { "foo" => "bar" }], ["GET", "https://server.org/b"])
|
|
96
|
+
# resp1, resp2 = session.request("GET", ["https://server.org/a", "https://server.org/b"], headers: { "x-api-token" => "TOKEN" })
|
|
97
|
+
#
|
|
98
|
+
def request(*args, **params)
|
|
99
|
+
raise ArgumentError, "must perform at least one request" if args.empty?
|
|
100
|
+
|
|
101
|
+
requests = args.first.is_a?(Request) ? args : build_requests(*args, params)
|
|
102
|
+
responses = send_requests(*requests)
|
|
103
|
+
return responses.first if responses.size == 1
|
|
104
|
+
|
|
105
|
+
responses
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# returns a HTTP::Request instance built from the HTTP +verb+, the request +uri+, and
|
|
109
|
+
# the optional set of request-specific +options+. This request **must** be sent through
|
|
110
|
+
# the same session it was built from.
|
|
111
|
+
#
|
|
112
|
+
# req = session.build_request("GET", "https://server.com")
|
|
113
|
+
# resp = session.request(req)
|
|
114
|
+
def build_request(verb, uri, params = EMPTY_HASH, options = @options)
|
|
115
|
+
rklass = options.request_class
|
|
116
|
+
request = rklass.new(verb, uri, options, params)
|
|
117
|
+
request.persistent = @persistent
|
|
118
|
+
set_request_callbacks(request)
|
|
119
|
+
request
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def select_connection(connection, selector)
|
|
123
|
+
pin_connection(connection, selector)
|
|
124
|
+
selector.register(connection)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def pin_connection(connection, selector)
|
|
128
|
+
connection.current_session = self
|
|
129
|
+
connection.current_selector = selector
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
alias_method :select_resolver, :select_connection
|
|
133
|
+
|
|
134
|
+
def deselect_connection(connection, selector, cloned = false)
|
|
135
|
+
connection.log(level: 2) do
|
|
136
|
+
"deregistering connection##{connection.object_id}(#{connection.state}) from selector##{selector.object_id}"
|
|
137
|
+
end
|
|
138
|
+
selector.deregister(connection)
|
|
139
|
+
|
|
140
|
+
# when connections coalesce
|
|
141
|
+
return if connection.state == :idle
|
|
142
|
+
|
|
143
|
+
return if cloned
|
|
144
|
+
|
|
145
|
+
return if @closing && connection.state == :closed
|
|
146
|
+
|
|
147
|
+
connection.log(level: 2) { "check-in connection##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" }
|
|
148
|
+
@pool.checkin_connection(connection)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def deselect_resolver(resolver, selector)
|
|
152
|
+
resolver.log(level: 2) do
|
|
153
|
+
"deregistering resolver##{resolver.object_id}(#{resolver.state}) from selector##{selector.object_id}"
|
|
154
|
+
end
|
|
155
|
+
selector.deregister(resolver)
|
|
156
|
+
|
|
157
|
+
return if @closing && resolver.closed?
|
|
158
|
+
|
|
159
|
+
resolver.log(level: 2) { "check-in resolver##{resolver.object_id}(#{resolver.state}) in pool##{@pool.object_id}" }
|
|
160
|
+
@pool.checkin_resolver(resolver)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def try_clone_connection(connection, selector, family)
|
|
164
|
+
connection.family ||= family
|
|
165
|
+
|
|
166
|
+
return connection if connection.family == family
|
|
167
|
+
|
|
168
|
+
new_connection = connection.class.new(connection.origin, connection.options)
|
|
169
|
+
|
|
170
|
+
new_connection.family = family
|
|
171
|
+
|
|
172
|
+
connection.sibling = new_connection
|
|
173
|
+
|
|
174
|
+
do_init_connection(new_connection, selector)
|
|
175
|
+
new_connection
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# returns the HTTPX::Connection through which the +request+ should be sent through.
|
|
179
|
+
def find_connection(request_uri, selector, options)
|
|
180
|
+
if (connection = selector.find_connection(request_uri, options))
|
|
181
|
+
connection.idling if connection.state == :closed
|
|
182
|
+
connection.log(level: 2) { "found connection##{connection.object_id}(#{connection.state}) in selector##{selector.object_id}" }
|
|
183
|
+
return connection
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
connection = @pool.checkout_connection(request_uri, options)
|
|
187
|
+
|
|
188
|
+
connection.log(level: 2) { "found connection##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" }
|
|
189
|
+
|
|
190
|
+
case connection.state
|
|
191
|
+
when :idle
|
|
192
|
+
do_init_connection(connection, selector)
|
|
193
|
+
when :open
|
|
194
|
+
if options.io
|
|
195
|
+
select_connection(connection, selector)
|
|
196
|
+
else
|
|
197
|
+
pin_connection(connection, selector)
|
|
198
|
+
end
|
|
199
|
+
when :closing, :closed
|
|
200
|
+
connection.idling
|
|
201
|
+
if connection.addresses?
|
|
202
|
+
select_connection(connection, selector)
|
|
203
|
+
else
|
|
204
|
+
# if addresses expired, resolve again
|
|
205
|
+
resolve_connection(connection, selector)
|
|
206
|
+
end
|
|
207
|
+
else
|
|
208
|
+
pin_connection(connection, selector)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
connection
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
private
|
|
215
|
+
|
|
216
|
+
def selector_close(selector)
|
|
217
|
+
begin
|
|
218
|
+
@closing = true
|
|
219
|
+
selector.terminate
|
|
220
|
+
ensure
|
|
221
|
+
@closing = false
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# tries deactivating connections in the +selector+, deregistering the ones that have been deactivated.
|
|
226
|
+
def deactivate(selector)
|
|
227
|
+
selector.each_connection.select do |c|
|
|
228
|
+
c.deactivate
|
|
229
|
+
|
|
230
|
+
c.state == :inactive
|
|
231
|
+
end.each do |c| # rubocop:disable Style/MultilineBlockChain
|
|
232
|
+
deselect_connection(c, selector)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# callback executed when an HTTP/2 promise frame has been received.
|
|
237
|
+
def on_promise(_, stream)
|
|
238
|
+
log(level: 2) { "#{stream.id}: refusing stream!" }
|
|
239
|
+
stream.refuse
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# returns the corresponding HTTP::Response to the given +request+ if it has been received.
|
|
243
|
+
def fetch_response(request, _selector, _options)
|
|
244
|
+
response = request.response
|
|
245
|
+
|
|
246
|
+
return unless response && response.finished?
|
|
247
|
+
|
|
248
|
+
log(level: 2) { "response fetched" }
|
|
249
|
+
|
|
250
|
+
response
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# sends the +request+ to the corresponding HTTPX::Connection
|
|
254
|
+
def send_request(request, selector, options = request.options)
|
|
255
|
+
error = begin
|
|
256
|
+
catch(:resolve_error) do
|
|
257
|
+
connection = find_connection(request.uri, selector, options)
|
|
258
|
+
connection.send(request)
|
|
259
|
+
end
|
|
260
|
+
rescue StandardError => e
|
|
261
|
+
e
|
|
262
|
+
end
|
|
263
|
+
return unless error && error.is_a?(Exception)
|
|
264
|
+
|
|
265
|
+
raise error unless error.is_a?(Error)
|
|
266
|
+
|
|
267
|
+
response = ErrorResponse.new(request, error)
|
|
268
|
+
request.response = response
|
|
269
|
+
request.emit(:response, response)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# returns a set of HTTPX::Request objects built from the given +args+ and +options+.
|
|
273
|
+
def build_requests(*args, params)
|
|
274
|
+
requests = if args.size == 1
|
|
275
|
+
reqs = args.first
|
|
276
|
+
reqs.map do |verb, uri, ps = EMPTY_HASH|
|
|
277
|
+
request_params = params
|
|
278
|
+
request_params = request_params.merge(ps) unless ps.empty?
|
|
279
|
+
build_request(verb, uri, request_params)
|
|
280
|
+
end
|
|
281
|
+
else
|
|
282
|
+
verb, uris = args
|
|
283
|
+
if uris.respond_to?(:each)
|
|
284
|
+
uris.enum_for(:each).map do |uri, ps = EMPTY_HASH|
|
|
285
|
+
request_params = params
|
|
286
|
+
request_params = request_params.merge(ps) unless ps.empty?
|
|
287
|
+
build_request(verb, uri, request_params)
|
|
288
|
+
end
|
|
289
|
+
else
|
|
290
|
+
[build_request(verb, uris, params)]
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
raise ArgumentError, "wrong number of URIs (given 0, expect 1..+1)" if requests.empty?
|
|
294
|
+
|
|
295
|
+
requests
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def set_request_callbacks(request)
|
|
299
|
+
request.on(:promise, &method(:on_promise))
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def do_init_connection(connection, selector)
|
|
303
|
+
resolve_connection(connection, selector) unless connection.family
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# sends an array of HTTPX::Request +requests+, returns the respective array of HTTPX::Response objects.
|
|
307
|
+
def send_requests(*requests)
|
|
308
|
+
selector = get_current_selector { Selector.new }
|
|
309
|
+
begin
|
|
310
|
+
_send_requests(requests, selector)
|
|
311
|
+
receive_requests(requests, selector)
|
|
312
|
+
ensure
|
|
313
|
+
unless @wrapped
|
|
314
|
+
if @persistent
|
|
315
|
+
deactivate(selector)
|
|
316
|
+
else
|
|
317
|
+
close(selector)
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# sends an array of HTTPX::Request objects
|
|
324
|
+
def _send_requests(requests, selector)
|
|
325
|
+
requests.each do |request|
|
|
326
|
+
send_request(request, selector)
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# returns the array of HTTPX::Response objects corresponding to the array of HTTPX::Request +requests+.
|
|
331
|
+
def receive_requests(requests, selector)
|
|
332
|
+
responses = [] # : Array[response]
|
|
333
|
+
|
|
334
|
+
# guarantee ordered responses
|
|
335
|
+
loop do
|
|
336
|
+
request = requests.first
|
|
337
|
+
|
|
338
|
+
return responses unless request
|
|
339
|
+
|
|
340
|
+
catch(:coalesced) { selector.next_tick } until (response = fetch_response(request, selector, request.options))
|
|
341
|
+
request.complete!(response)
|
|
342
|
+
|
|
343
|
+
responses << response
|
|
344
|
+
requests.shift
|
|
345
|
+
|
|
346
|
+
break if requests.empty?
|
|
347
|
+
|
|
348
|
+
next unless selector.empty?
|
|
349
|
+
|
|
350
|
+
# in some cases, the pool of connections might have been drained because there was some
|
|
351
|
+
# handshake error, and the error responses have already been emitted, but there was no
|
|
352
|
+
# opportunity to traverse the requests, hence we're returning only a fraction of the errors
|
|
353
|
+
# we were supposed to. This effectively fetches the existing responses and return them.
|
|
354
|
+
exit_from_loop = true
|
|
355
|
+
|
|
356
|
+
requests_to_remove = [] # : Array[Request]
|
|
357
|
+
|
|
358
|
+
requests.each do |req|
|
|
359
|
+
response = fetch_response(req, selector, request.options)
|
|
360
|
+
|
|
361
|
+
if exit_from_loop && response
|
|
362
|
+
req.complete!(response)
|
|
363
|
+
responses << response
|
|
364
|
+
requests_to_remove << req
|
|
365
|
+
else
|
|
366
|
+
# fetch_response may resend requests. when that happens, we need to go back to the initial
|
|
367
|
+
# loop and process the selector. we still do a pass-through on the remainder of requests, so
|
|
368
|
+
# that every request that need to be resent, is resent.
|
|
369
|
+
exit_from_loop = false
|
|
370
|
+
|
|
371
|
+
raise Error, "something went wrong, responses not found and requests not resent" if selector.empty?
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
break if exit_from_loop
|
|
376
|
+
|
|
377
|
+
requests -= requests_to_remove
|
|
378
|
+
end
|
|
379
|
+
responses
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def resolve_connection(connection, selector)
|
|
383
|
+
if connection.addresses? || connection.open?
|
|
384
|
+
#
|
|
385
|
+
# there are two cases in which we want to activate initialization of
|
|
386
|
+
# connection immediately:
|
|
387
|
+
#
|
|
388
|
+
# 1. when the connection already has addresses, i.e. it doesn't need to
|
|
389
|
+
# resolve a name (not the same as name being an IP, yet)
|
|
390
|
+
# 2. when the connection is initialized with an external already open IO.
|
|
391
|
+
#
|
|
392
|
+
on_resolver_connection(connection, selector)
|
|
393
|
+
return
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
resolver = find_resolver_for(connection, selector)
|
|
397
|
+
|
|
398
|
+
resolver.early_resolve(connection) || resolver.lazy_resolve(connection)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def on_resolver_connection(connection, selector)
|
|
402
|
+
from_pool = false
|
|
403
|
+
found_connection = selector.find_mergeable_connection(connection) || begin
|
|
404
|
+
from_pool = true
|
|
405
|
+
@pool.checkout_mergeable_connection(connection)
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
return select_connection(connection, selector) unless found_connection
|
|
409
|
+
|
|
410
|
+
connection.log(level: 2) do
|
|
411
|
+
"try coalescing from #{from_pool ? "pool##{@pool.object_id}" : "selector##{selector.object_id}"} " \
|
|
412
|
+
"(conn##{found_connection.object_id}[#{found_connection.origin}])"
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
coalesce_connections(found_connection, connection, selector, from_pool)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def on_resolver_close(resolver, selector)
|
|
419
|
+
return if resolver.closed?
|
|
420
|
+
|
|
421
|
+
deselect_resolver(resolver, selector)
|
|
422
|
+
resolver.close unless resolver.closed?
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def find_resolver_for(connection, selector)
|
|
426
|
+
if (resolver = selector.find_resolver(connection.options))
|
|
427
|
+
resolver.log(level: 2) { "found resolver##{connection.object_id}(#{connection.state}) in selector##{selector.object_id}" }
|
|
428
|
+
return resolver
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
resolver = @pool.checkout_resolver(connection.options)
|
|
432
|
+
resolver.log(level: 2) { "found resolver##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" }
|
|
433
|
+
resolver.current_session = self
|
|
434
|
+
resolver.current_selector = selector
|
|
435
|
+
|
|
436
|
+
resolver
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
# coalesces +conn2+ into +conn1+. if +conn1+ was loaded from the connection pool
|
|
440
|
+
# (it is known via +from_pool+), then it adds its to the +selector+.
|
|
441
|
+
def coalesce_connections(conn1, conn2, selector, from_pool)
|
|
442
|
+
unless conn1.coalescable?(conn2)
|
|
443
|
+
conn2.log(level: 2) { "not coalescing with conn##{conn1.object_id}[#{conn1.origin}])" }
|
|
444
|
+
select_connection(conn2, selector)
|
|
445
|
+
if from_pool
|
|
446
|
+
conn1.log(level: 2) { "check-in connection##{conn1.object_id}(#{conn1.state}) in pool##{@pool.object_id}" }
|
|
447
|
+
@pool.checkin_connection(conn1)
|
|
448
|
+
end
|
|
449
|
+
return false
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
conn2.log(level: 2) { "coalescing with conn##{conn1.object_id}[#{conn1.origin}])" }
|
|
453
|
+
conn2.coalesce!(conn1)
|
|
454
|
+
select_connection(conn1, selector) if from_pool
|
|
455
|
+
conn2.disconnect
|
|
456
|
+
true
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def get_current_selector
|
|
460
|
+
selector_store[self] || (yield if block_given?)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def set_current_selector(selector)
|
|
464
|
+
if selector
|
|
465
|
+
selector_store[self] = selector
|
|
466
|
+
else
|
|
467
|
+
selector_store.delete(self)
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
def selector_store
|
|
472
|
+
th_current = Thread.current
|
|
473
|
+
|
|
474
|
+
thread_selector_store(th_current) || begin
|
|
475
|
+
{}.compare_by_identity.tap do |store|
|
|
476
|
+
th_current.thread_variable_set(:httpx_persistent_selector_store, store)
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
def thread_selector_store(th)
|
|
482
|
+
th.thread_variable_get(:httpx_persistent_selector_store)
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
@default_options = Options.new
|
|
486
|
+
@default_options.freeze
|
|
487
|
+
@plugins = []
|
|
488
|
+
|
|
489
|
+
class << self
|
|
490
|
+
attr_reader :default_options
|
|
491
|
+
|
|
492
|
+
def inherited(klass)
|
|
493
|
+
super
|
|
494
|
+
klass.instance_variable_set(:@default_options, @default_options)
|
|
495
|
+
klass.instance_variable_set(:@plugins, @plugins.dup)
|
|
496
|
+
klass.instance_variable_set(:@callbacks, @callbacks.dup)
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
# returns a new HTTPX::Session instance, with the plugin pointed by +pl+ loaded.
|
|
500
|
+
#
|
|
501
|
+
# session_with_retries = session.plugin(:retries)
|
|
502
|
+
# session_with_custom = session.plugin(CustomPlugin)
|
|
503
|
+
#
|
|
504
|
+
def plugin(pl, options = nil, &block)
|
|
505
|
+
label = pl
|
|
506
|
+
# raise Error, "Cannot add a plugin to a frozen config" if frozen?
|
|
507
|
+
pl = Plugins.load_plugin(pl) if pl.is_a?(Symbol)
|
|
508
|
+
raise ArgumentError, "Invalid plugin type: #{pl.class.inspect}" unless pl.is_a?(Module)
|
|
509
|
+
|
|
510
|
+
if !@plugins.include?(pl)
|
|
511
|
+
@plugins << pl
|
|
512
|
+
pl.load_dependencies(self, &block) if pl.respond_to?(:load_dependencies)
|
|
513
|
+
|
|
514
|
+
@default_options = @default_options.dup
|
|
515
|
+
|
|
516
|
+
include(pl::InstanceMethods) if defined?(pl::InstanceMethods)
|
|
517
|
+
extend(pl::ClassMethods) if defined?(pl::ClassMethods)
|
|
518
|
+
|
|
519
|
+
opts = @default_options
|
|
520
|
+
opts.extend_with_plugin_classes(pl)
|
|
521
|
+
|
|
522
|
+
if defined?(pl::OptionsMethods)
|
|
523
|
+
# when a class gets dup'ed, the #initialize_dup callbacks isn't triggered.
|
|
524
|
+
# moreover, and because #method_added does not get triggered on mixin include,
|
|
525
|
+
# the callback is also forcefully manually called here.
|
|
526
|
+
opts.options_class.instance_variable_set(:@options_names, opts.options_class.options_names.dup)
|
|
527
|
+
(pl::OptionsMethods.instance_methods + pl::OptionsMethods.private_instance_methods - Object.instance_methods).each do |meth|
|
|
528
|
+
opts.options_class.method_added(meth)
|
|
529
|
+
end
|
|
530
|
+
@default_options = opts.options_class.new(opts)
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
@default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
|
|
534
|
+
@default_options = @default_options.merge(options) if options
|
|
535
|
+
|
|
536
|
+
if pl.respond_to?(:subplugins)
|
|
537
|
+
pl.subplugins.transform_keys(&Plugins.method(:load_plugin)).each do |main_pl, sub_pl|
|
|
538
|
+
# in case the main plugin has already been loaded, then apply subplugin functionality
|
|
539
|
+
# immediately
|
|
540
|
+
next unless @plugins.include?(main_pl)
|
|
541
|
+
|
|
542
|
+
plugin(sub_pl, options, &block)
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
pl.configure(self, &block) if pl.respond_to?(:configure)
|
|
547
|
+
|
|
548
|
+
if label.is_a?(Symbol)
|
|
549
|
+
# in case an already-loaded plugin complements functionality of
|
|
550
|
+
# the plugin currently being loaded, loaded it now
|
|
551
|
+
@plugins.each do |registered_pl|
|
|
552
|
+
next if registered_pl == pl
|
|
553
|
+
|
|
554
|
+
next unless registered_pl.respond_to?(:subplugins)
|
|
555
|
+
|
|
556
|
+
sub_pl = registered_pl.subplugins[label]
|
|
557
|
+
|
|
558
|
+
next unless sub_pl
|
|
559
|
+
|
|
560
|
+
plugin(sub_pl, options, &block)
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
@default_options.freeze
|
|
565
|
+
set_temporary_name("#{superclass}/#{pl}") if respond_to?(:set_temporary_name) # ruby 3.4 only
|
|
566
|
+
elsif options
|
|
567
|
+
# this can happen when two plugins are loaded, an one of them calls the other under the hood,
|
|
568
|
+
# albeit changing some default.
|
|
569
|
+
@default_options = pl.extra_options(@default_options) if pl.respond_to?(:extra_options)
|
|
570
|
+
@default_options = @default_options.merge(options) if options
|
|
571
|
+
|
|
572
|
+
@default_options.freeze
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
self
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
# setup of the support for close_on_fork sessions.
|
|
580
|
+
# adapted from https://github.com/mperham/connection_pool/blob/main/lib/connection_pool.rb#L48
|
|
581
|
+
if Process.respond_to?(:fork)
|
|
582
|
+
INSTANCES = ObjectSpace::WeakMap.new
|
|
583
|
+
private_constant :INSTANCES
|
|
584
|
+
|
|
585
|
+
def self.after_fork
|
|
586
|
+
INSTANCES.each_value(&:close)
|
|
587
|
+
nil
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
if ::Process.respond_to?(:_fork)
|
|
591
|
+
module ForkTracker
|
|
592
|
+
def _fork
|
|
593
|
+
pid = super
|
|
594
|
+
Session.after_fork if pid.zero?
|
|
595
|
+
pid
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
Process.singleton_class.prepend(ForkTracker)
|
|
599
|
+
end
|
|
600
|
+
else
|
|
601
|
+
INSTANCES = nil
|
|
602
|
+
private_constant :INSTANCES
|
|
603
|
+
|
|
604
|
+
def self.after_fork
|
|
605
|
+
# noop
|
|
606
|
+
end
|
|
607
|
+
end
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
# session may be overridden by certain adapters.
|
|
611
|
+
S = Session
|
|
612
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
unless ENV.keys.grep(/\Ahttps?_proxy\z/i).empty?
|
|
5
|
+
proxy_session = plugin(:proxy)
|
|
6
|
+
remove_const(:Session)
|
|
7
|
+
const_set(:Session, proxy_session.class)
|
|
8
|
+
|
|
9
|
+
# redefine the default options static var, which needs to
|
|
10
|
+
# refresh options_class
|
|
11
|
+
options = proxy_session.class.default_options.to_hash
|
|
12
|
+
original_verbosity = $VERBOSE
|
|
13
|
+
$VERBOSE = nil
|
|
14
|
+
new_options_class = proxy_session.class.default_options.options_class.dup
|
|
15
|
+
const_set(:Options, new_options_class)
|
|
16
|
+
options[:options_class] = Class.new(new_options_class).freeze
|
|
17
|
+
options.freeze
|
|
18
|
+
Options.send(:const_set, :DEFAULT_OPTIONS, options)
|
|
19
|
+
Session.instance_variable_set(:@default_options, Options.new(options))
|
|
20
|
+
$VERBOSE = original_verbosity
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# :nocov:
|
|
24
|
+
if Session.default_options.debug_level > 2
|
|
25
|
+
proxy_session = plugin(:internal_telemetry)
|
|
26
|
+
remove_const(:Session)
|
|
27
|
+
const_set(:Session, proxy_session.class)
|
|
28
|
+
end
|
|
29
|
+
# :nocov:
|
|
30
|
+
end
|