httpx 1.7.8 → 1.8.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/1_7_1.md +1 -2
- data/doc/release_notes/1_8_0.md +100 -0
- data/doc/release_notes/1_8_1.md +27 -0
- data/lib/httpx/adapters/datadog.rb +12 -1
- data/lib/httpx/adapters/faraday.rb +2 -2
- data/lib/httpx/adapters/webmock.rb +6 -0
- data/lib/httpx/connection/http1.rb +15 -12
- data/lib/httpx/connection/http2.rb +69 -9
- data/lib/httpx/connection.rb +119 -21
- data/lib/httpx/errors.rb +8 -1
- data/lib/httpx/headers.rb +2 -2
- data/lib/httpx/io/ssl.rb +8 -9
- data/lib/httpx/io/tcp.rb +22 -5
- data/lib/httpx/io/unix.rb +2 -2
- data/lib/httpx/loggable.rb +11 -4
- data/lib/httpx/options.rb +16 -4
- data/lib/httpx/parser/http1.rb +8 -2
- data/lib/httpx/plugins/auth/digest.rb +1 -1
- data/lib/httpx/plugins/auth.rb +61 -4
- data/lib/httpx/plugins/{response_cache → cache}/file_store.rb +1 -1
- data/lib/httpx/plugins/{response_cache → cache}/store.rb +1 -1
- data/lib/httpx/plugins/cache.rb +221 -0
- data/lib/httpx/plugins/callbacks.rb +12 -0
- data/lib/httpx/plugins/digest_auth.rb +4 -0
- data/lib/httpx/plugins/fiber_concurrency.rb +75 -4
- data/lib/httpx/plugins/ntlm_v2_auth.rb +92 -0
- data/lib/httpx/plugins/oauth.rb +66 -14
- data/lib/httpx/plugins/persistent.rb +18 -2
- data/lib/httpx/plugins/proxy.rb +5 -0
- data/lib/httpx/plugins/push_promise.rb +2 -2
- data/lib/httpx/plugins/response_cache.rb +26 -105
- data/lib/httpx/plugins/retries.rb +7 -5
- data/lib/httpx/plugins/server_sent_events.rb +158 -0
- data/lib/httpx/plugins/ssrf_filter.rb +17 -2
- data/lib/httpx/plugins/stream.rb +9 -5
- data/lib/httpx/plugins/stream_bidi.rb +2 -0
- data/lib/httpx/plugins/tracing.rb +15 -4
- data/lib/httpx/pool.rb +2 -2
- data/lib/httpx/request/body.rb +2 -2
- data/lib/httpx/request.rb +42 -10
- data/lib/httpx/resolver/cache/base.rb +1 -8
- data/lib/httpx/resolver/cache/file.rb +56 -0
- data/lib/httpx/resolver/https.rb +20 -20
- data/lib/httpx/resolver/native.rb +21 -3
- data/lib/httpx/resolver/resolver.rb +4 -0
- data/lib/httpx/resolver/system.rb +5 -2
- data/lib/httpx/response/body.rb +6 -4
- data/lib/httpx/response.rb +12 -5
- data/lib/httpx/selector.rb +12 -1
- data/lib/httpx/session.rb +6 -1
- data/lib/httpx/session_extensions.rb +2 -2
- data/lib/httpx/timers.rb +3 -0
- data/lib/httpx/version.rb +1 -1
- data/sig/chainable.rbs +3 -0
- data/sig/connection/http1.rbs +1 -1
- data/sig/connection/http2.rbs +4 -1
- data/sig/connection.rbs +16 -9
- data/sig/errors.rbs +9 -3
- data/sig/httpx.rbs +2 -0
- data/sig/io/tcp.rbs +2 -0
- data/sig/loggable.rbs +8 -0
- data/sig/options.rbs +25 -12
- data/sig/parser/http1.rbs +3 -1
- data/sig/plugins/auth/ntlm.rbs +1 -1
- data/sig/plugins/auth.rbs +4 -0
- data/sig/plugins/{response_cache → cache}/file_store.rbs +2 -2
- data/sig/plugins/{response_cache → cache}/store.rbs +2 -2
- data/sig/plugins/cache.rbs +69 -0
- data/sig/plugins/fiber_concurrency.rbs +4 -0
- data/sig/plugins/ntlm_v2_auth.rbs +36 -0
- data/sig/plugins/persistent.rbs +3 -0
- data/sig/plugins/response_cache.rbs +13 -38
- data/sig/plugins/retries.rbs +5 -5
- data/sig/plugins/server_sent_events.rbs +45 -0
- data/sig/plugins/ssrf_filter.rbs +5 -1
- data/sig/plugins/stream.rbs +1 -1
- data/sig/plugins/stream_bidi.rbs +0 -2
- data/sig/plugins/webdav.rbs +1 -1
- data/sig/pool.rbs +2 -2
- data/sig/request.rbs +9 -6
- data/sig/resolver/cache/file.rbs +13 -0
- data/sig/resolver/entry.rbs +1 -1
- data/sig/resolver/https.rbs +3 -3
- data/sig/resolver/multi.rbs +1 -1
- data/sig/resolver/native.rbs +5 -5
- data/sig/resolver/resolver.rbs +1 -3
- data/sig/resolver/system.rbs +5 -2
- data/sig/resolver.rbs +3 -0
- data/sig/response.rbs +3 -0
- data/sig/selector.rbs +13 -8
- data/sig/timers.rbs +7 -5
- data/sig/transcoder/body.rbs +1 -1
- data/sig/transcoder/gzip.rbs +3 -2
- data/sig/transcoder/multipart.rbs +4 -1
- data/sig/transcoder/utils/deflater.rbs +2 -0
- data/sig/transcoder.rbs +2 -0
- data/sig/utils.rbs +1 -1
- metadata +19 -7
data/lib/httpx/plugins/stream.rb
CHANGED
|
@@ -46,8 +46,8 @@ module HTTPX
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
def each_line
|
|
50
|
-
return enum_for(__method__) unless
|
|
49
|
+
def each_line(&block)
|
|
50
|
+
return enum_for(__method__) unless block
|
|
51
51
|
|
|
52
52
|
line = "".b
|
|
53
53
|
|
|
@@ -55,7 +55,11 @@ module HTTPX
|
|
|
55
55
|
line << chunk
|
|
56
56
|
|
|
57
57
|
while (idx = line.index("\n"))
|
|
58
|
-
|
|
58
|
+
if idx.zero?
|
|
59
|
+
yield ""
|
|
60
|
+
else
|
|
61
|
+
yield line.byteslice(0..(idx - 1))
|
|
62
|
+
end
|
|
59
63
|
|
|
60
64
|
line = line.byteslice((idx + 1)..-1)
|
|
61
65
|
end
|
|
@@ -71,11 +75,11 @@ module HTTPX
|
|
|
71
75
|
@on_chunk.call(chunk)
|
|
72
76
|
end
|
|
73
77
|
|
|
74
|
-
# :
|
|
78
|
+
# simplecov:disable
|
|
75
79
|
def inspect
|
|
76
80
|
"#<#{self.class}:#{object_id}>"
|
|
77
81
|
end
|
|
78
|
-
# :
|
|
82
|
+
# simplecov:enable
|
|
79
83
|
|
|
80
84
|
def to_s
|
|
81
85
|
if @request.response
|
|
@@ -111,10 +111,11 @@ module HTTPX::Plugins
|
|
|
111
111
|
@init_time = ::Time.now.utc
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
-
def
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
def send_request_to_parser(request)
|
|
115
|
+
if connecting?
|
|
116
|
+
# request span timeframe should include the time it took to connect.
|
|
117
|
+
request.init_time ||= @init_time
|
|
118
|
+
end
|
|
118
119
|
|
|
119
120
|
super
|
|
120
121
|
end
|
|
@@ -126,6 +127,16 @@ module HTTPX::Plugins
|
|
|
126
127
|
# the connection is back to :idle, and ready to connect again.
|
|
127
128
|
@init_time = ::Time.now.utc
|
|
128
129
|
end
|
|
130
|
+
|
|
131
|
+
private
|
|
132
|
+
|
|
133
|
+
def ping(request)
|
|
134
|
+
# if a connection is probed for liveness, the request timeframe should include
|
|
135
|
+
# it too.
|
|
136
|
+
request.init_time ||= ::Time.now.utc
|
|
137
|
+
|
|
138
|
+
super
|
|
139
|
+
end
|
|
129
140
|
end
|
|
130
141
|
end
|
|
131
142
|
register_plugin :tracing, Tracing
|
data/lib/httpx/pool.rb
CHANGED
|
@@ -173,7 +173,7 @@ module HTTPX
|
|
|
173
173
|
end
|
|
174
174
|
end
|
|
175
175
|
|
|
176
|
-
# :
|
|
176
|
+
# simplecov:disable
|
|
177
177
|
def inspect
|
|
178
178
|
"#<#{self.class}:#{object_id} " \
|
|
179
179
|
"@max_connections=#{@max_connections} " \
|
|
@@ -181,7 +181,7 @@ module HTTPX
|
|
|
181
181
|
"@pool_timeout=#{@pool_timeout} " \
|
|
182
182
|
"@connections=#{@connections.size}>"
|
|
183
183
|
end
|
|
184
|
-
# :
|
|
184
|
+
# simplecov:enable
|
|
185
185
|
|
|
186
186
|
private
|
|
187
187
|
|
data/lib/httpx/request/body.rb
CHANGED
|
@@ -114,12 +114,12 @@ module HTTPX
|
|
|
114
114
|
@headers.add("transfer-encoding", "chunked")
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
-
# :
|
|
117
|
+
# simplecov:disable
|
|
118
118
|
def inspect
|
|
119
119
|
"#<#{self.class}:#{object_id} " \
|
|
120
120
|
"#{unbounded_body? ? "stream" : "@bytesize=#{bytesize}"}>"
|
|
121
121
|
end
|
|
122
|
-
# :
|
|
122
|
+
# simplecov:enable
|
|
123
123
|
|
|
124
124
|
class << self
|
|
125
125
|
def initialize_body(params)
|
data/lib/httpx/request.rb
CHANGED
|
@@ -39,6 +39,10 @@ module HTTPX
|
|
|
39
39
|
# Exception raised during enumerable body writes.
|
|
40
40
|
attr_reader :drain_error
|
|
41
41
|
|
|
42
|
+
# when this request is sent via HTTP/2, it'll use this hash of options to set the priority of the
|
|
43
|
+
# respective HTTP/2 frame.
|
|
44
|
+
attr_reader :http2_stream_options
|
|
45
|
+
|
|
42
46
|
# The IP address from the peer server.
|
|
43
47
|
attr_accessor :peer_address
|
|
44
48
|
|
|
@@ -70,6 +74,7 @@ module HTTPX
|
|
|
70
74
|
# :form :: hash of array of key-values which will be form-urlencoded- or multipart-encoded in requests body payload.
|
|
71
75
|
# :json :: hash of array of key-values which will be JSON-encoded in requests body payload.
|
|
72
76
|
# :xml :: Nokogiri XML nodes which will be encoded in requests body payload.
|
|
77
|
+
# :http2_stream_options :: hash of options to be used to set the HTTP/2 priority by sending an initial PRIORITY frame.
|
|
73
78
|
#
|
|
74
79
|
# :body, :form, :json and :xml are all mutually exclusive, i.e. only one of them gets picked up.
|
|
75
80
|
def initialize(verb, uri, options, params = EMPTY_HASH)
|
|
@@ -81,6 +86,8 @@ module HTTPX
|
|
|
81
86
|
|
|
82
87
|
@query_params = params.delete(:params) if params.key?(:params)
|
|
83
88
|
|
|
89
|
+
@http2_stream_options = params.key?(:http2_stream_options) ? params.delete(:http2_stream_options) : EMPTY_HASH
|
|
90
|
+
|
|
84
91
|
@body = options.request_body_class.new(@headers, options, **params)
|
|
85
92
|
|
|
86
93
|
@options = @body.options
|
|
@@ -100,7 +107,7 @@ module HTTPX
|
|
|
100
107
|
@connection = @response =
|
|
101
108
|
@drainer = @peer_address =
|
|
102
109
|
@informational_status = @on_response_arrived = nil
|
|
103
|
-
@ping = false
|
|
110
|
+
@ping = @started = false
|
|
104
111
|
@persistent = @options.persistent
|
|
105
112
|
@active_timeouts = []
|
|
106
113
|
end
|
|
@@ -115,6 +122,7 @@ module HTTPX
|
|
|
115
122
|
|
|
116
123
|
def complete!(response = @response)
|
|
117
124
|
emit(:complete, response)
|
|
125
|
+
reset_timers(true)
|
|
118
126
|
end
|
|
119
127
|
|
|
120
128
|
# whether request has been buffered with a ping
|
|
@@ -142,6 +150,11 @@ module HTTPX
|
|
|
142
150
|
@options.timeout[:request_timeout]
|
|
143
151
|
end
|
|
144
152
|
|
|
153
|
+
# the total request timeout defined for this request.
|
|
154
|
+
def total_request_timeout
|
|
155
|
+
@options.timeout[:total_request_timeout]
|
|
156
|
+
end
|
|
157
|
+
|
|
145
158
|
def persistent?
|
|
146
159
|
@persistent
|
|
147
160
|
end
|
|
@@ -167,6 +180,10 @@ module HTTPX
|
|
|
167
180
|
@state != :done
|
|
168
181
|
end
|
|
169
182
|
|
|
183
|
+
def started?
|
|
184
|
+
@started
|
|
185
|
+
end
|
|
186
|
+
|
|
170
187
|
# merges +h+ into the instance of HTTPX::Headers of the request.
|
|
171
188
|
def merge_headers(h)
|
|
172
189
|
@headers = @headers.merge(h)
|
|
@@ -252,21 +269,19 @@ module HTTPX
|
|
|
252
269
|
|
|
253
270
|
# consumes and returns the next available chunk of request body that can be sent
|
|
254
271
|
def drain_body
|
|
255
|
-
return
|
|
272
|
+
return if @body.nil?
|
|
256
273
|
|
|
257
274
|
@drainer ||= @body.each
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
emit(:body_chunk, chunk)
|
|
261
|
-
chunk
|
|
275
|
+
@drainer.next.dup
|
|
262
276
|
rescue StopIteration
|
|
263
277
|
nil
|
|
264
278
|
rescue StandardError => e
|
|
279
|
+
# in case an error occurs while emitting body chunks
|
|
265
280
|
@drain_error = e
|
|
266
281
|
nil
|
|
267
282
|
end
|
|
268
283
|
|
|
269
|
-
# :
|
|
284
|
+
# simplecov:disable
|
|
270
285
|
def inspect
|
|
271
286
|
"#<#{self.class}:#{object_id} " \
|
|
272
287
|
"#{@verb} " \
|
|
@@ -274,7 +289,7 @@ module HTTPX
|
|
|
274
289
|
"@headers=#{@headers} " \
|
|
275
290
|
"@body=#{@body}>"
|
|
276
291
|
end
|
|
277
|
-
# :
|
|
292
|
+
# simplecov:enable
|
|
278
293
|
|
|
279
294
|
# moves on to the +nextstate+ of the request state machine (when all preconditions are met)
|
|
280
295
|
def transition(nextstate)
|
|
@@ -283,10 +298,14 @@ module HTTPX
|
|
|
283
298
|
@body.rewind
|
|
284
299
|
@ping = false
|
|
285
300
|
@response = @drainer = nil
|
|
286
|
-
|
|
301
|
+
|
|
302
|
+
# request may be sent to a different connection and will be
|
|
303
|
+
# reassigned a new set of timers.
|
|
304
|
+
reset_timers(false)
|
|
287
305
|
when :headers
|
|
288
306
|
return unless @state == :idle
|
|
289
307
|
|
|
308
|
+
@started = true
|
|
290
309
|
when :body
|
|
291
310
|
return unless @state == :headers ||
|
|
292
311
|
@state == :expect
|
|
@@ -309,7 +328,7 @@ module HTTPX
|
|
|
309
328
|
return if @state == :expect
|
|
310
329
|
|
|
311
330
|
end
|
|
312
|
-
log(level: 3) { "#{@state}
|
|
331
|
+
log(level: 3) { "#{@state} -> #{nextstate}" }
|
|
313
332
|
@state = nextstate
|
|
314
333
|
emit(@state, self)
|
|
315
334
|
nil
|
|
@@ -346,6 +365,19 @@ module HTTPX
|
|
|
346
365
|
|
|
347
366
|
@on_response_arrived.call
|
|
348
367
|
end
|
|
368
|
+
|
|
369
|
+
private
|
|
370
|
+
|
|
371
|
+
def reset_timers(reset_total_request_timers)
|
|
372
|
+
timers = @active_timeouts
|
|
373
|
+
|
|
374
|
+
until (timer = timers.shift).nil?
|
|
375
|
+
next if !reset_total_request_timers && timer.label == :total_request_timeout
|
|
376
|
+
|
|
377
|
+
# cancel active timers.
|
|
378
|
+
timer.cancel
|
|
379
|
+
end
|
|
380
|
+
end
|
|
349
381
|
end
|
|
350
382
|
end
|
|
351
383
|
|
|
@@ -106,14 +106,7 @@ module HTTPX
|
|
|
106
106
|
name = entry["name"]
|
|
107
107
|
next unless name != hostname
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
case family
|
|
112
|
-
when Socket::AF_INET6
|
|
113
|
-
lookups[name] << entry
|
|
114
|
-
when Socket::AF_INET
|
|
115
|
-
lookups[name].unshift(entry)
|
|
116
|
-
end
|
|
109
|
+
_set(name, family, [entry], lookups, hostnames)
|
|
117
110
|
end
|
|
118
111
|
end
|
|
119
112
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pstore"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
|
|
6
|
+
module HTTPX
|
|
7
|
+
module Resolver::Cache
|
|
8
|
+
# Implementation of a file resolver cache.
|
|
9
|
+
class File < Base
|
|
10
|
+
# default path where the resolver cache is stored. It's versioned, as the file may
|
|
11
|
+
# change format in-between releases, and it'd signal it as corrupted.
|
|
12
|
+
DEFAULT_PATH = ::File.join(Dir.tmpdir, "httpx-ruby-#{VERSION}.cache")
|
|
13
|
+
|
|
14
|
+
def initialize(path = DEFAULT_PATH)
|
|
15
|
+
super()
|
|
16
|
+
@store = PStore.new(path, true)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def get(hostname)
|
|
20
|
+
now = Utils.now
|
|
21
|
+
@store.transaction do
|
|
22
|
+
lookups = @store[:lookups] || EMPTY_HASH
|
|
23
|
+
hostnames = @store[:hostnames] || EMPTY
|
|
24
|
+
|
|
25
|
+
_get(hostname, lookups, hostnames, now)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def set(hostname, family, entries)
|
|
30
|
+
@store.transaction do
|
|
31
|
+
lookups = @store[:lookups] || {}
|
|
32
|
+
hostnames = @store[:hostnames] || []
|
|
33
|
+
|
|
34
|
+
_set(hostname, family, entries, lookups, hostnames)
|
|
35
|
+
|
|
36
|
+
@store[:lookups] = lookups
|
|
37
|
+
@store[:hostnames] = hostnames
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def evict(hostname, ip)
|
|
42
|
+
ip = ip.to_s
|
|
43
|
+
|
|
44
|
+
@store.transaction do
|
|
45
|
+
lookups = @store[:lookups] || EMPTY_HASH
|
|
46
|
+
hostnames = @store[:hostnames] || EMPTY
|
|
47
|
+
|
|
48
|
+
_evict(hostname, ip, lookups, hostnames)
|
|
49
|
+
|
|
50
|
+
@store[:lookups] = lookups
|
|
51
|
+
@store[:hostnames] = hostnames
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/httpx/resolver/https.rb
CHANGED
|
@@ -126,27 +126,27 @@ module HTTPX
|
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
def on_response(request, response)
|
|
129
|
-
response.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
location_uri = response.uri.merge(location_uri) if location_uri.relative?
|
|
142
|
-
|
|
143
|
-
# we assume that the DNS server URI changed permanently and move on
|
|
144
|
-
@uri = location_uri
|
|
145
|
-
send_request(hostname, connection)
|
|
146
|
-
return
|
|
147
|
-
end
|
|
129
|
+
if (e = response.error)
|
|
130
|
+
hostname = @requests.delete(request)
|
|
131
|
+
connection = reset_hostname(hostname)
|
|
132
|
+
emit_resolve_error(connection, connection.peer.host, e)
|
|
133
|
+
close_or_resolve
|
|
134
|
+
else
|
|
135
|
+
# @type var response: HTTPX::Response
|
|
136
|
+
if response.status.between?(300, 399) && response.headers.key?("location")
|
|
137
|
+
hostname = @requests[request]
|
|
138
|
+
connection = @queries[hostname]
|
|
139
|
+
location_uri = URI(response.headers["location"])
|
|
140
|
+
location_uri = response.uri.merge(location_uri) if location_uri.relative?
|
|
148
141
|
|
|
149
|
-
|
|
142
|
+
# we assume that the DNS server URI changed permanently and move on
|
|
143
|
+
@uri = location_uri
|
|
144
|
+
send_request(hostname, connection)
|
|
145
|
+
return
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
parse(request, response)
|
|
149
|
+
end
|
|
150
150
|
ensure
|
|
151
151
|
@requests.delete(request)
|
|
152
152
|
end
|
|
@@ -75,6 +75,13 @@ module HTTPX
|
|
|
75
75
|
|
|
76
76
|
def call
|
|
77
77
|
case @state
|
|
78
|
+
when :idle, :closed
|
|
79
|
+
return if @connections.empty?
|
|
80
|
+
|
|
81
|
+
transition(:idle) if @state == :closed
|
|
82
|
+
transition(:open)
|
|
83
|
+
|
|
84
|
+
consume if @state == :open
|
|
78
85
|
when :open
|
|
79
86
|
consume
|
|
80
87
|
end
|
|
@@ -512,12 +519,16 @@ module HTTPX
|
|
|
512
519
|
transition(:open)
|
|
513
520
|
end
|
|
514
521
|
|
|
522
|
+
# moves the resolver state machine to the +nextstate+ state (if all conditions are met)-
|
|
515
523
|
def transition(nextstate)
|
|
516
524
|
case nextstate
|
|
517
525
|
when :idle
|
|
518
|
-
if @io
|
|
519
|
-
@io.close
|
|
526
|
+
if (io = @io)
|
|
520
527
|
@io = nil
|
|
528
|
+
io.close
|
|
529
|
+
|
|
530
|
+
# @fiber-switch-guard
|
|
531
|
+
return if @io
|
|
521
532
|
end
|
|
522
533
|
when :open
|
|
523
534
|
return unless @state == :idle
|
|
@@ -531,7 +542,14 @@ module HTTPX
|
|
|
531
542
|
when :closed
|
|
532
543
|
return if @state == :closed
|
|
533
544
|
|
|
534
|
-
|
|
545
|
+
if (io = @io)
|
|
546
|
+
@io = nil
|
|
547
|
+
io.close
|
|
548
|
+
|
|
549
|
+
# @fiber-switch-guard
|
|
550
|
+
return if @io
|
|
551
|
+
end
|
|
552
|
+
|
|
535
553
|
@start_timeout = nil
|
|
536
554
|
@write_buffer.clear
|
|
537
555
|
@read_buffer.clear
|
|
@@ -23,6 +23,9 @@ module HTTPX
|
|
|
23
23
|
DONE = 1
|
|
24
24
|
ERROR = 2
|
|
25
25
|
|
|
26
|
+
class AddrinfoTimeoutError < StandardError
|
|
27
|
+
end
|
|
28
|
+
|
|
26
29
|
class << self
|
|
27
30
|
def multi?
|
|
28
31
|
false
|
|
@@ -227,7 +230,7 @@ module HTTPX
|
|
|
227
230
|
begin
|
|
228
231
|
addrs = if resolve_timeout
|
|
229
232
|
|
|
230
|
-
Timeout.timeout(resolve_timeout) do
|
|
233
|
+
Timeout.timeout(resolve_timeout, AddrinfoTimeoutError) do
|
|
231
234
|
__addrinfo_resolve(hostname, scheme)
|
|
232
235
|
end
|
|
233
236
|
else
|
|
@@ -246,7 +249,7 @@ module HTTPX
|
|
|
246
249
|
end
|
|
247
250
|
end
|
|
248
251
|
rescue StandardError => e
|
|
249
|
-
if e.is_a?(
|
|
252
|
+
if e.is_a?(AddrinfoTimeoutError)
|
|
250
253
|
timeouts.shift
|
|
251
254
|
retry unless timeouts.empty?
|
|
252
255
|
e = ResolveTimeoutError.new(resolve_timeout, e.message)
|
data/lib/httpx/response/body.rb
CHANGED
|
@@ -20,10 +20,10 @@ module HTTPX
|
|
|
20
20
|
@headers = response.headers
|
|
21
21
|
@options = options
|
|
22
22
|
@window_size = options.window_size
|
|
23
|
+
@max_response_body_size = options.max_response_body_size
|
|
23
24
|
@encodings = []
|
|
24
25
|
@length = 0
|
|
25
|
-
@buffer = nil
|
|
26
|
-
@reader = nil
|
|
26
|
+
@buffer = @reader = nil
|
|
27
27
|
@state = :idle
|
|
28
28
|
|
|
29
29
|
# initialize response encoding
|
|
@@ -59,6 +59,8 @@ module HTTPX
|
|
|
59
59
|
|
|
60
60
|
chunk = decode_chunk(chunk)
|
|
61
61
|
|
|
62
|
+
raise Error, "maximum response body size exceeded" if @max_response_body_size < @length
|
|
63
|
+
|
|
62
64
|
transition(:open)
|
|
63
65
|
@buffer.write(chunk)
|
|
64
66
|
|
|
@@ -159,13 +161,13 @@ module HTTPX
|
|
|
159
161
|
end
|
|
160
162
|
end
|
|
161
163
|
|
|
162
|
-
# :
|
|
164
|
+
# simplecov:disable
|
|
163
165
|
def inspect
|
|
164
166
|
"#<#{self.class}:#{object_id} " \
|
|
165
167
|
"@state=#{@state} " \
|
|
166
168
|
"@length=#{@length}>"
|
|
167
169
|
end
|
|
168
|
-
# :
|
|
170
|
+
# simplecov:enable
|
|
169
171
|
|
|
170
172
|
# rewinds the response payload buffer.
|
|
171
173
|
def rewind
|
data/lib/httpx/response.rb
CHANGED
|
@@ -68,7 +68,7 @@ module HTTPX
|
|
|
68
68
|
@headers = @options.headers_class.new(headers)
|
|
69
69
|
@body = @options.response_body_class.new(self, @options)
|
|
70
70
|
@finished = complete?
|
|
71
|
-
@content_type = nil
|
|
71
|
+
@content_type = @content_length = nil
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
# dupped initialization
|
|
@@ -88,6 +88,7 @@ module HTTPX
|
|
|
88
88
|
# merges headers defined in +h+ into the response headers.
|
|
89
89
|
def merge_headers(h)
|
|
90
90
|
@headers = @headers.merge(h)
|
|
91
|
+
@content_type = @content_length = nil
|
|
91
92
|
end
|
|
92
93
|
|
|
93
94
|
# writes +data+ chunk into the response body.
|
|
@@ -103,6 +104,13 @@ module HTTPX
|
|
|
103
104
|
@content_type ||= ContentType.new(@headers["content-type"])
|
|
104
105
|
end
|
|
105
106
|
|
|
107
|
+
# returns the response content length as advertised in the HTTP Content-Length header value.
|
|
108
|
+
def content_length
|
|
109
|
+
return @content_length if defined?(@content_length)
|
|
110
|
+
|
|
111
|
+
@content_length = @headers["content-length"]&.to_i
|
|
112
|
+
end
|
|
113
|
+
|
|
106
114
|
# returns whether the response has been fully fetched.
|
|
107
115
|
def finished?
|
|
108
116
|
@finished
|
|
@@ -133,7 +141,7 @@ module HTTPX
|
|
|
133
141
|
bodyless? || (@request.verb == "CONNECT" && @status == 200)
|
|
134
142
|
end
|
|
135
143
|
|
|
136
|
-
# :
|
|
144
|
+
# simplecov:disable
|
|
137
145
|
def inspect
|
|
138
146
|
"#<#{self.class}:#{object_id} " \
|
|
139
147
|
"HTTP/#{version} " \
|
|
@@ -141,7 +149,7 @@ module HTTPX
|
|
|
141
149
|
"@headers=#{@headers} " \
|
|
142
150
|
"@body=#{@body.bytesize}>"
|
|
143
151
|
end
|
|
144
|
-
# :
|
|
152
|
+
# simplecov:enable
|
|
145
153
|
|
|
146
154
|
# returns an instance of HTTPX::HTTPError if the response has a 4xx or 5xx
|
|
147
155
|
# status code, or nothing.
|
|
@@ -259,7 +267,6 @@ module HTTPX
|
|
|
259
267
|
# response = HTTPX.get("https://some-domain/path") #=> response is HTTPX::Response or HTTPX::ErrorResponse
|
|
260
268
|
# response.raise_for_status #=> raises if it wraps an error
|
|
261
269
|
class ErrorResponse
|
|
262
|
-
include Loggable
|
|
263
270
|
extend Forwardable
|
|
264
271
|
|
|
265
272
|
# the corresponding HTTPX::Request instance.
|
|
@@ -282,7 +289,7 @@ module HTTPX
|
|
|
282
289
|
@response = request.response if request.response.is_a?(Response)
|
|
283
290
|
@error = error
|
|
284
291
|
@options = request.options
|
|
285
|
-
log_exception(@error)
|
|
292
|
+
@request.log_exception(@error)
|
|
286
293
|
finish!
|
|
287
294
|
end
|
|
288
295
|
|
data/lib/httpx/selector.rb
CHANGED
|
@@ -41,6 +41,11 @@ module HTTPX
|
|
|
41
41
|
@selectables.empty? && @timers.empty?
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# first time the registered selectables are added, there's probably work to do.
|
|
45
|
+
def initial_call
|
|
46
|
+
@selectables.each(&:initial_call)
|
|
47
|
+
end
|
|
48
|
+
|
|
44
49
|
def next_tick
|
|
45
50
|
catch(:jump_tick) do
|
|
46
51
|
timeout = next_timeout
|
|
@@ -134,7 +139,13 @@ module HTTPX
|
|
|
134
139
|
# the connections to be reaped (such as the total timeout error) before #select
|
|
135
140
|
# gets called.
|
|
136
141
|
if @selectables.empty?
|
|
137
|
-
|
|
142
|
+
begin
|
|
143
|
+
sleep(interval)
|
|
144
|
+
rescue IOError
|
|
145
|
+
# @fiber-switch-guard
|
|
146
|
+
# in a fiber scheduler scenario, IOs may be closed by the scheduler and raised in a separate fiber
|
|
147
|
+
# on wakeup, which includes a sleep call.
|
|
148
|
+
end if interval
|
|
138
149
|
return
|
|
139
150
|
end
|
|
140
151
|
|
data/lib/httpx/session.rb
CHANGED
|
@@ -319,9 +319,14 @@ module HTTPX
|
|
|
319
319
|
|
|
320
320
|
waiting = false
|
|
321
321
|
|
|
322
|
-
|
|
322
|
+
requests.each do |request|
|
|
323
323
|
send_request(request, selector)
|
|
324
|
+
end
|
|
324
325
|
|
|
326
|
+
# do work first
|
|
327
|
+
selector.initial_call
|
|
328
|
+
|
|
329
|
+
responses = requests.each_with_index.map do |request, idx|
|
|
325
330
|
fetch_response(request, selector, request.options).tap do |response|
|
|
326
331
|
if response.nil?
|
|
327
332
|
pending += 1
|
|
@@ -20,11 +20,11 @@ module HTTPX
|
|
|
20
20
|
$VERBOSE = original_verbosity
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
# :
|
|
23
|
+
# simplecov:disable
|
|
24
24
|
if Session.default_options.debug_level > 2
|
|
25
25
|
proxy_session = plugin(:internal_telemetry)
|
|
26
26
|
remove_const(:Session)
|
|
27
27
|
const_set(:Session, proxy_session.class)
|
|
28
28
|
end
|
|
29
|
-
# :
|
|
29
|
+
# simplecov:enable
|
|
30
30
|
end
|
data/lib/httpx/timers.rb
CHANGED
data/lib/httpx/version.rb
CHANGED
data/sig/chainable.rbs
CHANGED
|
@@ -16,6 +16,7 @@ module HTTPX
|
|
|
16
16
|
| (:basic_auth, ?options) -> Plugins::sessionBasicAuth
|
|
17
17
|
| (:digest_auth, ?options) -> Plugins::sessionDigestAuth
|
|
18
18
|
| (:ntlm_auth, ?options) -> Plugins::sessionNTLMAuth
|
|
19
|
+
| (:ntlm_v2_auth, ?options) -> Plugins::sessionNTLMV2Auth
|
|
19
20
|
| (:aws_sdk_authentication, ?options) -> Plugins::sessionAwsSdkAuthentication
|
|
20
21
|
| (:brotli, ?options) -> Session
|
|
21
22
|
| (:cookies, ?options) -> Plugins::sessionCookies
|
|
@@ -32,8 +33,10 @@ module HTTPX
|
|
|
32
33
|
| (:rate_limiter, ?options) -> Plugins::sessionRateLimiter
|
|
33
34
|
| (:stream, ?options) -> Plugins::sessionStream
|
|
34
35
|
| (:stream_bidi, ?options) -> Plugins::sessionStreamBidi
|
|
36
|
+
| (:server_sent_events, ?options) -> Plugins::sessionServerSentEvents
|
|
35
37
|
| (:aws_sigv4, ?options) -> Plugins::awsSigV4Session
|
|
36
38
|
| (:grpc, ?options) -> Plugins::grpcSession
|
|
39
|
+
| (:cache, ?options) -> Plugins::sessionCache
|
|
37
40
|
| (:response_cache, ?options) -> Plugins::sessionResponseCache
|
|
38
41
|
| (:circuit_breaker, ?options) -> Plugins::sessionCircuitBreaker
|
|
39
42
|
| (:oauth, ?options) -> Plugins::sessionOAuth
|