httpx 0.18.6 → 0.18.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/doc/release_notes/0_18_5.md +2 -2
- data/doc/release_notes/0_18_7.md +5 -0
- data/lib/httpx/connection/http1.rb +5 -5
- data/lib/httpx/connection/http2.rb +1 -5
- data/lib/httpx/connection.rb +17 -9
- data/lib/httpx/io/tcp.rb +3 -1
- data/lib/httpx/plugins/internal_telemetry.rb +1 -1
- data/lib/httpx/plugins/multipart/mime_type_detector.rb +5 -1
- data/lib/httpx/plugins/proxy/http.rb +10 -23
- data/lib/httpx/plugins/proxy/socks4.rb +1 -1
- data/lib/httpx/plugins/proxy/socks5.rb +1 -1
- data/lib/httpx/plugins/proxy.rb +18 -7
- data/lib/httpx/resolver/https.rb +1 -1
- data/lib/httpx/resolver/native.rb +9 -2
- data/lib/httpx/resolver/resolver_mixin.rb +1 -1
- data/lib/httpx/resolver/system.rb +1 -1
- data/lib/httpx/session.rb +1 -15
- data/lib/httpx/session_extensions.rb +19 -0
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +1 -0
- data/sig/connection/http1.rbs +0 -2
- data/sig/connection/http2.rbs +2 -2
- data/sig/connection.rbs +1 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab9b9577b0e266b140e21030307b3f2436af346a13f1e0931af05020ba42f7e6
|
4
|
+
data.tar.gz: c5d043448ef41b0532c08d1622540d80c68511ef59cffcc810a6f8bd92f348d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b4ec58f2ab031d23f28a86bc47b40d0f0d79eea9aea64590b0cc3d07269738513de1364608e0c0282a6956d816b78b900520dbad4daab1f73522b8b7f73d138
|
7
|
+
data.tar.gz: f2d2c297b530bfb3567ebcd1678bad1d729187dd75c9107839c925def1a708c4648fe80df614a01af02bce309594e256e274e042f3c6b8347182aebff1df9935
|
data/doc/release_notes/0_18_5.md
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
## Improvements
|
4
4
|
|
5
5
|
* ruby 3.1 is now officially supported.
|
6
|
-
* when user sets a `Host` header for an HTTP/2 request, this will be used in the `:authority` HTTP/2 pseudo-header, instead of silently ignored (mimicking what "curl" does).
|
6
|
+
* when a user sets a `Host` header for an HTTP/2 request, this will be used in the `:authority` HTTP/2 pseudo-header, instead of silently ignored (mimicking what "curl" does).
|
7
7
|
|
8
8
|
## Bugfixes
|
9
9
|
|
10
|
-
* fixed "throw outside of catch block" error happening when pipelining requests on an HTTP/1
|
10
|
+
* fixed "throw outside of catch block" error happening when pipelining requests on an HTTP/1 connection and resulting in a timeout.
|
@@ -297,10 +297,6 @@ module HTTPX
|
|
297
297
|
extra_headers
|
298
298
|
end
|
299
299
|
|
300
|
-
def headline_uri(request)
|
301
|
-
request.path
|
302
|
-
end
|
303
|
-
|
304
300
|
def handle(request)
|
305
301
|
catch(:buffer_full) do
|
306
302
|
request.transition(:headers)
|
@@ -314,8 +310,12 @@ module HTTPX
|
|
314
310
|
end
|
315
311
|
end
|
316
312
|
|
313
|
+
def join_headline(request)
|
314
|
+
"#{request.verb.to_s.upcase} #{request.path} HTTP/#{@version.join(".")}"
|
315
|
+
end
|
316
|
+
|
317
317
|
def join_headers(request)
|
318
|
-
headline =
|
318
|
+
headline = join_headline(request)
|
319
319
|
@buffer << headline << CRLF
|
320
320
|
log(color: :yellow) { "<- HEADLINE: #{headline.chomp.inspect}" }
|
321
321
|
extra_headers = set_protocol_headers(request)
|
@@ -158,10 +158,6 @@ module HTTPX
|
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
161
|
-
def headline_uri(request)
|
162
|
-
request.path
|
163
|
-
end
|
164
|
-
|
165
161
|
def handle(request, stream)
|
166
162
|
catch(:buffer_full) do
|
167
163
|
request.transition(:headers)
|
@@ -213,7 +209,7 @@ module HTTPX
|
|
213
209
|
{
|
214
210
|
":scheme" => request.scheme,
|
215
211
|
":method" => request.verb.to_s.upcase,
|
216
|
-
":path" =>
|
212
|
+
":path" => request.path,
|
217
213
|
":authority" => request.authority,
|
218
214
|
}
|
219
215
|
end
|
data/lib/httpx/connection.rb
CHANGED
@@ -44,7 +44,7 @@ module HTTPX
|
|
44
44
|
|
45
45
|
def_delegator :@write_buffer, :empty?
|
46
46
|
|
47
|
-
attr_reader :origin, :state, :pending, :options
|
47
|
+
attr_reader :origin, :origins, :state, :pending, :options
|
48
48
|
|
49
49
|
attr_writer :timers
|
50
50
|
|
@@ -489,6 +489,18 @@ module HTTPX
|
|
489
489
|
end
|
490
490
|
|
491
491
|
def transition(nextstate)
|
492
|
+
handle_transition(nextstate)
|
493
|
+
rescue Errno::ECONNREFUSED,
|
494
|
+
Errno::EADDRNOTAVAIL,
|
495
|
+
Errno::EHOSTUNREACH,
|
496
|
+
TLSError => e
|
497
|
+
# connect errors, exit gracefully
|
498
|
+
handle_error(e)
|
499
|
+
@state = :closed
|
500
|
+
emit(:close)
|
501
|
+
end
|
502
|
+
|
503
|
+
def handle_transition(nextstate)
|
492
504
|
case nextstate
|
493
505
|
when :idle
|
494
506
|
@timeout = @current_timeout = @options.timeout[:connect_timeout]
|
@@ -525,14 +537,6 @@ module HTTPX
|
|
525
537
|
emit(:activate)
|
526
538
|
end
|
527
539
|
@state = nextstate
|
528
|
-
rescue Errno::ECONNREFUSED,
|
529
|
-
Errno::EADDRNOTAVAIL,
|
530
|
-
Errno::EHOSTUNREACH,
|
531
|
-
TLSError => e
|
532
|
-
# connect errors, exit gracefully
|
533
|
-
handle_error(e)
|
534
|
-
@state = :closed
|
535
|
-
emit(:close)
|
536
540
|
end
|
537
541
|
|
538
542
|
def purge_after_closed
|
@@ -550,6 +554,10 @@ module HTTPX
|
|
550
554
|
ex.set_backtrace(error.backtrace)
|
551
555
|
error = ex
|
552
556
|
else
|
557
|
+
# inactive connections do not contribute to the select loop, therefore
|
558
|
+
# they should fail due to such errors.
|
559
|
+
return if @state == :inactive
|
560
|
+
|
553
561
|
if @timeout
|
554
562
|
@timeout -= error.timeout
|
555
563
|
return unless @timeout <= 0
|
data/lib/httpx/io/tcp.rb
CHANGED
@@ -14,9 +14,13 @@ module HTTPX
|
|
14
14
|
def call(file, _)
|
15
15
|
return nil if file.eof? # FileMagic returns "application/x-empty" for empty files
|
16
16
|
|
17
|
-
FileMagic.open(FileMagic::MAGIC_MIME_TYPE) do |filemagic|
|
17
|
+
mime = FileMagic.open(FileMagic::MAGIC_MIME_TYPE) do |filemagic|
|
18
18
|
filemagic.buffer(file.read(MAGIC_NUMBER))
|
19
19
|
end
|
20
|
+
|
21
|
+
file.rewind
|
22
|
+
|
23
|
+
mime
|
20
24
|
end
|
21
25
|
elsif defined?(Marcel)
|
22
26
|
def call(file, filename)
|
@@ -13,7 +13,7 @@ module HTTPX
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
def
|
16
|
+
def handle_transition(nextstate)
|
17
17
|
return super unless @options.proxy && @options.proxy.uri.scheme == "http"
|
18
18
|
|
19
19
|
case nextstate
|
@@ -23,7 +23,8 @@ module HTTPX
|
|
23
23
|
@io.connect
|
24
24
|
return unless @io.connected?
|
25
25
|
|
26
|
-
@parser =
|
26
|
+
@parser = registry(@io.protocol).new(@write_buffer, @options.merge(max_concurrent_requests: 1))
|
27
|
+
@parser.extend(ProxyParser)
|
27
28
|
@parser.once(:response, &method(:__http_on_connect))
|
28
29
|
@parser.on(:close) { transition(:closing) }
|
29
30
|
__http_proxy_connect
|
@@ -36,7 +37,7 @@ module HTTPX
|
|
36
37
|
@parser.close
|
37
38
|
@parser = nil
|
38
39
|
when :idle
|
39
|
-
@parser
|
40
|
+
@parser.callbacks.clear
|
40
41
|
set_parser_callbacks(@parser)
|
41
42
|
end
|
42
43
|
end
|
@@ -54,7 +55,7 @@ module HTTPX
|
|
54
55
|
@inflight += 1
|
55
56
|
parser.send(connect_request)
|
56
57
|
else
|
57
|
-
|
58
|
+
handle_transition(:connected)
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
@@ -76,9 +77,11 @@ module HTTPX
|
|
76
77
|
end
|
77
78
|
end
|
78
79
|
|
79
|
-
|
80
|
-
def
|
81
|
-
request.
|
80
|
+
module ProxyParser
|
81
|
+
def join_headline(request)
|
82
|
+
return super if request.verb == :connect
|
83
|
+
|
84
|
+
"#{request.verb.to_s.upcase} #{request.uri} HTTP/#{@version.join(".")}"
|
82
85
|
end
|
83
86
|
|
84
87
|
def set_protocol_headers(request)
|
@@ -91,22 +94,6 @@ module HTTPX
|
|
91
94
|
end
|
92
95
|
end
|
93
96
|
|
94
|
-
class ConnectProxyParser < ProxyParser
|
95
|
-
attr_reader :pending
|
96
|
-
|
97
|
-
def headline_uri(request)
|
98
|
-
return super unless request.verb == :connect
|
99
|
-
|
100
|
-
tunnel = request.path
|
101
|
-
log { "establishing HTTP proxy tunnel to #{tunnel}" }
|
102
|
-
tunnel
|
103
|
-
end
|
104
|
-
|
105
|
-
def empty?
|
106
|
-
@requests.reject { |r| r.verb == :connect }.empty? || @requests.all? { |request| !request.response.nil? }
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
97
|
class ConnectRequest < Request
|
111
98
|
def initialize(uri, _options)
|
112
99
|
super(:connect, uri, {})
|
data/lib/httpx/plugins/proxy.rb
CHANGED
@@ -85,7 +85,7 @@ module HTTPX
|
|
85
85
|
end
|
86
86
|
uris
|
87
87
|
end
|
88
|
-
|
88
|
+
{ uri: @_proxy_uris.first } unless @_proxy_uris.empty?
|
89
89
|
end
|
90
90
|
|
91
91
|
def find_connection(request, connections, options)
|
@@ -109,8 +109,10 @@ module HTTPX
|
|
109
109
|
return super unless proxy
|
110
110
|
|
111
111
|
connection = options.connection_class.new("tcp", uri, options)
|
112
|
-
|
113
|
-
|
112
|
+
catch(:coalesced) do
|
113
|
+
pool.init_connection(connection, options)
|
114
|
+
connection
|
115
|
+
end
|
114
116
|
end
|
115
117
|
|
116
118
|
def fetch_response(request, connections, options)
|
@@ -181,11 +183,20 @@ module HTTPX
|
|
181
183
|
super && @options.proxy == options.proxy
|
182
184
|
end
|
183
185
|
|
184
|
-
|
185
|
-
def coalescable?(*)
|
186
|
+
def coalescable?(connection)
|
186
187
|
return super unless @options.proxy
|
187
188
|
|
188
|
-
|
189
|
+
if @io.protocol == "h2" &&
|
190
|
+
@origin.scheme == "https" &&
|
191
|
+
connection.origin.scheme == "https" &&
|
192
|
+
@io.can_verify_peer?
|
193
|
+
# in proxied connections, .origin is the proxy ; Given names
|
194
|
+
# are stored in .origins, this is what is used.
|
195
|
+
origin = URI(connection.origins.first)
|
196
|
+
@io.verify_hostname(origin.host)
|
197
|
+
else
|
198
|
+
@origin == connection.origin
|
199
|
+
end
|
189
200
|
end
|
190
201
|
|
191
202
|
def send(request)
|
@@ -234,7 +245,7 @@ module HTTPX
|
|
234
245
|
end
|
235
246
|
end
|
236
247
|
|
237
|
-
def
|
248
|
+
def handle_transition(nextstate)
|
238
249
|
return super unless @options.proxy
|
239
250
|
|
240
251
|
case nextstate
|
data/lib/httpx/resolver/https.rb
CHANGED
@@ -29,7 +29,7 @@ module HTTPX
|
|
29
29
|
attr_writer :pool
|
30
30
|
|
31
31
|
def initialize(options)
|
32
|
-
@options = Options.new(options)
|
32
|
+
@options = HTTPX::Options.new(options)
|
33
33
|
@resolver_options = DEFAULTS.merge(@options.resolver_options)
|
34
34
|
@_record_types = Hash.new { |types, host| types[host] = @resolver_options[:record_types].dup }
|
35
35
|
@queries = {}
|
@@ -50,7 +50,7 @@ module HTTPX
|
|
50
50
|
attr_reader :state
|
51
51
|
|
52
52
|
def initialize(options)
|
53
|
-
@options = Options.new(options)
|
53
|
+
@options = HTTPX::Options.new(options)
|
54
54
|
@ns_index = 0
|
55
55
|
@resolver_options = DEFAULTS.merge(@options.resolver_options)
|
56
56
|
@nameserver = @resolver_options[:nameserver]
|
@@ -200,6 +200,7 @@ module HTTPX
|
|
200
200
|
hostname, connection = @queries.first
|
201
201
|
if @_record_types[hostname].empty?
|
202
202
|
@queries.delete(hostname)
|
203
|
+
@timeouts.delete(hostname)
|
203
204
|
@connections.delete(connection)
|
204
205
|
ex = NativeResolveError.new(connection, hostname, e.message)
|
205
206
|
ex.set_backtrace(e.backtrace)
|
@@ -213,6 +214,7 @@ module HTTPX
|
|
213
214
|
if @_record_types[hostname].empty?
|
214
215
|
@queries.delete(hostname)
|
215
216
|
@_record_types.delete(hostname)
|
217
|
+
@timeouts.delete(hostname)
|
216
218
|
@connections.delete(connection)
|
217
219
|
|
218
220
|
raise NativeResolveError.new(connection, hostname)
|
@@ -236,13 +238,18 @@ module HTTPX
|
|
236
238
|
end
|
237
239
|
|
238
240
|
if address.key?("alias") # CNAME
|
239
|
-
|
241
|
+
# clean up intermediate queries
|
242
|
+
@timeouts.delete(address["name"]) unless connection.origin.host == address["name"]
|
243
|
+
|
244
|
+
if catch(:coalesced) { early_resolve(connection, hostname: address["alias"]) }
|
245
|
+
@timeouts.delete(connection.origin.host)
|
240
246
|
@connections.delete(connection)
|
241
247
|
else
|
242
248
|
resolve(connection, address["alias"])
|
243
249
|
return
|
244
250
|
end
|
245
251
|
else
|
252
|
+
@timeouts.delete(connection.origin.host)
|
246
253
|
@connections.delete(connection)
|
247
254
|
Resolver.cached_lookup_set(connection.origin.host, addresses) if @resolver_options[:cache]
|
248
255
|
emit_addresses(connection, addresses.map { |addr| addr["data"] })
|
@@ -32,7 +32,7 @@ module HTTPX
|
|
32
32
|
end
|
33
33
|
log { "resolver: answer #{connection.origin.host}: #{addresses.inspect}" }
|
34
34
|
connection.addresses = addresses
|
35
|
-
|
35
|
+
emit(:resolve, connection)
|
36
36
|
end
|
37
37
|
|
38
38
|
def early_resolve(connection, hostname: connection.origin.host)
|
data/lib/httpx/session.rb
CHANGED
@@ -207,7 +207,7 @@ module HTTPX
|
|
207
207
|
|
208
208
|
return responses unless request
|
209
209
|
|
210
|
-
pool.next_tick until (response = fetch_response(request, connections, request.options))
|
210
|
+
catch(:coalesced) { pool.next_tick } until (response = fetch_response(request, connections, request.options))
|
211
211
|
|
212
212
|
responses << response
|
213
213
|
requests.shift
|
@@ -309,18 +309,4 @@ module HTTPX
|
|
309
309
|
# :nocov:
|
310
310
|
end
|
311
311
|
end
|
312
|
-
|
313
|
-
unless ENV.grep(/https?_proxy$/i).empty?
|
314
|
-
proxy_session = plugin(:proxy)
|
315
|
-
::HTTPX.send(:remove_const, :Session)
|
316
|
-
::HTTPX.send(:const_set, :Session, proxy_session.class)
|
317
|
-
end
|
318
|
-
|
319
|
-
# :nocov:
|
320
|
-
if Session.default_options.debug_level > 2
|
321
|
-
proxy_session = plugin(:internal_telemetry)
|
322
|
-
::HTTPX.send(:remove_const, :Session)
|
323
|
-
::HTTPX.send(:const_set, :Session, proxy_session.class)
|
324
|
-
end
|
325
|
-
# :nocov:
|
326
312
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTPX
|
4
|
+
unless ENV.keys.grep(/\Ahttps?_proxy\z/i).empty?
|
5
|
+
proxy_session = plugin(:proxy)
|
6
|
+
remove_const(:Session)
|
7
|
+
const_set(:Session, proxy_session.class)
|
8
|
+
remove_const(:Options)
|
9
|
+
const_set(:Options, proxy_session.class.default_options.class)
|
10
|
+
end
|
11
|
+
|
12
|
+
# :nocov:
|
13
|
+
if Session.default_options.debug_level > 2
|
14
|
+
proxy_session = plugin(:internal_telemetry)
|
15
|
+
remove_const(:Session)
|
16
|
+
const_set(:Session, proxy_session.class)
|
17
|
+
end
|
18
|
+
# :nocov:
|
19
|
+
end
|
data/lib/httpx/version.rb
CHANGED
data/lib/httpx.rb
CHANGED
data/sig/connection/http1.rbs
CHANGED
data/sig/connection/http2.rbs
CHANGED
@@ -46,8 +46,6 @@ module HTTPX
|
|
46
46
|
|
47
47
|
def send_pending: () -> void
|
48
48
|
|
49
|
-
def headline_uri: (Request) -> String
|
50
|
-
|
51
49
|
def set_protocol_headers: (Request) -> _Each[[String, String]]
|
52
50
|
|
53
51
|
def handle: (Request request, HTTP2Next::Stream stream) -> void
|
@@ -56,6 +54,8 @@ module HTTPX
|
|
56
54
|
|
57
55
|
def handle_stream: (HTTP2Next::Stream stream, Request request) -> void
|
58
56
|
|
57
|
+
def join_headline: (Request request) -> String
|
58
|
+
|
59
59
|
def join_headers: (HTTP2Next::Stream stream, Request request) -> void
|
60
60
|
|
61
61
|
def join_trailers: (HTTP2Next::Stream stream, Request request) -> void
|
data/sig/connection.rbs
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httpx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.18.
|
4
|
+
version: 0.18.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Cardoso
|
@@ -69,6 +69,7 @@ extra_rdoc_files:
|
|
69
69
|
- doc/release_notes/0_18_4.md
|
70
70
|
- doc/release_notes/0_18_5.md
|
71
71
|
- doc/release_notes/0_18_6.md
|
72
|
+
- doc/release_notes/0_18_7.md
|
72
73
|
- doc/release_notes/0_1_0.md
|
73
74
|
- doc/release_notes/0_2_0.md
|
74
75
|
- doc/release_notes/0_2_1.md
|
@@ -131,6 +132,7 @@ files:
|
|
131
132
|
- doc/release_notes/0_18_4.md
|
132
133
|
- doc/release_notes/0_18_5.md
|
133
134
|
- doc/release_notes/0_18_6.md
|
135
|
+
- doc/release_notes/0_18_7.md
|
134
136
|
- doc/release_notes/0_1_0.md
|
135
137
|
- doc/release_notes/0_2_0.md
|
136
138
|
- doc/release_notes/0_2_1.md
|
@@ -234,6 +236,7 @@ files:
|
|
234
236
|
- lib/httpx/selector.rb
|
235
237
|
- lib/httpx/session.rb
|
236
238
|
- lib/httpx/session2.rb
|
239
|
+
- lib/httpx/session_extensions.rb
|
237
240
|
- lib/httpx/timers.rb
|
238
241
|
- lib/httpx/transcoder.rb
|
239
242
|
- lib/httpx/transcoder/body.rb
|