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,195 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Plugins
|
|
5
|
+
# This plugin makes a session reuse the same selector across all fibers in a given thread.
|
|
6
|
+
#
|
|
7
|
+
# This enables integration with fiber scheduler implementations such as [async](https://github.com/async).
|
|
8
|
+
#
|
|
9
|
+
# # https://gitlab.com/os85/httpx/wikis/FiberConcurrency
|
|
10
|
+
#
|
|
11
|
+
module FiberConcurrency
|
|
12
|
+
def self.subplugins
|
|
13
|
+
{
|
|
14
|
+
h2c: FiberConcurrencyH2C,
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module InstanceMethods
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def send_request(request, *)
|
|
22
|
+
request.set_context!
|
|
23
|
+
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get_current_selector
|
|
28
|
+
super(&nil) || begin
|
|
29
|
+
return unless block_given?
|
|
30
|
+
|
|
31
|
+
default = yield
|
|
32
|
+
|
|
33
|
+
set_current_selector(default)
|
|
34
|
+
|
|
35
|
+
default
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
module RequestMethods
|
|
41
|
+
# the execution context (fiber) this request was sent on.
|
|
42
|
+
attr_reader :context
|
|
43
|
+
|
|
44
|
+
def initialize(*)
|
|
45
|
+
super
|
|
46
|
+
@context = nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# sets the execution context for this request. the default is the current fiber.
|
|
50
|
+
def set_context!
|
|
51
|
+
@context ||= Fiber.current # rubocop:disable Naming/MemoizedInstanceVariableName
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# checks whether the current execution context is the one where the request was created.
|
|
55
|
+
def current_context?
|
|
56
|
+
@context == Fiber.current
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def complete!(response = @response)
|
|
60
|
+
@context = nil
|
|
61
|
+
super
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
module ConnectionMethods
|
|
66
|
+
def current_context?
|
|
67
|
+
@pending.any?(&:current_context?) || (
|
|
68
|
+
@sibling && @sibling.pending.any?(&:current_context?)
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def interests
|
|
73
|
+
return if connecting? && @pending.none?(&:current_context?)
|
|
74
|
+
|
|
75
|
+
super
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def send(request)
|
|
79
|
+
# DoH requests bypass the session, so context needs to be set here.
|
|
80
|
+
request.set_context!
|
|
81
|
+
|
|
82
|
+
super
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
module HTTP1Methods
|
|
87
|
+
def interests
|
|
88
|
+
request = @request || @requests.first
|
|
89
|
+
|
|
90
|
+
return unless request
|
|
91
|
+
|
|
92
|
+
return unless request.current_context? || @requests.any?(&:current_context?) || @pending.any?(&:current_context?)
|
|
93
|
+
|
|
94
|
+
super
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
module HTTP2Methods
|
|
99
|
+
def initialize(*)
|
|
100
|
+
super
|
|
101
|
+
@contexts = Hash.new { |hs, k| hs[k] = Set.new }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def interests
|
|
105
|
+
if @connection.state == :connected && @handshake_completed && !@contexts.key?(Fiber.current)
|
|
106
|
+
return :w unless @pings.empty?
|
|
107
|
+
|
|
108
|
+
return
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
super
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def send(request, *)
|
|
115
|
+
add_to_context(request)
|
|
116
|
+
|
|
117
|
+
super
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
def on_close(_, error, _)
|
|
123
|
+
if error == :http_1_1_required
|
|
124
|
+
# remove all pending requests context
|
|
125
|
+
@pending.each do |req|
|
|
126
|
+
clear_from_context(req)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
super
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def on_stream_close(_, request, error)
|
|
134
|
+
clear_from_context(request) if error != :stream_closed && @streams.key?(request)
|
|
135
|
+
|
|
136
|
+
super
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def teardown(request = nil)
|
|
140
|
+
super
|
|
141
|
+
|
|
142
|
+
if request
|
|
143
|
+
clear_from_context(request)
|
|
144
|
+
else
|
|
145
|
+
@contexts.clear
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def add_to_context(request)
|
|
150
|
+
@contexts[request.context] << request
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def clear_from_context(request)
|
|
154
|
+
requests = @contexts[request.context]
|
|
155
|
+
|
|
156
|
+
requests.delete(request)
|
|
157
|
+
|
|
158
|
+
@contexts.delete(request.context) if requests.empty?
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
module NativeResolverMethods
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
def calculate_interests
|
|
166
|
+
return if @queries.empty?
|
|
167
|
+
|
|
168
|
+
return unless @queries.values.any?(&:current_context?) || @connections.any?(&:current_context?)
|
|
169
|
+
|
|
170
|
+
super
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
module SystemResolverMethods
|
|
175
|
+
def interests
|
|
176
|
+
return unless @queries.any? { |_, conn| conn.current_context? }
|
|
177
|
+
|
|
178
|
+
super
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
module FiberConcurrencyH2C
|
|
183
|
+
module HTTP2Methods
|
|
184
|
+
def upgrade(request, *)
|
|
185
|
+
@contexts[request.context] << request
|
|
186
|
+
|
|
187
|
+
super
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
register_plugin :fiber_concurrency, FiberConcurrency
|
|
194
|
+
end
|
|
195
|
+
end
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
InsecureRedirectError = Class.new(Error)
|
|
5
|
+
module Plugins
|
|
6
|
+
#
|
|
7
|
+
# This plugin adds support for automatically following redirect (status 30X) responses.
|
|
8
|
+
#
|
|
9
|
+
# It has a default upper bound of followed redirects (see *MAX_REDIRECTS* and the *max_redirects* option),
|
|
10
|
+
# after which it will return the last redirect response. It will **not** raise an exception.
|
|
11
|
+
#
|
|
12
|
+
# It doesn't follow insecure redirects (https -> http) by default (see *follow_insecure_redirects*).
|
|
13
|
+
#
|
|
14
|
+
# It doesn't propagate authorization related headers to requests redirecting to different origins
|
|
15
|
+
# (see *allow_auth_to_other_origins*) to override.
|
|
16
|
+
#
|
|
17
|
+
# It allows customization of when to redirect via the *redirect_on* callback option).
|
|
18
|
+
#
|
|
19
|
+
# https://gitlab.com/os85/httpx/wikis/Follow-Redirects
|
|
20
|
+
#
|
|
21
|
+
module FollowRedirects
|
|
22
|
+
MAX_REDIRECTS = 3
|
|
23
|
+
REDIRECT_STATUS = (300..399).freeze
|
|
24
|
+
REQUEST_BODY_HEADERS = %w[transfer-encoding content-encoding content-type content-length content-language content-md5 trailer].freeze
|
|
25
|
+
|
|
26
|
+
using URIExtensions
|
|
27
|
+
|
|
28
|
+
# adds support for the following options:
|
|
29
|
+
#
|
|
30
|
+
# :max_redirects :: max number of times a request will be redirected (defaults to <tt>3</tt>).
|
|
31
|
+
# :follow_insecure_redirects :: whether redirects to an "http://" URI, when coming from an "https//", are allowed
|
|
32
|
+
# (defaults to <tt>false</tt>).
|
|
33
|
+
# :allow_auth_to_other_origins :: whether auth-related headers, such as "Authorization", are propagated on redirection
|
|
34
|
+
# (defaults to <tt>false</tt>).
|
|
35
|
+
# :redirect_on :: optional callback which receives the redirect location and can halt the redirect chain if it returns <tt>false</tt>.
|
|
36
|
+
module OptionsMethods
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def option_max_redirects(value)
|
|
40
|
+
num = Integer(value)
|
|
41
|
+
raise TypeError, ":max_redirects must be positive" if num.negative?
|
|
42
|
+
|
|
43
|
+
num
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def option_follow_insecure_redirects(value)
|
|
47
|
+
value
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def option_allow_auth_to_other_origins(value)
|
|
51
|
+
value
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def option_redirect_on(value)
|
|
55
|
+
raise TypeError, ":redirect_on must be callable" unless value.respond_to?(:call)
|
|
56
|
+
|
|
57
|
+
value
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
module InstanceMethods
|
|
62
|
+
# returns a session with the *max_redirects* option set to +n+
|
|
63
|
+
def max_redirects(n)
|
|
64
|
+
with(max_redirects: n.to_i)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def fetch_response(request, selector, options)
|
|
70
|
+
redirect_request = request.redirect_request
|
|
71
|
+
response = super(redirect_request, selector, options)
|
|
72
|
+
return unless response
|
|
73
|
+
|
|
74
|
+
max_redirects = redirect_request.max_redirects
|
|
75
|
+
|
|
76
|
+
return response unless response.is_a?(Response)
|
|
77
|
+
return response unless REDIRECT_STATUS.include?(response.status) && response.headers.key?("location")
|
|
78
|
+
return response unless max_redirects.positive?
|
|
79
|
+
|
|
80
|
+
redirect_uri = __get_location_from_response(response)
|
|
81
|
+
|
|
82
|
+
if options.redirect_on
|
|
83
|
+
redirect_allowed = options.redirect_on.call(redirect_uri)
|
|
84
|
+
return response unless redirect_allowed
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# build redirect request
|
|
88
|
+
request_body = redirect_request.body
|
|
89
|
+
redirect_method = "GET"
|
|
90
|
+
redirect_params = {}
|
|
91
|
+
|
|
92
|
+
if response.status == 305 && options.respond_to?(:proxy)
|
|
93
|
+
request_body.rewind
|
|
94
|
+
# The requested resource MUST be accessed through the proxy given by
|
|
95
|
+
# the Location field. The Location field gives the URI of the proxy.
|
|
96
|
+
redirect_options = options.merge(headers: redirect_request.headers,
|
|
97
|
+
proxy: { uri: redirect_uri },
|
|
98
|
+
max_redirects: max_redirects - 1)
|
|
99
|
+
|
|
100
|
+
redirect_params[:body] = request_body
|
|
101
|
+
redirect_uri = redirect_request.uri
|
|
102
|
+
options = redirect_options
|
|
103
|
+
else
|
|
104
|
+
redirect_headers = redirect_request_headers(redirect_request.uri, redirect_uri, request.headers, options)
|
|
105
|
+
redirect_opts = Hash[options]
|
|
106
|
+
redirect_params[:max_redirects] = max_redirects - 1
|
|
107
|
+
|
|
108
|
+
unless request_body.empty?
|
|
109
|
+
if response.status == 307
|
|
110
|
+
# The method and the body of the original request are reused to perform the redirected request.
|
|
111
|
+
redirect_method = redirect_request.verb
|
|
112
|
+
request_body.rewind
|
|
113
|
+
redirect_params[:body] = request_body
|
|
114
|
+
else
|
|
115
|
+
# redirects are **ALWAYS** GET, so remove body-related headers
|
|
116
|
+
REQUEST_BODY_HEADERS.each do |h|
|
|
117
|
+
redirect_headers.delete(h)
|
|
118
|
+
end
|
|
119
|
+
redirect_params[:body] = nil
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
options = options.class.new(redirect_opts.merge(headers: redirect_headers.to_h))
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
redirect_uri = Utils.to_uri(redirect_uri)
|
|
127
|
+
|
|
128
|
+
if !options.follow_insecure_redirects &&
|
|
129
|
+
response.uri.scheme == "https" &&
|
|
130
|
+
redirect_uri.scheme == "http"
|
|
131
|
+
error = InsecureRedirectError.new(redirect_uri.to_s)
|
|
132
|
+
error.set_backtrace(caller)
|
|
133
|
+
return ErrorResponse.new(request, error)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
retry_request = build_request(redirect_method, redirect_uri, redirect_params, options)
|
|
137
|
+
|
|
138
|
+
request.redirect_request = retry_request
|
|
139
|
+
|
|
140
|
+
redirect_after = response.headers["retry-after"]
|
|
141
|
+
|
|
142
|
+
if redirect_after
|
|
143
|
+
# Servers send the "Retry-After" header field to indicate how long the
|
|
144
|
+
# user agent ought to wait before making a follow-up request.
|
|
145
|
+
# When sent with any 3xx (Redirection) response, Retry-After indicates
|
|
146
|
+
# the minimum time that the user agent is asked to wait before issuing
|
|
147
|
+
# the redirected request.
|
|
148
|
+
#
|
|
149
|
+
redirect_after = Utils.parse_retry_after(redirect_after)
|
|
150
|
+
|
|
151
|
+
retry_start = Utils.now
|
|
152
|
+
log { "redirecting after #{redirect_after} secs..." }
|
|
153
|
+
selector.after(redirect_after) do
|
|
154
|
+
if (response = request.response)
|
|
155
|
+
response.finish!
|
|
156
|
+
retry_request.response = response
|
|
157
|
+
# request has terminated abruptly meanwhile
|
|
158
|
+
retry_request.emit(:response, response)
|
|
159
|
+
else
|
|
160
|
+
log { "redirecting (elapsed time: #{Utils.elapsed_time(retry_start)})!!" }
|
|
161
|
+
send_request(retry_request, selector, options)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
else
|
|
165
|
+
send_request(retry_request, selector, options)
|
|
166
|
+
end
|
|
167
|
+
nil
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# :nodoc:
|
|
171
|
+
def redirect_request_headers(original_uri, redirect_uri, headers, options)
|
|
172
|
+
headers = headers.dup
|
|
173
|
+
|
|
174
|
+
return headers if options.allow_auth_to_other_origins
|
|
175
|
+
|
|
176
|
+
return headers unless headers.key?("authorization")
|
|
177
|
+
|
|
178
|
+
return headers if original_uri.origin == redirect_uri.origin
|
|
179
|
+
|
|
180
|
+
headers.delete("authorization")
|
|
181
|
+
|
|
182
|
+
headers
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# :nodoc:
|
|
186
|
+
def __get_location_from_response(response)
|
|
187
|
+
# @type var location_uri: http_uri
|
|
188
|
+
location_uri = URI(response.headers["location"])
|
|
189
|
+
location_uri = response.uri.merge(location_uri) if location_uri.relative?
|
|
190
|
+
location_uri
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
module RequestMethods
|
|
195
|
+
# returns the top-most original HTTPX::Request from the redirect chain
|
|
196
|
+
attr_accessor :root_request
|
|
197
|
+
|
|
198
|
+
# returns the follow-up redirect request, or itself
|
|
199
|
+
def redirect_request
|
|
200
|
+
@redirect_request || self
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# sets the follow-up redirect request
|
|
204
|
+
def redirect_request=(req)
|
|
205
|
+
@redirect_request = req
|
|
206
|
+
req.root_request = @root_request || self
|
|
207
|
+
@response = nil
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def response
|
|
211
|
+
return super unless @redirect_request && @response.nil?
|
|
212
|
+
|
|
213
|
+
@redirect_request.response
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def max_redirects
|
|
217
|
+
@options.max_redirects || MAX_REDIRECTS
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
module ConnectionMethods
|
|
222
|
+
private
|
|
223
|
+
|
|
224
|
+
def set_request_request_timeout(request)
|
|
225
|
+
return unless request.root_request.nil?
|
|
226
|
+
|
|
227
|
+
super
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
register_plugin :follow_redirects, FollowRedirects
|
|
232
|
+
end
|
|
233
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Plugins
|
|
5
|
+
module GRPC
|
|
6
|
+
# Encapsulates call information
|
|
7
|
+
class Call
|
|
8
|
+
attr_writer :decoder
|
|
9
|
+
|
|
10
|
+
def initialize(response)
|
|
11
|
+
@response = response
|
|
12
|
+
@decoder = ->(z) { z }
|
|
13
|
+
@consumed = false
|
|
14
|
+
@grpc_response = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def inspect
|
|
18
|
+
"#{self.class}(#{grpc_response})"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
grpc_response.to_s
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def metadata
|
|
26
|
+
response.headers
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def trailing_metadata
|
|
30
|
+
return unless @consumed
|
|
31
|
+
|
|
32
|
+
@response.trailing_metadata
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def grpc_response
|
|
38
|
+
@grpc_response ||= if @response.respond_to?(:each)
|
|
39
|
+
Enumerator.new do |y|
|
|
40
|
+
Message.stream(@response).each do |message|
|
|
41
|
+
y << @decoder.call(message)
|
|
42
|
+
end
|
|
43
|
+
@consumed = true
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
@consumed = true
|
|
47
|
+
@decoder.call(Message.unary(@response))
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def respond_to_missing?(meth, *args, &blk)
|
|
52
|
+
grpc_response.respond_to?(meth, *args) || super
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def method_missing(meth, *args, &blk)
|
|
56
|
+
return grpc_response.__send__(meth, *args, &blk) if grpc_response.respond_to?(meth)
|
|
57
|
+
|
|
58
|
+
super
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Transcoder
|
|
5
|
+
module GRPCEncoding
|
|
6
|
+
class Deflater
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
attr_reader :content_type
|
|
10
|
+
|
|
11
|
+
def initialize(body, compressed:)
|
|
12
|
+
@content_type = body.content_type
|
|
13
|
+
@body = BodyReader.new(body)
|
|
14
|
+
@compressed = compressed
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def bytesize
|
|
18
|
+
return @body.bytesize if @body.respond_to?(:bytesize)
|
|
19
|
+
|
|
20
|
+
Float::INFINITY
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def read(length = nil, outbuf = nil)
|
|
24
|
+
buf = @body.read(length, outbuf)
|
|
25
|
+
|
|
26
|
+
return unless buf
|
|
27
|
+
|
|
28
|
+
compressed_flag = @compressed ? 1 : 0
|
|
29
|
+
|
|
30
|
+
buf = outbuf if outbuf
|
|
31
|
+
|
|
32
|
+
buf = buf.b if buf.frozen?
|
|
33
|
+
|
|
34
|
+
buf.prepend([compressed_flag, buf.bytesize].pack("CL>"))
|
|
35
|
+
buf
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class Inflater
|
|
40
|
+
def initialize(response)
|
|
41
|
+
@response = response
|
|
42
|
+
@grpc_encodings = nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def call(message, &blk)
|
|
46
|
+
data = "".b
|
|
47
|
+
|
|
48
|
+
until message.empty?
|
|
49
|
+
compressed, size = message.unpack("CL>")
|
|
50
|
+
|
|
51
|
+
encoded_data = message.byteslice(5..size + 5 - 1)
|
|
52
|
+
|
|
53
|
+
if compressed == 1
|
|
54
|
+
grpc_encodings.reverse_each do |encoding|
|
|
55
|
+
decoder = @response.body.class.initialize_inflater_by_encoding(encoding, @response, bytesize: encoded_data.bytesize)
|
|
56
|
+
encoded_data = decoder.call(encoded_data)
|
|
57
|
+
|
|
58
|
+
blk.call(encoded_data) if blk
|
|
59
|
+
|
|
60
|
+
data << encoded_data
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
blk.call(encoded_data) if blk
|
|
64
|
+
|
|
65
|
+
data << encoded_data
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
message = message.byteslice((size + 5)..-1)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
data
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def grpc_encodings
|
|
77
|
+
@grpc_encodings ||= @response.headers.get("grpc-encoding")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.encode(*args, **kwargs)
|
|
82
|
+
Deflater.new(*args, **kwargs)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.decode(response)
|
|
86
|
+
Inflater.new(response)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Plugins
|
|
5
|
+
module GRPC
|
|
6
|
+
# Encoding module for GRPC responses
|
|
7
|
+
#
|
|
8
|
+
# Can encode and decode grpc messages.
|
|
9
|
+
module Message
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# decodes a unary grpc response
|
|
13
|
+
def unary(response)
|
|
14
|
+
verify_status(response)
|
|
15
|
+
|
|
16
|
+
decoder = Transcoder::GRPCEncoding.decode(response)
|
|
17
|
+
|
|
18
|
+
decoder.call(response.to_s)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# lazy decodes a grpc stream response
|
|
22
|
+
def stream(response, &block)
|
|
23
|
+
return enum_for(__method__, response) unless block
|
|
24
|
+
|
|
25
|
+
decoder = Transcoder::GRPCEncoding.decode(response)
|
|
26
|
+
|
|
27
|
+
response.each do |frame|
|
|
28
|
+
decoder.call(frame, &block)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
verify_status(response)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def cancel(request)
|
|
35
|
+
request.emit(:refuse, :client_cancellation)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# interprets the grpc call trailing metadata, and raises an
|
|
39
|
+
# exception in case of error code
|
|
40
|
+
def verify_status(response)
|
|
41
|
+
# return standard errors if need be
|
|
42
|
+
response.raise_for_status
|
|
43
|
+
|
|
44
|
+
status = Integer(response.headers["grpc-status"])
|
|
45
|
+
message = response.headers["grpc-message"]
|
|
46
|
+
|
|
47
|
+
return if status.zero?
|
|
48
|
+
|
|
49
|
+
response.close
|
|
50
|
+
raise GRPCError.new(status, message, response.trailing_metadata)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|