httpx 0.23.4 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/doc/release_notes/0_24_0.md +48 -0
- data/doc/release_notes/0_24_1.md +12 -0
- data/lib/httpx/adapters/datadog.rb +22 -1
- data/lib/httpx/callbacks.rb +2 -0
- data/lib/httpx/chainable.rb +19 -0
- data/lib/httpx/connection/http1.rb +21 -8
- data/lib/httpx/connection/http2.rb +1 -0
- data/lib/httpx/domain_name.rb +1 -1
- data/lib/httpx/io/tcp.rb +4 -1
- data/lib/httpx/plugins/authentication/digest.rb +2 -3
- data/lib/httpx/plugins/circuit_breaker.rb +16 -2
- data/lib/httpx/plugins/digest_authentication.rb +1 -1
- data/lib/httpx/plugins/oauth.rb +170 -0
- data/lib/httpx/plugins/proxy/http.rb +6 -0
- data/lib/httpx/plugins/proxy/socks4.rb +6 -0
- data/lib/httpx/plugins/proxy/socks5.rb +8 -2
- data/lib/httpx/plugins/proxy.rb +26 -9
- data/lib/httpx/plugins/response_cache/file_store.rb +39 -34
- data/lib/httpx/plugins/response_cache/store.rb +35 -16
- data/lib/httpx/plugins/response_cache.rb +3 -3
- data/lib/httpx/request.rb +6 -2
- data/lib/httpx/resolver/multi.rb +1 -1
- data/lib/httpx/resolver/resolver.rb +4 -4
- data/lib/httpx/response.rb +12 -1
- data/lib/httpx/session.rb +36 -0
- data/lib/httpx/session_extensions.rb +4 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/callbacks.rbs +3 -3
- data/sig/chainable.rbs +1 -0
- data/sig/plugins/circuit_breaker.rbs +6 -2
- data/sig/plugins/oauth.rbs +54 -0
- data/sig/plugins/response_cache.rbs +5 -1
- data/sig/resolver/resolver.rbs +1 -1
- data/sig/response.rbs +1 -0
- data/sig/session.rbs +7 -5
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 588deec0af9ead32480f7cca9ce8c278b344ccdd2e608cc2a6a8db8c6135647f
|
4
|
+
data.tar.gz: 3b69af49050cd6ba7b0317ddcd2286cbe6a2261add9fd0b9839bb89290e3962a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e630447fb6bc2aabb6efd842fdd322734e78e7859ea03126ab3d45cf4580d91ede945aa4e77700ae6cbe92179cc0a7e96fdc294ccaf729b287c4b4269b9b40b8
|
7
|
+
data.tar.gz: 138310fead4041c202f32b3e53564023472383f5cc251c59cc88b115c8f2947801da8269518d3dce48ff8b53abe3b1350d92b553a9264be8ab052064a135b605
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# 0.24.0
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### `:oauth` plugin
|
6
|
+
|
7
|
+
The `:oauth` plugin manages the handling of a given OAuth session, in that it ships with convenience methods to generate a new access token, which it then injects in all requests.
|
8
|
+
|
9
|
+
More info under https://honeyryderchuck.gitlab.io/httpx/wiki/OAuth
|
10
|
+
|
11
|
+
### session callbacks
|
12
|
+
|
13
|
+
HTTP request/response lifecycle events have now the ability of being intercepted via public API callback methods:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
HTTPX.on_request_completed do |request|
|
17
|
+
puts "request to #{request.uri} sent"
|
18
|
+
end.get(...)
|
19
|
+
```
|
20
|
+
|
21
|
+
More info under https://honeyryderchuck.gitlab.io/httpx/wiki/Events to know which events and callback methods are supported.
|
22
|
+
|
23
|
+
### `:circuit_breaker` plugin `on_circuit_open` callback
|
24
|
+
|
25
|
+
A callback has been introduced for the `:circuit_breaker` plugin, which is triggered when a circuit is opened.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
http = HTTPX.plugin(:circuit_breaker).on_circuit_open do |req|
|
29
|
+
puts "circuit opened for #{req.uri}"
|
30
|
+
end
|
31
|
+
http.get(...)
|
32
|
+
```
|
33
|
+
|
34
|
+
## Improvements
|
35
|
+
|
36
|
+
Several `:response_cache` features have been improved:
|
37
|
+
|
38
|
+
* `:response_cache` plugin: response cache store has been made thread-safe.
|
39
|
+
* cached response sharing across threads is made safer, as stringio/tempfile instances are copied instead of shared (without copying the underling string/file).
|
40
|
+
* stale cached responses are eliminate on cache store lookup/store operations.
|
41
|
+
* already closed responses are evicted from the cache store.
|
42
|
+
* fallback for lack of compatible response "date" header has been fixed to return a `Time` object.
|
43
|
+
|
44
|
+
## Bugfixes
|
45
|
+
|
46
|
+
* Ability to recover from errors happening during response chunk processing (required for overriding behaviour and response chunk callbacks); error bubbling up will result in the connection being closed.
|
47
|
+
* Happy eyeballs support for multi-homed early-resolved domain names (such as `localhost` under `/etc/hosts`) was broken, as it would try the first given IP; so, if given `::1` and connection would fail, it wouldn't try `127.0.0.1`, which would have succeeded.
|
48
|
+
* `:digest_authentication` plugin was removing the "algorithm" header on `-sess` declared algorithms, which is required for HTTP digest auth negotiation.
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# 0.24.1
|
2
|
+
|
3
|
+
## Improvements
|
4
|
+
|
5
|
+
* datadog adapter: support `:service_name` configuration option.
|
6
|
+
* datadog adapter: set `:distributed_tracing` to `true` by default.
|
7
|
+
* `:proxy` plugin: when the proxy uri uses an unsupported scheme (i.e.: "scp://125.24.2.1"), a more user friendly error is raised (instead of the previous broken stacktrace).
|
8
|
+
|
9
|
+
## Bugfixes
|
10
|
+
|
11
|
+
* datadog adapter: fix tracing enable call, which was wrongly calling `super`.
|
12
|
+
+ `:proxy` plugin: fix for bug which was turning off plugins overriding `HTTPX::Connection#send` (such as the datadog adapter).
|
@@ -160,7 +160,7 @@ module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
|
|
160
160
|
|
161
161
|
module RequestMethods
|
162
162
|
def __datadog_enable_trace!
|
163
|
-
return
|
163
|
+
return if @__datadog_enable_trace
|
164
164
|
|
165
165
|
RequestTracer.new(self).call
|
166
166
|
@__datadog_enable_trace = true
|
@@ -203,6 +203,27 @@ module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
|
|
203
203
|
o.lazy
|
204
204
|
end
|
205
205
|
|
206
|
+
if defined?(TRACING_MODULE::Contrib::SpanAttributeSchema)
|
207
|
+
option :service_name do |o|
|
208
|
+
o.default do
|
209
|
+
TRACING_MODULE::Contrib::SpanAttributeSchema.fetch_service_name(
|
210
|
+
"DD_TRACE_HTTPX_SERVICE_NAME",
|
211
|
+
"httpx"
|
212
|
+
)
|
213
|
+
end
|
214
|
+
o.lazy
|
215
|
+
end
|
216
|
+
else
|
217
|
+
option :service_name do |o|
|
218
|
+
o.default do
|
219
|
+
ENV.fetch("DD_TRACE_HTTPX_SERVICE_NAME", "httpx")
|
220
|
+
end
|
221
|
+
o.lazy
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
option :distributed_tracing, default: true
|
226
|
+
|
206
227
|
option :error_handler, default: DEFAULT_ERROR_HANDLER
|
207
228
|
end
|
208
229
|
end
|
data/lib/httpx/callbacks.rb
CHANGED
data/lib/httpx/chainable.rb
CHANGED
@@ -10,6 +10,19 @@ module HTTPX
|
|
10
10
|
MOD
|
11
11
|
end
|
12
12
|
|
13
|
+
%i[
|
14
|
+
connection_opened connection_closed
|
15
|
+
request_error
|
16
|
+
request_started request_body_chunk request_completed
|
17
|
+
response_started response_body_chunk response_completed
|
18
|
+
].each do |meth|
|
19
|
+
class_eval(<<-MOD, __FILE__, __LINE__ + 1)
|
20
|
+
def on_#{meth}(&blk) # def on_connection_opened(&blk)
|
21
|
+
on(:#{meth}, &blk) # on(:connection_opened, &blk)
|
22
|
+
end # end
|
23
|
+
MOD
|
24
|
+
end
|
25
|
+
|
13
26
|
def request(*args, **options)
|
14
27
|
branch(default_options).request(*args, **options)
|
15
28
|
end
|
@@ -56,6 +69,12 @@ module HTTPX
|
|
56
69
|
branch(default_options.merge(options), &blk)
|
57
70
|
end
|
58
71
|
|
72
|
+
protected
|
73
|
+
|
74
|
+
def on(*args, &blk)
|
75
|
+
branch(default_options).on(*args, &blk)
|
76
|
+
end
|
77
|
+
|
59
78
|
private
|
60
79
|
|
61
80
|
def default_options
|
@@ -133,33 +133,42 @@ module HTTPX
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def on_data(chunk)
|
136
|
-
|
136
|
+
request = @request
|
137
|
+
|
138
|
+
return unless request
|
137
139
|
|
138
140
|
log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
|
139
141
|
log(level: 2, color: :green) { "-> #{chunk.inspect}" }
|
140
|
-
response =
|
142
|
+
response = request.response
|
141
143
|
|
142
144
|
response << chunk
|
145
|
+
rescue StandardError => e
|
146
|
+
error_response = ErrorResponse.new(request, e, request.options)
|
147
|
+
request.response = error_response
|
148
|
+
dispatch
|
143
149
|
end
|
144
150
|
|
145
151
|
def on_complete
|
146
|
-
|
152
|
+
request = @request
|
153
|
+
|
154
|
+
return unless request
|
147
155
|
|
148
156
|
log(level: 2) { "parsing complete" }
|
149
157
|
dispatch
|
150
158
|
end
|
151
159
|
|
152
160
|
def dispatch
|
153
|
-
|
161
|
+
request = @request
|
162
|
+
|
163
|
+
if request.expects?
|
154
164
|
@parser.reset!
|
155
|
-
return handle(
|
165
|
+
return handle(request)
|
156
166
|
end
|
157
167
|
|
158
|
-
request = @request
|
159
168
|
@request = nil
|
160
169
|
@requests.shift
|
161
170
|
response = request.response
|
162
|
-
response.finish!
|
171
|
+
response.finish! unless response.is_a?(ErrorResponse)
|
163
172
|
emit(:response, request, response)
|
164
173
|
|
165
174
|
if @parser.upgrade?
|
@@ -169,7 +178,11 @@ module HTTPX
|
|
169
178
|
|
170
179
|
@parser.reset!
|
171
180
|
@max_requests -= 1
|
172
|
-
|
181
|
+
if response.is_a?(ErrorResponse)
|
182
|
+
disable
|
183
|
+
else
|
184
|
+
manage_connection(response)
|
185
|
+
end
|
173
186
|
|
174
187
|
send(@pending.shift) unless @pending.empty?
|
175
188
|
end
|
data/lib/httpx/domain_name.rb
CHANGED
@@ -63,7 +63,7 @@ module HTTPX
|
|
63
63
|
# Normalizes a _domain_ using the Punycode algorithm as necessary.
|
64
64
|
# The result will be a downcased, ASCII-only string.
|
65
65
|
def normalize(domain)
|
66
|
-
domain = domain.
|
66
|
+
domain = domain.chomp(DOT).unicode_normalize(:nfc) unless domain.ascii_only?
|
67
67
|
Punycode.encode_hostname(domain).downcase
|
68
68
|
end
|
69
69
|
end
|
data/lib/httpx/io/tcp.rb
CHANGED
@@ -45,7 +45,6 @@ module HTTPX
|
|
45
45
|
raise DigestError, "unknown algorithm \"#{alg}\"" unless algorithm
|
46
46
|
|
47
47
|
sess = Regexp.last_match(2)
|
48
|
-
params.delete("algorithm")
|
49
48
|
else
|
50
49
|
algorithm = ::Digest::MD5
|
51
50
|
end
|
@@ -77,11 +76,11 @@ module HTTPX
|
|
77
76
|
%(response="#{algorithm.hexdigest(request_digest)}"),
|
78
77
|
]
|
79
78
|
header << %(realm="#{params["realm"]}") if params.key?("realm")
|
80
|
-
header << %(algorithm=#{params["algorithm"]}
|
81
|
-
header << %(opaque="#{params["opaque"]}") if params.key?("opaque")
|
79
|
+
header << %(algorithm=#{params["algorithm"]}) if params.key?("algorithm")
|
82
80
|
header << %(cnonce="#{cnonce}") if cnonce
|
83
81
|
header << %(nc=#{nc})
|
84
82
|
header << %(qop=#{qop}) if qop
|
83
|
+
header << %(opaque="#{params["opaque"]}") if params.key?("opaque")
|
85
84
|
header.join ", "
|
86
85
|
end
|
87
86
|
|
@@ -31,6 +31,16 @@ module HTTPX
|
|
31
31
|
@circuit_store = orig.instance_variable_get(:@circuit_store).dup
|
32
32
|
end
|
33
33
|
|
34
|
+
%i[circuit_open].each do |meth|
|
35
|
+
class_eval(<<-MOD, __FILE__, __LINE__ + 1)
|
36
|
+
def on_#{meth}(&blk) # def on_circuit_open(&blk)
|
37
|
+
on(:#{meth}, &blk) # on(:circuit_open, &blk)
|
38
|
+
end # end
|
39
|
+
MOD
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
34
44
|
def send_requests(*requests)
|
35
45
|
# @type var short_circuit_responses: Array[response]
|
36
46
|
short_circuit_responses = []
|
@@ -59,6 +69,12 @@ module HTTPX
|
|
59
69
|
end
|
60
70
|
|
61
71
|
def on_response(request, response)
|
72
|
+
emit(:circuit_open, request) if try_circuit_open(request, response)
|
73
|
+
|
74
|
+
super
|
75
|
+
end
|
76
|
+
|
77
|
+
def try_circuit_open(request, response)
|
62
78
|
if response.is_a?(ErrorResponse)
|
63
79
|
case response.error
|
64
80
|
when RequestTimeoutError
|
@@ -69,8 +85,6 @@ module HTTPX
|
|
69
85
|
elsif (break_on = request.options.circuit_breaker_break_on) && break_on.call(response)
|
70
86
|
@circuit_store.try_open(request.uri, response)
|
71
87
|
end
|
72
|
-
|
73
|
-
super
|
74
88
|
end
|
75
89
|
end
|
76
90
|
|
@@ -22,7 +22,7 @@ module HTTPX
|
|
22
22
|
|
23
23
|
module OptionsMethods
|
24
24
|
def option_digest(value)
|
25
|
-
raise TypeError, ":digest must be a Digest" unless value.is_a?(Authentication::Digest)
|
25
|
+
raise TypeError, ":digest must be a #{Authentication::Digest}" unless value.is_a?(Authentication::Digest)
|
26
26
|
|
27
27
|
value
|
28
28
|
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTPX
|
4
|
+
module Plugins
|
5
|
+
#
|
6
|
+
# https://gitlab.com/os85/httpx/wikis/OAuth
|
7
|
+
#
|
8
|
+
module OAuth
|
9
|
+
class << self
|
10
|
+
def load_dependencies(_klass)
|
11
|
+
require_relative "authentication/basic"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
SUPPORTED_GRANT_TYPES = %w[client_credentials refresh_token].freeze
|
16
|
+
SUPPORTED_AUTH_METHODS = %w[client_secret_basic client_secret_post].freeze
|
17
|
+
|
18
|
+
class OAuthSession
|
19
|
+
attr_reader :token_endpoint_auth_method, :grant_type, :client_id, :client_secret, :access_token, :refresh_token, :scope
|
20
|
+
|
21
|
+
def initialize(
|
22
|
+
issuer:,
|
23
|
+
client_id:,
|
24
|
+
client_secret:,
|
25
|
+
access_token: nil,
|
26
|
+
refresh_token: nil,
|
27
|
+
scope: nil,
|
28
|
+
token_endpoint: nil,
|
29
|
+
response_type: nil,
|
30
|
+
grant_type: nil,
|
31
|
+
token_endpoint_auth_method: "client_secret_basic"
|
32
|
+
)
|
33
|
+
@issuer = URI(issuer)
|
34
|
+
@client_id = client_id
|
35
|
+
@client_secret = client_secret
|
36
|
+
@token_endpoint = URI(token_endpoint) if token_endpoint
|
37
|
+
@response_type = response_type
|
38
|
+
@scope = case scope
|
39
|
+
when String
|
40
|
+
scope.split
|
41
|
+
when Array
|
42
|
+
scope
|
43
|
+
end
|
44
|
+
@access_token = access_token
|
45
|
+
@refresh_token = refresh_token
|
46
|
+
@token_endpoint_auth_method = String(token_endpoint_auth_method)
|
47
|
+
@grant_type = grant_type || (@refresh_token ? "refresh_token" : "client_credentials")
|
48
|
+
|
49
|
+
unless SUPPORTED_AUTH_METHODS.include?(@token_endpoint_auth_method)
|
50
|
+
raise Error, "#{@token_endpoint_auth_method} is not a supported auth method"
|
51
|
+
end
|
52
|
+
|
53
|
+
return if SUPPORTED_GRANT_TYPES.include?(@grant_type)
|
54
|
+
|
55
|
+
raise Error, "#{@grant_type} is not a supported grant type"
|
56
|
+
end
|
57
|
+
|
58
|
+
def token_endpoint
|
59
|
+
@token_endpoint || "#{@issuer}/token"
|
60
|
+
end
|
61
|
+
|
62
|
+
def load(http)
|
63
|
+
return unless @token_endpoint && @token_endpoint_auth_method && @grant_type && @scope
|
64
|
+
|
65
|
+
metadata = http.get("#{issuer}/.well-known/oauth-authorization-server").raise_for_status.json
|
66
|
+
|
67
|
+
@token_endpoint = metadata["token_endpoint"]
|
68
|
+
@scope = metadata["scopes_supported"]
|
69
|
+
@grant_type = Array(metadata["grant_types_supported"]).find { |gr| SUPPORTED_GRANT_TYPES.include?(gr) }
|
70
|
+
@token_endpoint_auth_method = Array(metadata["token_endpoint_auth_methods_supported"]).find do |am|
|
71
|
+
SUPPORTED_AUTH_METHODS.include?(am)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def merge(other)
|
76
|
+
obj = dup
|
77
|
+
|
78
|
+
case other
|
79
|
+
when OAuthSession
|
80
|
+
other.instance_variables.each do |ivar|
|
81
|
+
val = other.instance_variable_get(ivar)
|
82
|
+
next unless val
|
83
|
+
|
84
|
+
obj.instance_variable_set(ivar, val)
|
85
|
+
end
|
86
|
+
when Hash
|
87
|
+
other.each do |k, v|
|
88
|
+
obj.instance_variable_set(:"@#{k}", v) if obj.instance_variable_defined?(:"@#{k}")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
obj
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
module OptionsMethods
|
96
|
+
def option_oauth_session(value)
|
97
|
+
case value
|
98
|
+
when Hash
|
99
|
+
OAuthSession.new(**value)
|
100
|
+
when OAuthSession
|
101
|
+
value
|
102
|
+
else
|
103
|
+
raise TypeError, ":oauth_session must be a #{OAuthSession}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
module InstanceMethods
|
109
|
+
def oauth_authentication(**args)
|
110
|
+
with(oauth_session: OAuthSession.new(**args))
|
111
|
+
end
|
112
|
+
|
113
|
+
def with_access_token
|
114
|
+
oauth_session = @options.oauth_session
|
115
|
+
|
116
|
+
oauth_session.load(self)
|
117
|
+
|
118
|
+
grant_type = oauth_session.grant_type
|
119
|
+
|
120
|
+
headers = {}
|
121
|
+
form_post = { "grant_type" => grant_type, "scope" => Array(oauth_session.scope).join(" ") }.compact
|
122
|
+
|
123
|
+
# auth
|
124
|
+
case oauth_session.token_endpoint_auth_method
|
125
|
+
when "client_secret_basic"
|
126
|
+
headers["authorization"] = Authentication::Basic.new(oauth_session.client_id, oauth_session.client_secret).authenticate
|
127
|
+
when "client_secret_post"
|
128
|
+
form_post["client_id"] = oauth_session.client_id
|
129
|
+
form_post["client_secret"] = oauth_session.client_secret
|
130
|
+
end
|
131
|
+
|
132
|
+
case grant_type
|
133
|
+
when "client_credentials"
|
134
|
+
# do nothing
|
135
|
+
when "refresh_token"
|
136
|
+
form_post["refresh_token"] = oauth_session.refresh_token
|
137
|
+
end
|
138
|
+
|
139
|
+
token_request = build_request("POST", oauth_session.token_endpoint, headers: headers, form: form_post)
|
140
|
+
token_request.headers.delete("authorization") unless oauth_session.token_endpoint_auth_method == "client_secret_basic"
|
141
|
+
|
142
|
+
token_response = request(token_request)
|
143
|
+
token_response.raise_for_status
|
144
|
+
|
145
|
+
payload = token_response.json
|
146
|
+
|
147
|
+
access_token = payload["access_token"]
|
148
|
+
refresh_token = payload["refresh_token"]
|
149
|
+
|
150
|
+
with(oauth_session: oauth_session.merge(access_token: access_token, refresh_token: refresh_token))
|
151
|
+
end
|
152
|
+
|
153
|
+
def build_request(*, _)
|
154
|
+
request = super
|
155
|
+
|
156
|
+
return request if request.headers.key?("authorization")
|
157
|
+
|
158
|
+
oauth_session = @options.oauth_session
|
159
|
+
|
160
|
+
return request unless oauth_session && oauth_session.access_token
|
161
|
+
|
162
|
+
request.headers["authorization"] = "Bearer #{oauth_session.access_token}"
|
163
|
+
|
164
|
+
request
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
register_plugin :oauth, OAuth
|
169
|
+
end
|
170
|
+
end
|
@@ -6,6 +6,12 @@ module HTTPX
|
|
6
6
|
module Plugins
|
7
7
|
module Proxy
|
8
8
|
module HTTP
|
9
|
+
class << self
|
10
|
+
def extra_options(options)
|
11
|
+
options.merge(supported_proxy_protocols: options.supported_proxy_protocols + %w[http])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
9
15
|
module InstanceMethods
|
10
16
|
def with_proxy_basic_auth(opts)
|
11
17
|
with(proxy: opts.merge(scheme: "basic"))
|
@@ -16,6 +16,12 @@ module HTTPX
|
|
16
16
|
|
17
17
|
Error = Socks4Error
|
18
18
|
|
19
|
+
class << self
|
20
|
+
def extra_options(options)
|
21
|
+
options.merge(supported_proxy_protocols: options.supported_proxy_protocols + PROTOCOLS)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
19
25
|
module ConnectionMethods
|
20
26
|
def interests
|
21
27
|
if @state == :connecting
|
@@ -18,8 +18,14 @@ module HTTPX
|
|
18
18
|
|
19
19
|
Error = Socks5Error
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
class << self
|
22
|
+
def load_dependencies(*)
|
23
|
+
require_relative "../authentication/socks5"
|
24
|
+
end
|
25
|
+
|
26
|
+
def extra_options(options)
|
27
|
+
options.merge(supported_proxy_protocols: options.supported_proxy_protocols + %w[socks5])
|
28
|
+
end
|
23
29
|
end
|
24
30
|
|
25
31
|
module ConnectionMethods
|
data/lib/httpx/plugins/proxy.rb
CHANGED
@@ -25,6 +25,10 @@ module HTTPX
|
|
25
25
|
klass.plugin(:"proxy/socks5")
|
26
26
|
end
|
27
27
|
|
28
|
+
def extra_options(options)
|
29
|
+
options.merge(supported_proxy_protocols: [])
|
30
|
+
end
|
31
|
+
|
28
32
|
if URI::Generic.methods.include?(:use_proxy?)
|
29
33
|
def use_proxy?(*args)
|
30
34
|
URI::Generic.use_proxy?(*args)
|
@@ -118,6 +122,12 @@ module HTTPX
|
|
118
122
|
def option_proxy(value)
|
119
123
|
value.is_a?(Parameters) ? value : Hash[value]
|
120
124
|
end
|
125
|
+
|
126
|
+
def option_supported_proxy_protocols(value)
|
127
|
+
raise TypeError, ":supported_proxy_protocols must be an Array" unless value.is_a?(Array)
|
128
|
+
|
129
|
+
value.map(&:to_s)
|
130
|
+
end
|
121
131
|
end
|
122
132
|
|
123
133
|
module InstanceMethods
|
@@ -142,8 +152,12 @@ module HTTPX
|
|
142
152
|
next_proxy = @_proxy_uris.first
|
143
153
|
raise Error, "Failed to connect to proxy" unless next_proxy
|
144
154
|
|
155
|
+
next_proxy = URI(next_proxy)
|
156
|
+
|
157
|
+
raise Error,
|
158
|
+
"#{next_proxy.scheme}: unsupported proxy protocol" unless options.supported_proxy_protocols.include?(next_proxy.scheme)
|
159
|
+
|
145
160
|
if proxy.key?(:no_proxy)
|
146
|
-
next_proxy = URI(next_proxy)
|
147
161
|
|
148
162
|
no_proxy = proxy[:no_proxy]
|
149
163
|
no_proxy = no_proxy.join(",") if no_proxy.is_a?(Array)
|
@@ -170,11 +184,7 @@ module HTTPX
|
|
170
184
|
proxy = options.proxy
|
171
185
|
return super unless proxy
|
172
186
|
|
173
|
-
|
174
|
-
catch(:coalesced) do
|
175
|
-
pool.init_connection(connection, options)
|
176
|
-
connection
|
177
|
-
end
|
187
|
+
init_connection("tcp", uri, options)
|
178
188
|
end
|
179
189
|
|
180
190
|
def fetch_response(request, connections, options)
|
@@ -257,10 +267,11 @@ module HTTPX
|
|
257
267
|
end
|
258
268
|
|
259
269
|
def send(request)
|
260
|
-
return super unless
|
261
|
-
|
270
|
+
return super unless (
|
271
|
+
@options.proxy && @state != :idle && connecting?
|
272
|
+
)
|
262
273
|
|
263
|
-
@
|
274
|
+
(@proxy_pending ||= []) << request
|
264
275
|
end
|
265
276
|
|
266
277
|
def connecting?
|
@@ -298,6 +309,12 @@ module HTTPX
|
|
298
309
|
when :idle
|
299
310
|
transition(:connecting)
|
300
311
|
when :connected
|
312
|
+
if @proxy_pending
|
313
|
+
while (req = @proxy_pendind.shift)
|
314
|
+
send(req)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
301
318
|
transition(:open)
|
302
319
|
end
|
303
320
|
end
|
@@ -1,34 +1,39 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
module HTTPX::Plugins
|
6
|
+
module ResponseCache
|
7
|
+
class FileStore < Store
|
8
|
+
def initialize(dir = Dir.tmpdir)
|
9
|
+
@dir = Pathname.new(dir)
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear
|
13
|
+
# delete all files
|
14
|
+
end
|
15
|
+
|
16
|
+
def cached?(request)
|
17
|
+
file_path = @dir.join(request.response_cache_key)
|
18
|
+
|
19
|
+
exist?(file_path)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def _get(request)
|
25
|
+
return unless cached?(request)
|
26
|
+
|
27
|
+
File.open(@dir.join(request.response_cache_key))
|
28
|
+
end
|
29
|
+
|
30
|
+
def _set(request, response)
|
31
|
+
file_path = @dir.join(request.response_cache_key)
|
32
|
+
|
33
|
+
response.copy_to(file_path)
|
34
|
+
|
35
|
+
response.body.rewind
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,28 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "mutex_m"
|
4
4
|
|
5
5
|
module HTTPX::Plugins
|
6
6
|
module ResponseCache
|
7
7
|
class Store
|
8
|
-
extend Forwardable
|
9
|
-
|
10
|
-
def_delegator :@store, :clear
|
11
|
-
|
12
8
|
def initialize
|
13
9
|
@store = {}
|
10
|
+
@store.extend(Mutex_m)
|
11
|
+
end
|
12
|
+
|
13
|
+
def clear
|
14
|
+
@store.synchronize { @store.clear }
|
14
15
|
end
|
15
16
|
|
16
17
|
def lookup(request)
|
17
|
-
responses =
|
18
|
+
responses = _get(request)
|
18
19
|
|
19
20
|
return unless responses
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
return unless response && response.fresh?
|
24
|
-
|
25
|
-
response
|
22
|
+
responses.find(&method(:match_by_vary?).curry(2)[request])
|
26
23
|
end
|
27
24
|
|
28
25
|
def cached?(request)
|
@@ -32,11 +29,7 @@ module HTTPX::Plugins
|
|
32
29
|
def cache(request, response)
|
33
30
|
return unless ResponseCache.cacheable_request?(request) && ResponseCache.cacheable_response?(response)
|
34
31
|
|
35
|
-
|
36
|
-
|
37
|
-
responses.reject!(&method(:match_by_vary?).curry(2)[request])
|
38
|
-
|
39
|
-
responses << response
|
32
|
+
_set(request, response)
|
40
33
|
end
|
41
34
|
|
42
35
|
def prepare(request)
|
@@ -71,6 +64,32 @@ module HTTPX::Plugins
|
|
71
64
|
!original_request.headers.key?(cache_field) || request.headers[cache_field] == original_request.headers[cache_field]
|
72
65
|
end
|
73
66
|
end
|
67
|
+
|
68
|
+
def _get(request)
|
69
|
+
@store.synchronize do
|
70
|
+
responses = @store[request.response_cache_key]
|
71
|
+
|
72
|
+
return unless responses
|
73
|
+
|
74
|
+
responses.select! do |res|
|
75
|
+
!res.body.closed? && res.fresh?
|
76
|
+
end
|
77
|
+
|
78
|
+
responses
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def _set(request, response)
|
83
|
+
@store.synchronize do
|
84
|
+
responses = (@store[request.response_cache_key] ||= [])
|
85
|
+
|
86
|
+
responses.reject! do |res|
|
87
|
+
res.body.closed? || !res.fresh? || match_by_vary?(request, res)
|
88
|
+
end
|
89
|
+
|
90
|
+
responses << response
|
91
|
+
end
|
92
|
+
end
|
74
93
|
end
|
75
94
|
end
|
76
95
|
end
|
@@ -102,9 +102,9 @@ module HTTPX
|
|
102
102
|
|
103
103
|
module ResponseMethods
|
104
104
|
def copy_from_cached(other)
|
105
|
-
@body = other.body
|
105
|
+
@body = other.body.dup
|
106
106
|
|
107
|
-
@body.
|
107
|
+
@body.rewind
|
108
108
|
end
|
109
109
|
|
110
110
|
# A response is fresh if its age has not yet exceeded its freshness lifetime.
|
@@ -169,7 +169,7 @@ module HTTPX
|
|
169
169
|
def date
|
170
170
|
@date ||= Time.httpdate(@headers["date"])
|
171
171
|
rescue NoMethodError, ArgumentError
|
172
|
-
Time.now
|
172
|
+
Time.now
|
173
173
|
end
|
174
174
|
end
|
175
175
|
end
|
data/lib/httpx/request.rb
CHANGED
@@ -95,6 +95,8 @@ module HTTPX
|
|
95
95
|
return
|
96
96
|
end
|
97
97
|
@response = response
|
98
|
+
|
99
|
+
emit(:response_started, response)
|
98
100
|
end
|
99
101
|
|
100
102
|
def path
|
@@ -130,8 +132,10 @@ module HTTPX
|
|
130
132
|
return nil if @body.nil?
|
131
133
|
|
132
134
|
@drainer ||= @body.each
|
133
|
-
chunk = @drainer.next
|
134
|
-
|
135
|
+
chunk = @drainer.next.dup
|
136
|
+
|
137
|
+
emit(:body_chunk, chunk)
|
138
|
+
chunk
|
135
139
|
rescue StopIteration
|
136
140
|
nil
|
137
141
|
rescue StandardError => e
|
data/lib/httpx/resolver/multi.rb
CHANGED
@@ -46,13 +46,13 @@ module HTTPX
|
|
46
46
|
true
|
47
47
|
end
|
48
48
|
|
49
|
-
def emit_addresses(connection, family, addresses)
|
49
|
+
def emit_addresses(connection, family, addresses, early_resolve = false)
|
50
50
|
addresses.map! do |address|
|
51
51
|
address.is_a?(IPAddr) ? address : IPAddr.new(address.to_s)
|
52
52
|
end
|
53
53
|
|
54
|
-
# double emission check
|
55
|
-
return if connection.addresses && !addresses.intersect?(connection.addresses)
|
54
|
+
# double emission check, but allow early resolution to work
|
55
|
+
return if !early_resolve && connection.addresses && !addresses.intersect?(connection.addresses)
|
56
56
|
|
57
57
|
log { "resolver: answer #{FAMILY_TYPES[RECORD_TYPES[family]]} #{connection.origin.host}: #{addresses.inspect}" }
|
58
58
|
if @pool && # if triggered by early resolve, pool may not be here yet
|
@@ -87,7 +87,7 @@ module HTTPX
|
|
87
87
|
|
88
88
|
return if addresses.empty?
|
89
89
|
|
90
|
-
emit_addresses(connection, @family, addresses)
|
90
|
+
emit_addresses(connection, @family, addresses, true)
|
91
91
|
end
|
92
92
|
|
93
93
|
def emit_resolve_error(connection, hostname = connection.origin.host, ex = nil)
|
data/lib/httpx/response.rb
CHANGED
@@ -9,6 +9,7 @@ require "forwardable"
|
|
9
9
|
module HTTPX
|
10
10
|
class Response
|
11
11
|
extend Forwardable
|
12
|
+
include Callbacks
|
12
13
|
|
13
14
|
attr_reader :status, :headers, :body, :version
|
14
15
|
|
@@ -139,6 +140,12 @@ module HTTPX
|
|
139
140
|
@state = :idle
|
140
141
|
end
|
141
142
|
|
143
|
+
def initialize_dup(other)
|
144
|
+
super
|
145
|
+
|
146
|
+
@buffer = other.instance_variable_get(:@buffer).dup
|
147
|
+
end
|
148
|
+
|
142
149
|
def closed?
|
143
150
|
@state == :closed
|
144
151
|
end
|
@@ -146,9 +153,13 @@ module HTTPX
|
|
146
153
|
def write(chunk)
|
147
154
|
return if @state == :closed
|
148
155
|
|
149
|
-
|
156
|
+
size = chunk.bytesize
|
157
|
+
@length += size
|
150
158
|
transition
|
151
159
|
@buffer.write(chunk)
|
160
|
+
|
161
|
+
@response.emit(:chunk_received, chunk)
|
162
|
+
size
|
152
163
|
end
|
153
164
|
|
154
165
|
def read(*args)
|
data/lib/httpx/session.rb
CHANGED
@@ -4,6 +4,7 @@ module HTTPX
|
|
4
4
|
class Session
|
5
5
|
include Loggable
|
6
6
|
include Chainable
|
7
|
+
include Callbacks
|
7
8
|
|
8
9
|
EMPTY_HASH = {}.freeze
|
9
10
|
|
@@ -45,6 +46,31 @@ module HTTPX
|
|
45
46
|
request = rklass.new(verb, uri, options.merge(persistent: @persistent))
|
46
47
|
request.on(:response, &method(:on_response).curry(2)[request])
|
47
48
|
request.on(:promise, &method(:on_promise))
|
49
|
+
|
50
|
+
request.on(:headers) do
|
51
|
+
emit(:request_started, request)
|
52
|
+
end
|
53
|
+
request.on(:body_chunk) do |chunk|
|
54
|
+
emit(:request_body_chunk, request, chunk)
|
55
|
+
end
|
56
|
+
request.on(:done) do
|
57
|
+
emit(:request_completed, request)
|
58
|
+
end
|
59
|
+
|
60
|
+
request.on(:response_started) do |res|
|
61
|
+
if res.is_a?(Response)
|
62
|
+
emit(:response_started, request, res)
|
63
|
+
res.on(:chunk_received) do |chunk|
|
64
|
+
emit(:response_body_chunk, request, res, chunk)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
emit(:request_error, request, res.error)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
request.on(:response) do |res|
|
71
|
+
emit(:response_completed, request, res)
|
72
|
+
end
|
73
|
+
|
48
74
|
request
|
49
75
|
end
|
50
76
|
|
@@ -174,7 +200,16 @@ module HTTPX
|
|
174
200
|
raise UnsupportedSchemeError, "#{uri}: #{uri.scheme}: unsupported URI scheme"
|
175
201
|
end
|
176
202
|
end
|
203
|
+
init_connection(type, uri, options)
|
204
|
+
end
|
205
|
+
|
206
|
+
def init_connection(type, uri, options)
|
177
207
|
connection = options.connection_class.new(type, uri, options)
|
208
|
+
connection.on(:open) do
|
209
|
+
emit(:connection_opened, connection.origin, connection.io.socket)
|
210
|
+
# only run close callback if it opened
|
211
|
+
connection.on(:close) { emit(:connection_closed, connection.origin, connection.io.socket) }
|
212
|
+
end
|
178
213
|
catch(:coalesced) do
|
179
214
|
pool.init_connection(connection, options)
|
180
215
|
connection
|
@@ -252,6 +287,7 @@ module HTTPX
|
|
252
287
|
super
|
253
288
|
klass.instance_variable_set(:@default_options, @default_options)
|
254
289
|
klass.instance_variable_set(:@plugins, @plugins.dup)
|
290
|
+
klass.instance_variable_set(:@callbacks, @callbacks.dup)
|
255
291
|
end
|
256
292
|
|
257
293
|
def plugin(pl, options = nil, &block)
|
@@ -9,10 +9,13 @@ module HTTPX
|
|
9
9
|
# redefine the default options static var, which needs to
|
10
10
|
# refresh options_class
|
11
11
|
options = proxy_session.class.default_options.to_hash
|
12
|
-
options.freeze
|
13
12
|
original_verbosity = $VERBOSE
|
14
13
|
$VERBOSE = nil
|
14
|
+
const_set(:Options, proxy_session.class.default_options.options_class)
|
15
|
+
options[:options_class] = Class.new(options[:options_class])
|
16
|
+
options.freeze
|
15
17
|
Options.send(:const_set, :DEFAULT_OPTIONS, options)
|
18
|
+
Session.instance_variable_set(:@default_options, Options.new(options))
|
16
19
|
$VERBOSE = original_verbosity
|
17
20
|
end
|
18
21
|
|
data/lib/httpx/version.rb
CHANGED
data/sig/callbacks.rbs
CHANGED
@@ -4,9 +4,9 @@ module HTTPX
|
|
4
4
|
end
|
5
5
|
|
6
6
|
module Callbacks
|
7
|
-
def on: (Symbol) { (*untyped) -> void } ->
|
8
|
-
def once: (Symbol) { (*untyped) -> void } ->
|
9
|
-
def only: (Symbol) { (*untyped) -> void } ->
|
7
|
+
def on: (Symbol) { (*untyped) -> void } -> self
|
8
|
+
def once: (Symbol) { (*untyped) -> void } -> self
|
9
|
+
def only: (Symbol) { (*untyped) -> void } -> self
|
10
10
|
def emit: (Symbol, *untyped) -> void
|
11
11
|
|
12
12
|
def callbacks_for?: (Symbol) -> bool
|
data/sig/chainable.rbs
CHANGED
@@ -34,6 +34,7 @@ module HTTPX
|
|
34
34
|
| (:grpc, ?options) -> Plugins::grpcSession
|
35
35
|
| (:response_cache, ?options) -> Plugins::sessionResponseCache
|
36
36
|
| (:circuit_breaker, ?options) -> Plugins::sessionCircuitBreaker
|
37
|
+
| (:oauth, ?options) -> Plugins::sessionOAuth
|
37
38
|
| (Symbol | Module, ?options) { (Class) -> void } -> Session
|
38
39
|
| (Symbol | Module, ?options) -> Session
|
39
40
|
|
@@ -5,7 +5,7 @@ module HTTPX
|
|
5
5
|
class CircuitStore
|
6
6
|
@circuits: Hash[String, Circuit]
|
7
7
|
|
8
|
-
def try_open: (generic_uri uri, response response) ->
|
8
|
+
def try_open: (generic_uri uri, response response) -> response?
|
9
9
|
|
10
10
|
def try_respond: (Request request) -> response?
|
11
11
|
|
@@ -30,7 +30,7 @@ module HTTPX
|
|
30
30
|
|
31
31
|
def respond: () -> response?
|
32
32
|
|
33
|
-
def try_open: (response) ->
|
33
|
+
def try_open: (response) -> response?
|
34
34
|
|
35
35
|
def try_close: () -> void
|
36
36
|
|
@@ -52,6 +52,10 @@ module HTTPX
|
|
52
52
|
|
53
53
|
module InstanceMethods
|
54
54
|
@circuit_store: CircuitStore
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def try_circuit_open: (Request request, response response) -> response?
|
55
59
|
end
|
56
60
|
|
57
61
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module HTTPX
|
2
|
+
module Plugins
|
3
|
+
#
|
4
|
+
# https://gitlab.com/os85/httpx/wikis/OAuth
|
5
|
+
#
|
6
|
+
module OAuth
|
7
|
+
def self.load_dependencies: (singleton(Session) klass) -> void
|
8
|
+
|
9
|
+
type grant_type = "client_credentials" | "refresh_token"
|
10
|
+
|
11
|
+
type token_auth_method = "client_secret_basic" | "client_secret_post"
|
12
|
+
|
13
|
+
SUPPORTED_GRANT_TYPES: ::Array[grant_type]
|
14
|
+
|
15
|
+
SUPPORTED_AUTH_METHODS: ::Array[token_auth_method]
|
16
|
+
|
17
|
+
class OAuthSession
|
18
|
+
attr_reader token_endpoint_auth_method: token_auth_method
|
19
|
+
|
20
|
+
attr_reader grant_type: grant_type
|
21
|
+
|
22
|
+
attr_reader client_id: String
|
23
|
+
|
24
|
+
attr_reader client_secret: String
|
25
|
+
|
26
|
+
attr_reader access_token: String?
|
27
|
+
|
28
|
+
attr_reader refresh_token: String?
|
29
|
+
|
30
|
+
attr_reader scope: Array[String]?
|
31
|
+
|
32
|
+
def initialize: (issuer: uri, client_id: String, client_secret: String, ?access_token: String?, ?refresh_token: String?, ?scope: (Array[String] | String)?, ?token_endpoint: String?, ?response_type: String?, ?grant_type: String?, ?token_endpoint_auth_method: ::String) -> void
|
33
|
+
|
34
|
+
def token_endpoint: () -> String
|
35
|
+
|
36
|
+
def load: (Session http) -> void
|
37
|
+
|
38
|
+
def merge: (instance | Hash[untyped, untyped] other) -> instance
|
39
|
+
end
|
40
|
+
|
41
|
+
interface _AwsSdkOptions
|
42
|
+
def oauth_session: () -> OAuthSession?
|
43
|
+
end
|
44
|
+
|
45
|
+
module InstanceMethods
|
46
|
+
def oauth_authentication: (**untyped args) -> instance
|
47
|
+
|
48
|
+
def with_access_token: () -> instance
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
type sessionOAuth = Session & OAuth::InstanceMethods
|
53
|
+
end
|
54
|
+
end
|
@@ -8,7 +8,7 @@ module HTTPX
|
|
8
8
|
def self?.cached_response?: (response response) -> bool
|
9
9
|
|
10
10
|
class Store
|
11
|
-
@store: Hash[String, Array[Response]]
|
11
|
+
@store: Hash[String, Array[Response]] & Mutex_m
|
12
12
|
|
13
13
|
def lookup: (Request request) -> Response?
|
14
14
|
|
@@ -21,6 +21,10 @@ module HTTPX
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def match_by_vary?: (Request request, Response response) -> bool
|
24
|
+
|
25
|
+
def _get: (Request request) -> Array[Response]?
|
26
|
+
|
27
|
+
def _set: (Request request, Response response) -> void
|
24
28
|
end
|
25
29
|
|
26
30
|
module InstanceMethods
|
data/sig/resolver/resolver.rbs
CHANGED
data/sig/response.rbs
CHANGED
data/sig/session.rbs
CHANGED
@@ -27,9 +27,9 @@ module HTTPX
|
|
27
27
|
def on_promise: (untyped, untyped) -> void
|
28
28
|
def fetch_response: (Request request, Array[Connection] connections, untyped options) -> response?
|
29
29
|
|
30
|
-
def find_connection: (Request, Array[Connection] connections, Options options) -> Connection
|
30
|
+
def find_connection: (Request request, Array[Connection] connections, Options options) -> Connection
|
31
31
|
|
32
|
-
def set_connection_callbacks: (Connection, Array[Connection], Options) -> void
|
32
|
+
def set_connection_callbacks: (Connection connection, Array[Connection] connections, Options options) -> void
|
33
33
|
|
34
34
|
def build_altsvc_connection: (Connection existing_connection, Array[Connection] connections, URI::Generic alt_origin, String origin, Hash[String, String] alt_params, Options options) -> Connection?
|
35
35
|
|
@@ -39,13 +39,15 @@ module HTTPX
|
|
39
39
|
| (verb, _Each[[uri, options]], Options) -> Array[Request]
|
40
40
|
| (verb, _Each[uri], options) -> Array[Request]
|
41
41
|
|
42
|
-
def build_connection: (URI::HTTP | URI::
|
42
|
+
def build_connection: (URI::HTTP | URI::HTTP uri, Options options) -> Connection
|
43
|
+
|
44
|
+
def init_connection: (String type, URI::HTTP | URI::HTTP uri, Options options) -> Connection
|
43
45
|
|
44
46
|
def send_requests: (*Request) -> Array[response]
|
45
47
|
|
46
|
-
def _send_requests: (Array[Request]) -> Array[Connection]
|
48
|
+
def _send_requests: (Array[Request] requests) -> Array[Connection]
|
47
49
|
|
48
|
-
def receive_requests: (Array[Request], Array[Connection]) -> Array[response]
|
50
|
+
def receive_requests: (Array[Request] requests, Array[Connection] connections) -> Array[response]
|
49
51
|
|
50
52
|
attr_reader self.default_options: Options
|
51
53
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httpx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.24.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Cardoso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-06-
|
11
|
+
date: 2023-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http-2-next
|
@@ -99,6 +99,8 @@ extra_rdoc_files:
|
|
99
99
|
- doc/release_notes/0_23_2.md
|
100
100
|
- doc/release_notes/0_23_3.md
|
101
101
|
- doc/release_notes/0_23_4.md
|
102
|
+
- doc/release_notes/0_24_0.md
|
103
|
+
- doc/release_notes/0_24_1.md
|
102
104
|
- doc/release_notes/0_2_0.md
|
103
105
|
- doc/release_notes/0_2_1.md
|
104
106
|
- doc/release_notes/0_3_0.md
|
@@ -190,6 +192,8 @@ files:
|
|
190
192
|
- doc/release_notes/0_23_2.md
|
191
193
|
- doc/release_notes/0_23_3.md
|
192
194
|
- doc/release_notes/0_23_4.md
|
195
|
+
- doc/release_notes/0_24_0.md
|
196
|
+
- doc/release_notes/0_24_1.md
|
193
197
|
- doc/release_notes/0_2_0.md
|
194
198
|
- doc/release_notes/0_2_1.md
|
195
199
|
- doc/release_notes/0_3_0.md
|
@@ -268,6 +272,7 @@ files:
|
|
268
272
|
- lib/httpx/plugins/multipart/mime_type_detector.rb
|
269
273
|
- lib/httpx/plugins/multipart/part.rb
|
270
274
|
- lib/httpx/plugins/ntlm_authentication.rb
|
275
|
+
- lib/httpx/plugins/oauth.rb
|
271
276
|
- lib/httpx/plugins/persistent.rb
|
272
277
|
- lib/httpx/plugins/proxy.rb
|
273
278
|
- lib/httpx/plugins/proxy/http.rb
|
@@ -349,6 +354,7 @@ files:
|
|
349
354
|
- sig/plugins/h2c.rbs
|
350
355
|
- sig/plugins/multipart.rbs
|
351
356
|
- sig/plugins/ntlm_authentication.rbs
|
357
|
+
- sig/plugins/oauth.rbs
|
352
358
|
- sig/plugins/persistent.rbs
|
353
359
|
- sig/plugins/proxy.rbs
|
354
360
|
- sig/plugins/proxy/http.rbs
|
@@ -388,7 +394,7 @@ metadata:
|
|
388
394
|
changelog_uri: https://os85.gitlab.io/httpx/#release-notes
|
389
395
|
documentation_uri: https://os85.gitlab.io/httpx/rdoc/
|
390
396
|
source_code_uri: https://gitlab.com/os85/httpx
|
391
|
-
homepage_uri: https://
|
397
|
+
homepage_uri: https://honeyryderchuck.gitlab.io/httpx/
|
392
398
|
rubygems_mfa_required: 'true'
|
393
399
|
post_install_message:
|
394
400
|
rdoc_options: []
|
@@ -405,7 +411,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
405
411
|
- !ruby/object:Gem::Version
|
406
412
|
version: '0'
|
407
413
|
requirements: []
|
408
|
-
rubygems_version: 3.4.
|
414
|
+
rubygems_version: 3.4.10
|
409
415
|
signing_key:
|
410
416
|
specification_version: 4
|
411
417
|
summary: HTTPX, to the future, and beyond
|