httpx 0.21.0 → 1.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 +4 -4
- data/LICENSE.txt +0 -48
- data/README.md +54 -45
- data/doc/release_notes/0_10_0.md +2 -2
- data/doc/release_notes/0_11_0.md +3 -5
- data/doc/release_notes/0_12_0.md +5 -5
- data/doc/release_notes/0_13_0.md +4 -4
- data/doc/release_notes/0_14_0.md +2 -2
- data/doc/release_notes/0_16_0.md +3 -3
- data/doc/release_notes/0_17_0.md +1 -1
- data/doc/release_notes/0_18_0.md +4 -4
- data/doc/release_notes/0_18_2.md +1 -1
- data/doc/release_notes/0_19_0.md +1 -1
- data/doc/release_notes/0_20_0.md +1 -1
- data/doc/release_notes/0_21_0.md +7 -5
- data/doc/release_notes/0_21_1.md +12 -0
- data/doc/release_notes/0_22_0.md +13 -0
- data/doc/release_notes/0_22_1.md +11 -0
- data/doc/release_notes/0_22_2.md +5 -0
- data/doc/release_notes/0_22_3.md +55 -0
- data/doc/release_notes/0_22_4.md +6 -0
- data/doc/release_notes/0_22_5.md +6 -0
- data/doc/release_notes/0_23_0.md +42 -0
- data/doc/release_notes/0_23_1.md +5 -0
- data/doc/release_notes/0_23_2.md +5 -0
- data/doc/release_notes/0_23_3.md +6 -0
- data/doc/release_notes/0_23_4.md +5 -0
- data/doc/release_notes/0_24_0.md +48 -0
- data/doc/release_notes/0_24_1.md +12 -0
- data/doc/release_notes/0_24_2.md +12 -0
- data/doc/release_notes/0_24_3.md +12 -0
- data/doc/release_notes/0_24_4.md +18 -0
- data/doc/release_notes/0_24_5.md +6 -0
- data/doc/release_notes/0_24_6.md +5 -0
- data/doc/release_notes/0_24_7.md +10 -0
- data/doc/release_notes/1_0_0.md +60 -0
- data/doc/release_notes/1_0_1.md +5 -0
- data/doc/release_notes/1_0_2.md +7 -0
- data/doc/release_notes/1_1_0.md +32 -0
- data/doc/release_notes/1_1_1.md +17 -0
- data/doc/release_notes/1_1_2.md +12 -0
- data/doc/release_notes/1_1_3.md +18 -0
- data/doc/release_notes/1_1_4.md +6 -0
- data/doc/release_notes/1_1_5.md +12 -0
- data/doc/release_notes/1_2_0.md +49 -0
- data/doc/release_notes/1_2_1.md +6 -0
- data/lib/httpx/adapters/datadog.rb +100 -106
- data/lib/httpx/adapters/faraday.rb +143 -107
- data/lib/httpx/adapters/sentry.rb +26 -7
- data/lib/httpx/adapters/webmock.rb +33 -17
- data/lib/httpx/altsvc.rb +61 -24
- data/lib/httpx/base64.rb +27 -0
- data/lib/httpx/buffer.rb +12 -0
- data/lib/httpx/callbacks.rb +5 -3
- data/lib/httpx/chainable.rb +54 -39
- data/lib/httpx/connection/http1.rb +62 -37
- data/lib/httpx/connection/http2.rb +16 -27
- data/lib/httpx/connection.rb +213 -120
- data/lib/httpx/domain_name.rb +10 -13
- data/lib/httpx/errors.rb +34 -2
- data/lib/httpx/extensions.rb +4 -134
- data/lib/httpx/io/ssl.rb +77 -71
- data/lib/httpx/io/tcp.rb +46 -70
- data/lib/httpx/io/udp.rb +18 -52
- data/lib/httpx/io/unix.rb +6 -13
- data/lib/httpx/io.rb +3 -9
- data/lib/httpx/loggable.rb +4 -19
- data/lib/httpx/options.rb +168 -110
- data/lib/httpx/plugins/{authentication → auth}/basic.rb +1 -5
- data/lib/httpx/plugins/{authentication → auth}/digest.rb +13 -14
- data/lib/httpx/plugins/{authentication → auth}/ntlm.rb +1 -3
- data/lib/httpx/plugins/{authentication → auth}/socks5.rb +0 -2
- data/lib/httpx/plugins/auth.rb +25 -0
- data/lib/httpx/plugins/aws_sdk_authentication.rb +1 -3
- data/lib/httpx/plugins/aws_sigv4.rb +5 -6
- data/lib/httpx/plugins/basic_auth.rb +29 -0
- data/lib/httpx/plugins/brotli.rb +50 -0
- data/lib/httpx/plugins/callbacks.rb +91 -0
- data/lib/httpx/plugins/circuit_breaker/circuit.rb +40 -16
- data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +14 -5
- data/lib/httpx/plugins/circuit_breaker.rb +30 -7
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +0 -2
- data/lib/httpx/plugins/cookies.rb +20 -10
- data/lib/httpx/plugins/{digest_authentication.rb → digest_auth.rb} +11 -12
- data/lib/httpx/plugins/expect.rb +15 -13
- data/lib/httpx/plugins/follow_redirects.rb +71 -29
- data/lib/httpx/plugins/grpc/call.rb +2 -3
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +88 -0
- data/lib/httpx/plugins/grpc/message.rb +7 -37
- data/lib/httpx/plugins/grpc.rb +35 -29
- data/lib/httpx/plugins/h2c.rb +25 -18
- data/lib/httpx/plugins/internal_telemetry.rb +16 -0
- data/lib/httpx/plugins/{ntlm_authentication.rb → ntlm_auth.rb} +7 -5
- data/lib/httpx/plugins/oauth.rb +170 -0
- data/lib/httpx/plugins/persistent.rb +1 -1
- data/lib/httpx/plugins/proxy/http.rb +15 -10
- data/lib/httpx/plugins/proxy/socks4.rb +8 -6
- data/lib/httpx/plugins/proxy/socks5.rb +10 -8
- data/lib/httpx/plugins/proxy.rb +69 -67
- data/lib/httpx/plugins/push_promise.rb +1 -1
- data/lib/httpx/plugins/rate_limiter.rb +3 -1
- data/lib/httpx/plugins/response_cache/file_store.rb +40 -0
- data/lib/httpx/plugins/response_cache/store.rb +34 -17
- data/lib/httpx/plugins/response_cache.rb +6 -6
- data/lib/httpx/plugins/retries.rb +61 -12
- data/lib/httpx/plugins/ssrf_filter.rb +142 -0
- data/lib/httpx/plugins/stream.rb +27 -32
- data/lib/httpx/plugins/upgrade/h2.rb +4 -4
- data/lib/httpx/plugins/upgrade.rb +8 -10
- data/lib/httpx/plugins/webdav.rb +10 -8
- data/lib/httpx/pool.rb +85 -23
- data/lib/httpx/punycode.rb +9 -291
- data/lib/httpx/request/body.rb +158 -0
- data/lib/httpx/request.rb +86 -121
- data/lib/httpx/resolver/https.rb +54 -17
- data/lib/httpx/resolver/multi.rb +8 -12
- data/lib/httpx/resolver/native.rb +163 -70
- data/lib/httpx/resolver/resolver.rb +28 -13
- data/lib/httpx/resolver/system.rb +15 -10
- data/lib/httpx/resolver.rb +38 -16
- data/lib/httpx/response/body.rb +242 -0
- data/lib/httpx/response/buffer.rb +96 -0
- data/lib/httpx/response.rb +113 -211
- data/lib/httpx/selector.rb +2 -4
- data/lib/httpx/session.rb +91 -64
- data/lib/httpx/session_extensions.rb +4 -1
- data/lib/httpx/timers.rb +28 -8
- data/lib/httpx/transcoder/body.rb +0 -2
- data/lib/httpx/transcoder/chunker.rb +0 -1
- data/lib/httpx/transcoder/deflate.rb +37 -0
- data/lib/httpx/transcoder/form.rb +52 -33
- data/lib/httpx/transcoder/gzip.rb +74 -0
- data/lib/httpx/transcoder/json.rb +2 -5
- data/lib/httpx/transcoder/multipart/decoder.rb +139 -0
- data/lib/httpx/{plugins → transcoder}/multipart/encoder.rb +3 -3
- data/lib/httpx/{plugins → transcoder}/multipart/mime_type_detector.rb +1 -1
- data/lib/httpx/{plugins → transcoder}/multipart/part.rb +3 -2
- data/lib/httpx/transcoder/multipart.rb +17 -0
- data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
- data/lib/httpx/transcoder/utils/deflater.rb +72 -0
- data/lib/httpx/transcoder/utils/inflater.rb +19 -0
- data/lib/httpx/transcoder/xml.rb +0 -5
- data/lib/httpx/transcoder.rb +4 -6
- data/lib/httpx/utils.rb +36 -16
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +12 -14
- data/sig/altsvc.rbs +33 -0
- data/sig/buffer.rbs +1 -0
- data/sig/callbacks.rbs +3 -3
- data/sig/chainable.rbs +10 -9
- data/sig/connection/http1.rbs +5 -4
- data/sig/connection/http2.rbs +1 -1
- data/sig/connection.rbs +46 -24
- data/sig/errors.rbs +9 -3
- data/sig/httpx.rbs +5 -4
- data/sig/io/ssl.rbs +26 -0
- data/sig/io/tcp.rbs +60 -0
- data/sig/io/udp.rbs +20 -0
- data/sig/io/unix.rbs +10 -0
- data/sig/options.rbs +28 -12
- data/sig/plugins/{authentication → auth}/basic.rbs +0 -2
- data/sig/plugins/{authentication → auth}/digest.rbs +2 -1
- data/sig/plugins/auth.rbs +13 -0
- data/sig/plugins/{basic_authentication.rbs → basic_auth.rbs} +2 -2
- data/sig/plugins/brotli.rbs +22 -0
- data/sig/plugins/callbacks.rbs +38 -0
- data/sig/plugins/circuit_breaker.rbs +13 -3
- data/sig/plugins/compression.rbs +6 -4
- data/sig/plugins/cookies/jar.rbs +2 -2
- data/sig/plugins/cookies.rbs +2 -0
- data/sig/plugins/{digest_authentication.rbs → digest_auth.rbs} +2 -2
- data/sig/plugins/follow_redirects.rbs +11 -2
- data/sig/plugins/grpc/call.rbs +19 -0
- data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
- data/sig/plugins/grpc/message.rbs +17 -0
- data/sig/plugins/grpc.rbs +2 -32
- data/sig/plugins/h2c.rbs +1 -1
- data/sig/plugins/{ntlm_authentication.rbs → ntlm_auth.rbs} +2 -2
- data/sig/plugins/oauth.rbs +54 -0
- data/sig/plugins/proxy/socks4.rbs +4 -4
- data/sig/plugins/proxy/socks5.rbs +2 -2
- data/sig/plugins/proxy/ssh.rbs +1 -1
- data/sig/plugins/proxy.rbs +10 -4
- data/sig/plugins/response_cache.rbs +12 -3
- data/sig/plugins/retries.rbs +28 -8
- data/sig/plugins/stream.rbs +24 -17
- data/sig/plugins/upgrade.rbs +5 -3
- data/sig/pool.rbs +5 -4
- data/sig/request/body.rbs +40 -0
- data/sig/request.rbs +12 -28
- data/sig/resolver/https.rbs +7 -2
- data/sig/resolver/native.rbs +10 -4
- data/sig/resolver/resolver.rbs +6 -4
- data/sig/resolver/system.rbs +2 -0
- data/sig/resolver.rbs +9 -5
- data/sig/response/body.rbs +53 -0
- data/sig/response/buffer.rbs +24 -0
- data/sig/response.rbs +17 -38
- data/sig/session.rbs +24 -18
- data/sig/timers.rbs +17 -7
- data/sig/transcoder/body.rbs +4 -3
- data/sig/transcoder/deflate.rbs +11 -0
- data/sig/transcoder/form.rbs +5 -3
- data/sig/transcoder/gzip.rbs +24 -0
- data/sig/transcoder/json.rbs +4 -2
- data/sig/{plugins → transcoder}/multipart.rbs +3 -12
- data/sig/transcoder/utils/body_reader.rbs +15 -0
- data/sig/transcoder/utils/deflater.rbs +29 -0
- data/sig/transcoder/utils/inflater.rbs +12 -0
- data/sig/transcoder/xml.rbs +1 -1
- data/sig/transcoder.rbs +22 -7
- data/sig/utils.rbs +2 -0
- metadata +127 -40
- data/lib/httpx/plugins/authentication.rb +0 -20
- data/lib/httpx/plugins/basic_authentication.rb +0 -30
- data/lib/httpx/plugins/compression/brotli.rb +0 -54
- data/lib/httpx/plugins/compression/deflate.rb +0 -49
- data/lib/httpx/plugins/compression/gzip.rb +0 -88
- data/lib/httpx/plugins/compression.rb +0 -164
- data/lib/httpx/plugins/multipart/decoder.rb +0 -187
- data/lib/httpx/plugins/multipart.rb +0 -84
- data/lib/httpx/registry.rb +0 -85
- data/sig/plugins/authentication.rbs +0 -11
- data/sig/plugins/compression/brotli.rbs +0 -21
- data/sig/plugins/compression/deflate.rbs +0 -17
- data/sig/plugins/compression/gzip.rbs +0 -29
- data/sig/registry.rbs +0 -13
- /data/sig/plugins/{authentication → auth}/ntlm.rbs +0 -0
- /data/sig/plugins/{authentication → auth}/socks5.rbs +0 -0
|
@@ -27,6 +27,11 @@ module HTTPX::Plugins
|
|
|
27
27
|
def set_sentry_trace_header(request, sentry_span)
|
|
28
28
|
return unless sentry_span
|
|
29
29
|
|
|
30
|
+
config = ::Sentry.configuration
|
|
31
|
+
url = request.uri.to_s
|
|
32
|
+
|
|
33
|
+
return unless config.propagate_traces && config.trace_propagation_targets.any? { |target| url.match?(target) }
|
|
34
|
+
|
|
30
35
|
trace = ::Sentry.get_current_client.generate_sentry_trace(sentry_span)
|
|
31
36
|
request.headers[::Sentry::SENTRY_TRACE_HEADER_NAME] = trace if trace
|
|
32
37
|
end
|
|
@@ -43,8 +48,8 @@ module HTTPX::Plugins
|
|
|
43
48
|
|
|
44
49
|
request_info = extract_request_info(req)
|
|
45
50
|
|
|
46
|
-
data = if
|
|
47
|
-
{ error: res.message, **request_info }
|
|
51
|
+
data = if res.is_a?(HTTPX::ErrorResponse)
|
|
52
|
+
{ error: res.error.message, **request_info }
|
|
48
53
|
else
|
|
49
54
|
{ status: res.status, **request_info }
|
|
50
55
|
end
|
|
@@ -63,7 +68,11 @@ module HTTPX::Plugins
|
|
|
63
68
|
|
|
64
69
|
request_info = extract_request_info(req)
|
|
65
70
|
sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
|
|
66
|
-
|
|
71
|
+
if res.is_a?(HTTPX::ErrorResponse)
|
|
72
|
+
sentry_span.set_data(:error, res.error.message)
|
|
73
|
+
else
|
|
74
|
+
sentry_span.set_data(:status, res.status)
|
|
75
|
+
end
|
|
67
76
|
sentry_span.set_timestamp(::Sentry.utc_now.to_f)
|
|
68
77
|
end
|
|
69
78
|
|
|
@@ -71,7 +80,7 @@ module HTTPX::Plugins
|
|
|
71
80
|
uri = req.uri
|
|
72
81
|
|
|
73
82
|
result = {
|
|
74
|
-
method: req.verb
|
|
83
|
+
method: req.verb,
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
if ::Sentry.configuration.send_default_pii
|
|
@@ -85,17 +94,27 @@ module HTTPX::Plugins
|
|
|
85
94
|
end
|
|
86
95
|
end
|
|
87
96
|
|
|
97
|
+
module RequestMethods
|
|
98
|
+
def __sentry_enable_trace!
|
|
99
|
+
return if @__sentry_enable_trace
|
|
100
|
+
|
|
101
|
+
Tracer.call(self)
|
|
102
|
+
@__sentry_enable_trace = true
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
88
106
|
module ConnectionMethods
|
|
89
107
|
def send(request)
|
|
90
|
-
|
|
108
|
+
request.__sentry_enable_trace!
|
|
109
|
+
|
|
91
110
|
super
|
|
92
111
|
end
|
|
93
112
|
end
|
|
94
113
|
end
|
|
95
114
|
end
|
|
96
115
|
|
|
97
|
-
Sentry.register_patch do
|
|
98
|
-
sentry_session =
|
|
116
|
+
Sentry.register_patch(:httpx) do
|
|
117
|
+
sentry_session = HTTPX.plugin(HTTPX::Plugins::Sentry)
|
|
99
118
|
|
|
100
119
|
HTTPX.send(:remove_const, :Session)
|
|
101
120
|
HTTPX.send(:const_set, :Session, sentry_session.class)
|
|
@@ -2,13 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module WebMock
|
|
4
4
|
module HttpLibAdapters
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
HTTP_REASONS = WEBrick::HTTPStatus::StatusMessage
|
|
8
|
-
else
|
|
9
|
-
require "net/http/status"
|
|
10
|
-
HTTP_REASONS = Net::HTTP::STATUS_CODES
|
|
11
|
-
end
|
|
5
|
+
require "net/http/status"
|
|
6
|
+
HTTP_REASONS = Net::HTTP::STATUS_CODES
|
|
12
7
|
|
|
13
8
|
#
|
|
14
9
|
# HTTPX plugin for webmock.
|
|
@@ -23,7 +18,7 @@ module WebMock
|
|
|
23
18
|
uri.path = uri.normalized_path.gsub("[^:]//", "/")
|
|
24
19
|
|
|
25
20
|
WebMock::RequestSignature.new(
|
|
26
|
-
request.verb,
|
|
21
|
+
request.verb.downcase.to_sym,
|
|
27
22
|
uri.to_s,
|
|
28
23
|
body: request.body.each.to_a.join,
|
|
29
24
|
headers: request.headers.to_h
|
|
@@ -43,12 +38,12 @@ module WebMock
|
|
|
43
38
|
|
|
44
39
|
return build_error_response(request, webmock_response.exception) if webmock_response.exception
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
request.options.response_class.new(request,
|
|
42
|
+
webmock_response.status[0],
|
|
43
|
+
"2.0",
|
|
44
|
+
webmock_response.headers).tap do |res|
|
|
45
|
+
res.mocked = true
|
|
46
|
+
end
|
|
52
47
|
end
|
|
53
48
|
|
|
54
49
|
def build_error_response(request, exception)
|
|
@@ -57,16 +52,36 @@ module WebMock
|
|
|
57
52
|
end
|
|
58
53
|
|
|
59
54
|
module InstanceMethods
|
|
60
|
-
def
|
|
55
|
+
def init_connection(*)
|
|
61
56
|
connection = super
|
|
62
57
|
connection.once(:unmock_connection) do
|
|
58
|
+
unless connection.addresses
|
|
59
|
+
connection.__send__(:callbacks)[:connect_error].clear
|
|
60
|
+
pool.__send__(:unregister_connection, connection)
|
|
61
|
+
end
|
|
63
62
|
pool.__send__(:resolve_connection, connection)
|
|
64
|
-
pool.__send__(:unregister_connection, connection) unless connection.addresses
|
|
65
63
|
end
|
|
66
64
|
connection
|
|
67
65
|
end
|
|
68
66
|
end
|
|
69
67
|
|
|
68
|
+
module ResponseMethods
|
|
69
|
+
attr_accessor :mocked
|
|
70
|
+
|
|
71
|
+
def initialize(*)
|
|
72
|
+
super
|
|
73
|
+
@mocked = false
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
module ResponseBodyMethods
|
|
78
|
+
def decode_chunk(chunk)
|
|
79
|
+
return chunk if @response.mocked
|
|
80
|
+
|
|
81
|
+
super
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
70
85
|
module ConnectionMethods
|
|
71
86
|
def initialize(*)
|
|
72
87
|
super
|
|
@@ -95,6 +110,7 @@ module WebMock
|
|
|
95
110
|
log { "mocking #{request.uri} with #{mock_response.inspect}" }
|
|
96
111
|
request.response = response
|
|
97
112
|
request.emit(:response, response)
|
|
113
|
+
response << mock_response.body.dup unless response.is_a?(HTTPX::ErrorResponse)
|
|
98
114
|
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
99
115
|
if WebMock::CallbackRegistry.any_callbacks?
|
|
100
116
|
request.on(:response) do |resp|
|
|
@@ -122,7 +138,7 @@ module WebMock
|
|
|
122
138
|
|
|
123
139
|
class << self
|
|
124
140
|
def enable!
|
|
125
|
-
@original_session
|
|
141
|
+
@original_session ||= HTTPX::Session
|
|
126
142
|
|
|
127
143
|
webmock_session = HTTPX.plugin(Plugin)
|
|
128
144
|
|
data/lib/httpx/altsvc.rb
CHANGED
|
@@ -4,7 +4,59 @@ require "strscan"
|
|
|
4
4
|
|
|
5
5
|
module HTTPX
|
|
6
6
|
module AltSvc
|
|
7
|
-
|
|
7
|
+
# makes connections able to accept requests destined to primary service.
|
|
8
|
+
module ConnectionMixin
|
|
9
|
+
using URIExtensions
|
|
10
|
+
|
|
11
|
+
def send(request)
|
|
12
|
+
request.headers["alt-used"] = @origin.authority if @parser && !@write_buffer.full? && match_altsvcs?(request.uri)
|
|
13
|
+
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def match?(uri, options)
|
|
18
|
+
return false if !used? && (@state == :closing || @state == :closed)
|
|
19
|
+
|
|
20
|
+
match_altsvcs?(uri) && match_altsvc_options?(uri, options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# checks if this is connection is an alternative service of
|
|
26
|
+
# +uri+
|
|
27
|
+
def match_altsvcs?(uri)
|
|
28
|
+
@origins.any? { |origin| altsvc_match?(uri, origin) } ||
|
|
29
|
+
AltSvc.cached_altsvc(@origin).any? do |altsvc|
|
|
30
|
+
origin = altsvc["origin"]
|
|
31
|
+
altsvc_match?(origin, uri.origin)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def match_altsvc_options?(uri, options)
|
|
36
|
+
return @options == options unless @options.ssl.all? do |k, v|
|
|
37
|
+
v == (k == :hostname ? uri.host : options.ssl[k])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
@options.options_equals?(options, Options::REQUEST_BODY_IVARS + %i[@ssl])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def altsvc_match?(uri, other_uri)
|
|
44
|
+
other_uri = URI(other_uri)
|
|
45
|
+
|
|
46
|
+
uri.origin == other_uri.origin || begin
|
|
47
|
+
case uri.scheme
|
|
48
|
+
when "h2"
|
|
49
|
+
(other_uri.scheme == "https" || other_uri.scheme == "h2") &&
|
|
50
|
+
uri.host == other_uri.host &&
|
|
51
|
+
uri.port == other_uri.port
|
|
52
|
+
else
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@altsvc_mutex = Thread::Mutex.new
|
|
8
60
|
@altsvcs = Hash.new { |h, k| h[k] = [] }
|
|
9
61
|
|
|
10
62
|
module_function
|
|
@@ -46,7 +98,7 @@ module HTTPX
|
|
|
46
98
|
|
|
47
99
|
altsvc = response.headers["alt-svc"]
|
|
48
100
|
|
|
49
|
-
# https://
|
|
101
|
+
# https://datatracker.ietf.org/doc/html/rfc7838#section-3
|
|
50
102
|
# A field value containing the special value "clear" indicates that the
|
|
51
103
|
# origin requests all alternatives for that origin to be invalidated
|
|
52
104
|
# (including those specified in the same response, in case of an
|
|
@@ -98,29 +150,14 @@ module HTTPX
|
|
|
98
150
|
end
|
|
99
151
|
end
|
|
100
152
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def parse_altsvc_origin(alt_proto, alt_origin)
|
|
104
|
-
alt_scheme = parse_altsvc_scheme(alt_proto) or return
|
|
105
|
-
|
|
106
|
-
alt_origin = alt_origin[1..-2] if alt_origin.start_with?("\"") && alt_origin.end_with?("\"")
|
|
107
|
-
if alt_origin.start_with?(":")
|
|
108
|
-
alt_origin = "#{alt_scheme}://dummy#{alt_origin}"
|
|
109
|
-
uri = URI.parse(alt_origin)
|
|
110
|
-
uri.host = nil
|
|
111
|
-
uri
|
|
112
|
-
else
|
|
113
|
-
URI.parse("#{alt_scheme}://#{alt_origin}")
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
else
|
|
117
|
-
def parse_altsvc_origin(alt_proto, alt_origin)
|
|
118
|
-
alt_scheme = parse_altsvc_scheme(alt_proto) or return
|
|
119
|
-
alt_origin = alt_origin[1..-2] if alt_origin.start_with?("\"") && alt_origin.end_with?("\"")
|
|
153
|
+
def parse_altsvc_origin(alt_proto, alt_origin)
|
|
154
|
+
alt_scheme = parse_altsvc_scheme(alt_proto)
|
|
120
155
|
|
|
121
|
-
|
|
122
|
-
|
|
156
|
+
return unless alt_scheme
|
|
157
|
+
|
|
158
|
+
alt_origin = alt_origin[1..-2] if alt_origin.start_with?("\"") && alt_origin.end_with?("\"")
|
|
159
|
+
|
|
160
|
+
URI.parse("#{alt_scheme}://#{alt_origin}")
|
|
123
161
|
end
|
|
124
|
-
# :nocov:
|
|
125
162
|
end
|
|
126
163
|
end
|
data/lib/httpx/base64.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
if RUBY_VERSION < "3.3.0"
|
|
4
|
+
require "base64"
|
|
5
|
+
elsif !defined?(Base64)
|
|
6
|
+
module HTTPX
|
|
7
|
+
# require "base64" will not be a default gem after ruby 3.4.0
|
|
8
|
+
module Base64
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def decode64(str)
|
|
12
|
+
str.unpack1("m")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def strict_encode64(bin)
|
|
16
|
+
[bin].pack("m0")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def urlsafe_encode64(bin, padding: true)
|
|
20
|
+
str = strict_encode64(bin)
|
|
21
|
+
str.chomp!("==") or str.chomp!("=") unless padding
|
|
22
|
+
str.tr!("+/", "-_")
|
|
23
|
+
str
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/httpx/buffer.rb
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
require "forwardable"
|
|
4
4
|
|
|
5
5
|
module HTTPX
|
|
6
|
+
# Internal class to abstract a string buffer, by wrapping a string and providing the
|
|
7
|
+
# minimum possible API and functionality required.
|
|
8
|
+
#
|
|
9
|
+
# buffer = Buffer.new(640)
|
|
10
|
+
# buffer.full? #=> false
|
|
11
|
+
# buffer << "aa"
|
|
12
|
+
# buffer.capacity #=> 638
|
|
13
|
+
#
|
|
6
14
|
class Buffer
|
|
7
15
|
extend Forwardable
|
|
8
16
|
|
|
@@ -31,6 +39,10 @@ module HTTPX
|
|
|
31
39
|
@buffer.bytesize >= @limit
|
|
32
40
|
end
|
|
33
41
|
|
|
42
|
+
def capacity
|
|
43
|
+
@limit - @buffer.bytesize
|
|
44
|
+
end
|
|
45
|
+
|
|
34
46
|
def shift!(fin)
|
|
35
47
|
@buffer = @buffer.byteslice(fin..-1) || "".b
|
|
36
48
|
end
|
data/lib/httpx/callbacks.rb
CHANGED
|
@@ -4,6 +4,7 @@ module HTTPX
|
|
|
4
4
|
module Callbacks
|
|
5
5
|
def on(type, &action)
|
|
6
6
|
callbacks(type) << action
|
|
7
|
+
self
|
|
7
8
|
end
|
|
8
9
|
|
|
9
10
|
def once(type, &block)
|
|
@@ -11,6 +12,7 @@ module HTTPX
|
|
|
11
12
|
block.call(*args, &callback)
|
|
12
13
|
:delete
|
|
13
14
|
end
|
|
15
|
+
self
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
def only(type, &block)
|
|
@@ -22,12 +24,12 @@ module HTTPX
|
|
|
22
24
|
callbacks(type).delete_if { |pr| :delete == pr.call(*args) } # rubocop:disable Style/YodaCondition
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
protected
|
|
26
|
-
|
|
27
27
|
def callbacks_for?(type)
|
|
28
|
-
@callbacks.key?(type) &&
|
|
28
|
+
@callbacks.key?(type) && @callbacks[type].any?
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
protected
|
|
32
|
+
|
|
31
33
|
def callbacks(type = nil)
|
|
32
34
|
return @callbacks unless type
|
|
33
35
|
|
data/lib/httpx/chainable.rb
CHANGED
|
@@ -1,89 +1,104 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module HTTPX
|
|
4
|
+
# Session mixin, implements most of the APIs that the users call.
|
|
5
|
+
# delegates to a default session when extended.
|
|
4
6
|
module Chainable
|
|
5
|
-
%
|
|
7
|
+
%w[head get post put delete trace options connect patch].each do |meth|
|
|
6
8
|
class_eval(<<-MOD, __FILE__, __LINE__ + 1)
|
|
7
|
-
def #{meth}(*uri, **options)
|
|
8
|
-
request(
|
|
9
|
-
end
|
|
9
|
+
def #{meth}(*uri, **options) # def get(*uri, **options)
|
|
10
|
+
request("#{meth.upcase}", uri, **options) # request("GET", uri, **options)
|
|
11
|
+
end # end
|
|
10
12
|
MOD
|
|
11
13
|
end
|
|
12
14
|
|
|
15
|
+
# delegates to the default session (see HTTPX::Session#request).
|
|
13
16
|
def request(*args, **options)
|
|
14
17
|
branch(default_options).request(*args, **options)
|
|
15
18
|
end
|
|
16
19
|
|
|
17
|
-
# :nocov:
|
|
18
|
-
def timeout(**args)
|
|
19
|
-
warn ":#{__method__} is deprecated, use :with_timeout instead"
|
|
20
|
-
with(timeout: args)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def headers(headers)
|
|
24
|
-
warn ":#{__method__} is deprecated, use :with_headers instead"
|
|
25
|
-
with(headers: headers)
|
|
26
|
-
end
|
|
27
|
-
# :nocov:
|
|
28
|
-
|
|
29
20
|
def accept(type)
|
|
30
21
|
with(headers: { "accept" => String(type) })
|
|
31
22
|
end
|
|
32
23
|
|
|
24
|
+
# delegates to the default session (see HTTPX::Session#wrap).
|
|
33
25
|
def wrap(&blk)
|
|
34
26
|
branch(default_options).wrap(&blk)
|
|
35
27
|
end
|
|
36
28
|
|
|
29
|
+
# returns a new instance loaded with the +pl+ plugin and +options+.
|
|
37
30
|
def plugin(pl, options = nil, &blk)
|
|
38
|
-
klass = is_a?(
|
|
31
|
+
klass = is_a?(S) ? self.class : Session
|
|
39
32
|
klass = Class.new(klass)
|
|
40
33
|
klass.instance_variable_set(:@default_options, klass.default_options.merge(default_options))
|
|
41
34
|
klass.plugin(pl, options, &blk).new
|
|
42
35
|
end
|
|
43
36
|
|
|
44
|
-
#
|
|
45
|
-
# :nocov:
|
|
46
|
-
def plugins(pls)
|
|
47
|
-
warn ":#{__method__} is deprecated, use :plugin instead"
|
|
48
|
-
klass = is_a?(Session) ? self.class : Session
|
|
49
|
-
klass = Class.new(klass)
|
|
50
|
-
klass.instance_variable_set(:@default_options, klass.default_options.merge(default_options))
|
|
51
|
-
klass.plugins(pls).new
|
|
52
|
-
end
|
|
53
|
-
# :nocov:
|
|
54
|
-
|
|
37
|
+
# returns a new instance loaded with +options+.
|
|
55
38
|
def with(options, &blk)
|
|
56
39
|
branch(default_options.merge(options), &blk)
|
|
57
40
|
end
|
|
58
41
|
|
|
59
42
|
private
|
|
60
43
|
|
|
44
|
+
# returns default instance of HTTPX::Options.
|
|
61
45
|
def default_options
|
|
62
46
|
@options || Session.default_options
|
|
63
47
|
end
|
|
64
48
|
|
|
49
|
+
# returns a default instance of HTTPX::Session.
|
|
65
50
|
def branch(options, &blk)
|
|
66
|
-
return self.class.new(options, &blk) if is_a?(
|
|
51
|
+
return self.class.new(options, &blk) if is_a?(S)
|
|
67
52
|
|
|
68
53
|
Session.new(options, &blk)
|
|
69
54
|
end
|
|
70
55
|
|
|
71
|
-
def method_missing(meth, *args, **options)
|
|
72
|
-
|
|
56
|
+
def method_missing(meth, *args, **options, &blk)
|
|
57
|
+
case meth
|
|
58
|
+
when /\Awith_(.+)/
|
|
73
59
|
|
|
74
|
-
|
|
60
|
+
option = Regexp.last_match(1)
|
|
75
61
|
|
|
76
|
-
|
|
62
|
+
return super unless option
|
|
77
63
|
|
|
78
|
-
|
|
79
|
-
|
|
64
|
+
with(option.to_sym => args.first || options)
|
|
65
|
+
when /\Aon_(.+)/
|
|
66
|
+
callback = Regexp.last_match(1)
|
|
80
67
|
|
|
81
|
-
|
|
82
|
-
|
|
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)
|
|
83
74
|
|
|
84
|
-
|
|
75
|
+
warn "DEPRECATION WARNING: calling `.#{meth}` on plain HTTPX sessions is deprecated. " \
|
|
76
|
+
"Use HTTPX.plugin(:callbacks).#{meth} instead."
|
|
85
77
|
|
|
86
|
-
|
|
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
|
|
87
102
|
end
|
|
88
103
|
end
|
|
89
104
|
end
|