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,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "sentry-ruby"
|
|
4
|
+
|
|
5
|
+
module HTTPX::Plugins
|
|
6
|
+
module Sentry
|
|
7
|
+
module Tracer
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def call(request)
|
|
11
|
+
sentry_span = start_sentry_span
|
|
12
|
+
|
|
13
|
+
return unless sentry_span
|
|
14
|
+
|
|
15
|
+
set_sentry_trace_header(request, sentry_span)
|
|
16
|
+
|
|
17
|
+
request.on(:response, &method(:finish_sentry_span).curry(3)[sentry_span, request])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def start_sentry_span
|
|
21
|
+
return unless ::Sentry.initialized? && (span = ::Sentry.get_current_scope.get_span)
|
|
22
|
+
return if span.sampled == false
|
|
23
|
+
|
|
24
|
+
span.start_child(op: "httpx.client", start_timestamp: ::Sentry.utc_now.to_f)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def set_sentry_trace_header(request, sentry_span)
|
|
28
|
+
return unless sentry_span
|
|
29
|
+
|
|
30
|
+
config = ::Sentry.configuration
|
|
31
|
+
url = request.uri.to_s
|
|
32
|
+
|
|
33
|
+
return unless config.propagate_traces && config.trace_propagation_targets.any? { |target| url.match?(target) }
|
|
34
|
+
|
|
35
|
+
trace = ::Sentry.get_current_client.generate_sentry_trace(sentry_span)
|
|
36
|
+
request.headers[::Sentry::SENTRY_TRACE_HEADER_NAME] = trace if trace
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def finish_sentry_span(span, request, response)
|
|
40
|
+
return unless ::Sentry.initialized?
|
|
41
|
+
|
|
42
|
+
record_sentry_breadcrumb(request, response)
|
|
43
|
+
record_sentry_span(request, response, span)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def record_sentry_breadcrumb(req, res)
|
|
47
|
+
return unless ::Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
|
|
48
|
+
|
|
49
|
+
request_info = extract_request_info(req)
|
|
50
|
+
|
|
51
|
+
data = if res.is_a?(HTTPX::ErrorResponse)
|
|
52
|
+
{ error: res.error.message, **request_info }
|
|
53
|
+
else
|
|
54
|
+
{ status: res.status, **request_info }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
crumb = ::Sentry::Breadcrumb.new(
|
|
58
|
+
level: :info,
|
|
59
|
+
category: "httpx",
|
|
60
|
+
type: :info,
|
|
61
|
+
data: data
|
|
62
|
+
)
|
|
63
|
+
::Sentry.add_breadcrumb(crumb)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def record_sentry_span(req, res, sentry_span)
|
|
67
|
+
return unless sentry_span
|
|
68
|
+
|
|
69
|
+
request_info = extract_request_info(req)
|
|
70
|
+
sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
|
|
71
|
+
if res.is_a?(HTTPX::ErrorResponse)
|
|
72
|
+
sentry_span.set_data(:error, res.error.message)
|
|
73
|
+
else
|
|
74
|
+
sentry_span.set_data(:status, res.status)
|
|
75
|
+
end
|
|
76
|
+
sentry_span.set_timestamp(::Sentry.utc_now.to_f)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def extract_request_info(req)
|
|
80
|
+
uri = req.uri
|
|
81
|
+
|
|
82
|
+
result = {
|
|
83
|
+
method: req.verb,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if ::Sentry.configuration.send_default_pii
|
|
87
|
+
uri += "?#{req.query}" unless req.query.empty?
|
|
88
|
+
result[:body] = req.body.to_s unless req.body.empty? || req.body.unbounded_body?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
result[:url] = uri.to_s
|
|
92
|
+
|
|
93
|
+
result
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
module RequestMethods
|
|
98
|
+
def __sentry_enable_trace!
|
|
99
|
+
return if @__sentry_enable_trace
|
|
100
|
+
|
|
101
|
+
Tracer.call(self)
|
|
102
|
+
@__sentry_enable_trace = true
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
module ConnectionMethods
|
|
107
|
+
def send(request)
|
|
108
|
+
request.__sentry_enable_trace!
|
|
109
|
+
|
|
110
|
+
super
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
Sentry.register_patch(:httpx) do
|
|
117
|
+
sentry_session = HTTPX.plugin(HTTPX::Plugins::Sentry)
|
|
118
|
+
|
|
119
|
+
HTTPX.send(:remove_const, :Session)
|
|
120
|
+
HTTPX.send(:const_set, :Session, sentry_session.class)
|
|
121
|
+
end
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
module HttpLibAdapters
|
|
5
|
+
require "net/http/status"
|
|
6
|
+
HTTP_REASONS = Net::HTTP::STATUS_CODES
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# HTTPX plugin for webmock.
|
|
10
|
+
#
|
|
11
|
+
# Requests are "hijacked" at the session, before they're distributed to a connection.
|
|
12
|
+
#
|
|
13
|
+
module Plugin
|
|
14
|
+
class << self
|
|
15
|
+
def build_webmock_request_signature(request)
|
|
16
|
+
uri = WebMock::Util::URI.heuristic_parse(request.uri)
|
|
17
|
+
uri.query = request.query
|
|
18
|
+
uri.path = uri.normalized_path.gsub("[^:]//", "/")
|
|
19
|
+
|
|
20
|
+
WebMock::RequestSignature.new(
|
|
21
|
+
request.verb.downcase.to_sym,
|
|
22
|
+
uri.to_s,
|
|
23
|
+
body: request.body.to_s,
|
|
24
|
+
headers: request.headers.to_h
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def build_webmock_response(_request, response)
|
|
29
|
+
webmock_response = WebMock::Response.new
|
|
30
|
+
webmock_response.status = [response.status, HTTP_REASONS[response.status]]
|
|
31
|
+
webmock_response.body = response.body.to_s
|
|
32
|
+
webmock_response.headers = response.headers.to_h
|
|
33
|
+
webmock_response
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def build_from_webmock_response(request, webmock_response)
|
|
37
|
+
return build_error_response(request, HTTPX::TimeoutError.new(1, "Timed out")) if webmock_response.should_timeout
|
|
38
|
+
|
|
39
|
+
return build_error_response(request, webmock_response.exception) if webmock_response.exception
|
|
40
|
+
|
|
41
|
+
request.options.response_class.new(request,
|
|
42
|
+
webmock_response.status[0],
|
|
43
|
+
"2.0",
|
|
44
|
+
webmock_response.headers).tap do |res|
|
|
45
|
+
res.mocked = true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def build_error_response(request, exception)
|
|
50
|
+
HTTPX::ErrorResponse.new(request, exception)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
module InstanceMethods
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def do_init_connection(connection, selector)
|
|
58
|
+
super
|
|
59
|
+
|
|
60
|
+
connection.once(:unmock_connection) do
|
|
61
|
+
next unless connection.current_session == self
|
|
62
|
+
|
|
63
|
+
unless connection.addresses?
|
|
64
|
+
# reset Happy Eyeballs, fail early
|
|
65
|
+
connection.sibling = nil
|
|
66
|
+
|
|
67
|
+
deselect_connection(connection, selector)
|
|
68
|
+
end
|
|
69
|
+
resolve_connection(connection, selector)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
module ResponseMethods
|
|
75
|
+
attr_accessor :mocked
|
|
76
|
+
|
|
77
|
+
def initialize(*)
|
|
78
|
+
super
|
|
79
|
+
@mocked = false
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
module ResponseBodyMethods
|
|
84
|
+
def decode_chunk(chunk)
|
|
85
|
+
return chunk if @response.mocked
|
|
86
|
+
|
|
87
|
+
super
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
module ConnectionMethods
|
|
92
|
+
def initialize(*)
|
|
93
|
+
super
|
|
94
|
+
@mocked = true
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def open?
|
|
98
|
+
return true if @mocked
|
|
99
|
+
|
|
100
|
+
super
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def interests
|
|
104
|
+
return if @mocked
|
|
105
|
+
|
|
106
|
+
super
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def terminate
|
|
110
|
+
force_reset
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def send(request)
|
|
114
|
+
request_signature = Plugin.build_webmock_request_signature(request)
|
|
115
|
+
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
116
|
+
|
|
117
|
+
if (mock_response = WebMock::StubRegistry.instance.response_for_request(request_signature))
|
|
118
|
+
response = Plugin.build_from_webmock_response(request, mock_response)
|
|
119
|
+
WebMock::CallbackRegistry.invoke_callbacks({ lib: :httpx }, request_signature, mock_response)
|
|
120
|
+
log { "mocking #{request.uri} with #{mock_response.inspect}" }
|
|
121
|
+
request.transition(:headers)
|
|
122
|
+
request.transition(:body)
|
|
123
|
+
request.transition(:trailers)
|
|
124
|
+
request.transition(:done)
|
|
125
|
+
response.finish!
|
|
126
|
+
request.response = response
|
|
127
|
+
request.emit(:response, response)
|
|
128
|
+
request_signature.headers = request.headers.to_h
|
|
129
|
+
|
|
130
|
+
response << mock_response.body.dup unless response.is_a?(HTTPX::ErrorResponse)
|
|
131
|
+
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
132
|
+
if WebMock::CallbackRegistry.any_callbacks?
|
|
133
|
+
request.on(:response) do |resp|
|
|
134
|
+
unless resp.is_a?(HTTPX::ErrorResponse)
|
|
135
|
+
webmock_response = Plugin.build_webmock_response(request, resp)
|
|
136
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
137
|
+
{ lib: :httpx, real_request: true }, request_signature,
|
|
138
|
+
webmock_response
|
|
139
|
+
)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
@mocked = false
|
|
144
|
+
emit(:unmock_connection, self)
|
|
145
|
+
super
|
|
146
|
+
else
|
|
147
|
+
raise WebMock::NetConnectNotAllowedError, request_signature
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
class HttpxAdapter < HttpLibAdapter
|
|
154
|
+
adapter_for :httpx
|
|
155
|
+
|
|
156
|
+
class << self
|
|
157
|
+
def enable!
|
|
158
|
+
@original_session ||= HTTPX::Session
|
|
159
|
+
|
|
160
|
+
webmock_session = HTTPX.plugin(Plugin)
|
|
161
|
+
|
|
162
|
+
HTTPX.send(:remove_const, :Session)
|
|
163
|
+
HTTPX.send(:const_set, :Session, webmock_session.class)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def disable!
|
|
167
|
+
return unless @original_session
|
|
168
|
+
|
|
169
|
+
HTTPX.send(:remove_const, :Session)
|
|
170
|
+
HTTPX.send(:const_set, :Session, @original_session)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
data/lib/httpx/altsvc.rb
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "strscan"
|
|
4
|
+
|
|
5
|
+
module HTTPX
|
|
6
|
+
module AltSvc
|
|
7
|
+
# makes connections able to accept requests destined to primary service.
|
|
8
|
+
module ConnectionMixin
|
|
9
|
+
using URIExtensions
|
|
10
|
+
|
|
11
|
+
def send(request)
|
|
12
|
+
request.headers["alt-used"] = @origin.authority if @parser && !@write_buffer.full? && match_altsvcs?(request.uri)
|
|
13
|
+
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def match?(uri, options)
|
|
18
|
+
return false if !used? && (@state == :closing || @state == :closed)
|
|
19
|
+
|
|
20
|
+
match_altsvcs?(uri) && match_altsvc_options?(uri, options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# checks if this is connection is an alternative service of
|
|
26
|
+
# +uri+
|
|
27
|
+
def match_altsvcs?(uri)
|
|
28
|
+
@origins.any? { |origin| altsvc_match?(uri, origin) } ||
|
|
29
|
+
AltSvc.cached_altsvc(@origin).any? do |altsvc|
|
|
30
|
+
origin = altsvc["origin"]
|
|
31
|
+
altsvc_match?(origin, uri.origin)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def match_altsvc_options?(uri, options)
|
|
36
|
+
return @options == options unless @options.ssl.all? do |k, v|
|
|
37
|
+
v == (k == :hostname ? uri.host : options.ssl[k])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
@options.options_equals?(options, Options::REQUEST_BODY_IVARS + %i[@ssl])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def altsvc_match?(uri, other_uri)
|
|
44
|
+
other_uri = URI(other_uri)
|
|
45
|
+
|
|
46
|
+
uri.origin == other_uri.origin || begin
|
|
47
|
+
case uri.scheme
|
|
48
|
+
when "h2"
|
|
49
|
+
(other_uri.scheme == "https" || other_uri.scheme == "h2") &&
|
|
50
|
+
uri.host == other_uri.host &&
|
|
51
|
+
uri.port == other_uri.port
|
|
52
|
+
else
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@altsvc_mutex = Thread::Mutex.new
|
|
60
|
+
@altsvcs = Hash.new { |h, k| h[k] = [] }
|
|
61
|
+
|
|
62
|
+
module_function
|
|
63
|
+
|
|
64
|
+
def cached_altsvc(origin)
|
|
65
|
+
now = Utils.now
|
|
66
|
+
@altsvc_mutex.synchronize do
|
|
67
|
+
lookup(origin, now)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def cached_altsvc_set(origin, entry)
|
|
72
|
+
now = Utils.now
|
|
73
|
+
@altsvc_mutex.synchronize do
|
|
74
|
+
return if @altsvcs[origin].any? { |altsvc| altsvc["origin"] == entry["origin"] }
|
|
75
|
+
|
|
76
|
+
entry["TTL"] = Integer(entry["ma"]) + now if entry.key?("ma")
|
|
77
|
+
@altsvcs[origin] << entry
|
|
78
|
+
entry
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def lookup(origin, ttl)
|
|
83
|
+
return [] unless @altsvcs.key?(origin)
|
|
84
|
+
|
|
85
|
+
@altsvcs[origin] = @altsvcs[origin].select do |entry|
|
|
86
|
+
!entry.key?("TTL") || entry["TTL"] > ttl
|
|
87
|
+
end
|
|
88
|
+
@altsvcs[origin].reject { |entry| entry["noop"] }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def emit(request, response)
|
|
92
|
+
return unless response.respond_to?(:headers)
|
|
93
|
+
# Alt-Svc
|
|
94
|
+
return unless response.headers.key?("alt-svc")
|
|
95
|
+
|
|
96
|
+
origin = request.origin
|
|
97
|
+
host = request.uri.host
|
|
98
|
+
|
|
99
|
+
altsvc = response.headers["alt-svc"]
|
|
100
|
+
|
|
101
|
+
# https://datatracker.ietf.org/doc/html/rfc7838#section-3
|
|
102
|
+
# A field value containing the special value "clear" indicates that the
|
|
103
|
+
# origin requests all alternatives for that origin to be invalidated
|
|
104
|
+
# (including those specified in the same response, in case of an
|
|
105
|
+
# invalid reply containing both "clear" and alternative services).
|
|
106
|
+
if altsvc == "clear"
|
|
107
|
+
@altsvc_mutex.synchronize do
|
|
108
|
+
@altsvcs[origin].clear
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
return
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
parse(altsvc) do |alt_origin, alt_params|
|
|
115
|
+
alt_origin.host ||= host
|
|
116
|
+
yield(alt_origin, origin, alt_params)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def parse(altsvc)
|
|
121
|
+
return enum_for(__method__, altsvc) unless block_given?
|
|
122
|
+
|
|
123
|
+
scanner = StringScanner.new(altsvc)
|
|
124
|
+
until scanner.eos?
|
|
125
|
+
alt_service = scanner.scan(/[^=]+=("[^"]+"|[^;,]+)/)
|
|
126
|
+
|
|
127
|
+
alt_params = []
|
|
128
|
+
loop do
|
|
129
|
+
alt_param = scanner.scan(/[^=]+=("[^"]+"|[^;,]+)/)
|
|
130
|
+
alt_params << alt_param.strip if alt_param
|
|
131
|
+
scanner.skip(/;/)
|
|
132
|
+
break if scanner.eos? || scanner.scan(/ *, */)
|
|
133
|
+
end
|
|
134
|
+
alt_params = Hash[alt_params.map { |field| field.split("=", 2) }]
|
|
135
|
+
|
|
136
|
+
alt_proto, alt_authority = alt_service.split("=", 2)
|
|
137
|
+
alt_origin = parse_altsvc_origin(alt_proto, alt_authority)
|
|
138
|
+
return unless alt_origin
|
|
139
|
+
|
|
140
|
+
yield(alt_origin, alt_params.merge("proto" => alt_proto))
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def parse_altsvc_scheme(alt_proto)
|
|
145
|
+
case alt_proto
|
|
146
|
+
when "h2c"
|
|
147
|
+
"http"
|
|
148
|
+
when "h2"
|
|
149
|
+
"https"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def parse_altsvc_origin(alt_proto, alt_origin)
|
|
154
|
+
alt_scheme = parse_altsvc_scheme(alt_proto)
|
|
155
|
+
|
|
156
|
+
return unless alt_scheme
|
|
157
|
+
|
|
158
|
+
alt_origin = alt_origin[1..-2] if alt_origin.start_with?("\"") && alt_origin.end_with?("\"")
|
|
159
|
+
|
|
160
|
+
URI.parse("#{alt_scheme}://#{alt_origin}")
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
data/lib/httpx/base64.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
if RUBY_VERSION < "3.3.0"
|
|
4
|
+
require "base64"
|
|
5
|
+
elsif !defined?(Base64)
|
|
6
|
+
module HTTPX
|
|
7
|
+
# require "base64" will not be a default gem after ruby 3.4.0
|
|
8
|
+
module Base64
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def decode64(str)
|
|
12
|
+
str.unpack1("m")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def strict_encode64(bin)
|
|
16
|
+
[bin].pack("m0")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def urlsafe_encode64(bin, padding: true)
|
|
20
|
+
str = strict_encode64(bin)
|
|
21
|
+
str.chomp!("==") or str.chomp!("=") unless padding
|
|
22
|
+
str.tr!("+/", "-_")
|
|
23
|
+
str
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/httpx/buffer.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
|
|
5
|
+
module HTTPX
|
|
6
|
+
# Internal class to abstract a string buffer, by wrapping a string and providing the
|
|
7
|
+
# minimum possible API and functionality required.
|
|
8
|
+
#
|
|
9
|
+
# buffer = Buffer.new(640)
|
|
10
|
+
# buffer.full? #=> false
|
|
11
|
+
# buffer << "aa"
|
|
12
|
+
# buffer.capacity #=> 638
|
|
13
|
+
#
|
|
14
|
+
class Buffer
|
|
15
|
+
extend Forwardable
|
|
16
|
+
|
|
17
|
+
def_delegator :@buffer, :to_s
|
|
18
|
+
|
|
19
|
+
def_delegator :@buffer, :to_str
|
|
20
|
+
|
|
21
|
+
def_delegator :@buffer, :empty?
|
|
22
|
+
|
|
23
|
+
def_delegator :@buffer, :bytesize
|
|
24
|
+
|
|
25
|
+
def_delegator :@buffer, :clear
|
|
26
|
+
|
|
27
|
+
def_delegator :@buffer, :replace
|
|
28
|
+
|
|
29
|
+
attr_reader :limit
|
|
30
|
+
|
|
31
|
+
if RUBY_VERSION >= "3.4.0"
|
|
32
|
+
def initialize(limit)
|
|
33
|
+
@buffer = String.new("", encoding: Encoding::BINARY, capacity: limit)
|
|
34
|
+
@limit = limit
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def <<(chunk)
|
|
38
|
+
@buffer.append_as_bytes(chunk)
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
def initialize(limit)
|
|
42
|
+
@buffer = "".b
|
|
43
|
+
@limit = limit
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def_delegator :@buffer, :<<
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def full?
|
|
50
|
+
@buffer.bytesize >= @limit
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def capacity
|
|
54
|
+
@limit - @buffer.bytesize
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def shift!(fin)
|
|
58
|
+
@buffer = @buffer.byteslice(fin..-1) || "".b
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Callbacks
|
|
5
|
+
def on(type, &action)
|
|
6
|
+
callbacks(type) << action
|
|
7
|
+
action
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def once(type, &block)
|
|
11
|
+
on(type) do |*args, &callback|
|
|
12
|
+
block.call(*args, &callback)
|
|
13
|
+
:delete
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def emit(type, *args)
|
|
18
|
+
log { "emit #{type.inspect} callbacks" } if respond_to?(:log)
|
|
19
|
+
callbacks(type).delete_if { |pr| :delete == pr.call(*args) } # rubocop:disable Style/YodaCondition
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def callbacks_for?(type)
|
|
23
|
+
@callbacks && @callbacks.key?(type) && @callbacks[type].any?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
def callbacks(type = nil)
|
|
29
|
+
return @callbacks unless type
|
|
30
|
+
|
|
31
|
+
@callbacks ||= Hash.new { |h, k| h[k] = [] }
|
|
32
|
+
@callbacks[type]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
# Session mixin, implements most of the APIs that the users call.
|
|
5
|
+
# delegates to a default session when extended.
|
|
6
|
+
module Chainable
|
|
7
|
+
%w[head get post put delete trace options connect patch].each do |meth|
|
|
8
|
+
class_eval(<<-MOD, __FILE__, __LINE__ + 1)
|
|
9
|
+
def #{meth}(*uri, **options) # def get(*uri, **options)
|
|
10
|
+
request("#{meth.upcase}", uri, **options) # request("GET", uri, **options)
|
|
11
|
+
end # end
|
|
12
|
+
MOD
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# delegates to the default session (see HTTPX::Session#request).
|
|
16
|
+
def request(*args, **options)
|
|
17
|
+
branch(default_options).request(*args, **options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def accept(type)
|
|
21
|
+
with(headers: { "accept" => String(type) })
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# delegates to the default session (see HTTPX::Session#wrap).
|
|
25
|
+
def wrap(&blk)
|
|
26
|
+
branch(default_options).wrap(&blk)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# returns a new instance loaded with the +pl+ plugin and +options+.
|
|
30
|
+
def plugin(pl, options = nil, &blk)
|
|
31
|
+
klass = is_a?(S) ? self.class : Session
|
|
32
|
+
klass = Class.new(klass)
|
|
33
|
+
klass.instance_variable_set(:@default_options, klass.default_options.merge(default_options))
|
|
34
|
+
klass.plugin(pl, options, &blk).new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# returns a new instance loaded with +options+.
|
|
38
|
+
def with(options, &blk)
|
|
39
|
+
branch(default_options.merge(options), &blk)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# returns default instance of HTTPX::Options.
|
|
45
|
+
def default_options
|
|
46
|
+
@options || Session.default_options
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# returns a default instance of HTTPX::Session.
|
|
50
|
+
def branch(options, &blk)
|
|
51
|
+
return self.class.new(options, &blk) if is_a?(S)
|
|
52
|
+
|
|
53
|
+
Session.new(options, &blk)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def method_missing(meth, *args, **options, &blk)
|
|
57
|
+
case meth
|
|
58
|
+
when /\Awith_(.+)/
|
|
59
|
+
|
|
60
|
+
option = Regexp.last_match(1)
|
|
61
|
+
|
|
62
|
+
return super unless option
|
|
63
|
+
|
|
64
|
+
with(option.to_sym => args.first || options)
|
|
65
|
+
when /\Aon_(.+)/
|
|
66
|
+
callback = Regexp.last_match(1)
|
|
67
|
+
|
|
68
|
+
return super unless %w[
|
|
69
|
+
connection_opened connection_closed
|
|
70
|
+
request_error
|
|
71
|
+
request_started request_body_chunk request_completed
|
|
72
|
+
response_started response_body_chunk response_completed
|
|
73
|
+
].include?(callback)
|
|
74
|
+
|
|
75
|
+
warn "DEPRECATION WARNING: calling `.#{meth}` on plain HTTPX sessions is deprecated. " \
|
|
76
|
+
"Use `HTTPX.plugin(:callbacks).#{meth}` instead."
|
|
77
|
+
|
|
78
|
+
plugin(:callbacks).__send__(meth, *args, **options, &blk)
|
|
79
|
+
else
|
|
80
|
+
super
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def respond_to_missing?(meth, *)
|
|
85
|
+
case meth
|
|
86
|
+
when /\Awith_(.+)/
|
|
87
|
+
option = Regexp.last_match(1)
|
|
88
|
+
|
|
89
|
+
default_options.respond_to?(option) || super
|
|
90
|
+
when /\Aon_(.+)/
|
|
91
|
+
callback = Regexp.last_match(1)
|
|
92
|
+
|
|
93
|
+
%w[
|
|
94
|
+
connection_opened connection_closed
|
|
95
|
+
request_error
|
|
96
|
+
request_started request_body_chunk request_completed
|
|
97
|
+
response_started response_body_chunk response_completed
|
|
98
|
+
].include?(callback) || super
|
|
99
|
+
else
|
|
100
|
+
super
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
extend Chainable
|
|
106
|
+
end
|