httpx 0.10.0 → 0.10.1
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_10_1.md +39 -0
- data/lib/httpx/chainable.rb +7 -6
- data/lib/httpx/connection.rb +4 -15
- data/lib/httpx/connection/http1.rb +14 -1
- data/lib/httpx/connection/http2.rb +11 -12
- data/lib/httpx/errors.rb +1 -1
- data/lib/httpx/plugins/multipart.rb +15 -1
- data/lib/httpx/plugins/proxy.rb +16 -2
- data/lib/httpx/plugins/proxy/socks4.rb +14 -16
- data/lib/httpx/pool.rb +8 -14
- data/lib/httpx/request.rb +1 -1
- data/lib/httpx/resolver.rb +0 -2
- data/lib/httpx/resolver/https.rb +15 -22
- data/lib/httpx/resolver/native.rb +12 -13
- data/lib/httpx/resolver/resolver_mixin.rb +4 -2
- data/lib/httpx/resolver/system.rb +2 -2
- data/lib/httpx/selector.rb +8 -13
- data/lib/httpx/session.rb +9 -3
- data/lib/httpx/transcoder.rb +18 -0
- data/lib/httpx/transcoder/form.rb +9 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/connection.rbs +84 -1
- data/sig/connection/http1.rbs +66 -0
- data/sig/connection/http2.rbs +74 -0
- data/sig/httpx.rbs +1 -0
- data/sig/options.rbs +3 -3
- data/sig/plugins/basic_authentication.rbs +1 -1
- data/sig/plugins/compression.rbs +1 -1
- data/sig/plugins/compression/brotli.rbs +1 -1
- data/sig/plugins/compression/deflate.rbs +1 -1
- data/sig/plugins/compression/gzip.rbs +1 -1
- data/sig/plugins/h2c.rbs +1 -1
- data/sig/plugins/multipart.rbs +4 -2
- data/sig/plugins/persistent.rbs +1 -1
- data/sig/plugins/proxy.rbs +2 -2
- data/sig/plugins/proxy/ssh.rbs +1 -1
- data/sig/plugins/rate_limiter.rbs +1 -1
- data/sig/pool.rbs +36 -2
- data/sig/request.rbs +1 -1
- data/sig/resolver.rbs +26 -0
- data/sig/resolver/https.rbs +49 -0
- data/sig/resolver/native.rbs +60 -0
- data/sig/resolver/resolver_mixin.rbs +27 -0
- data/sig/resolver/system.rbs +17 -0
- data/sig/response.rbs +1 -1
- data/sig/selector.rbs +20 -0
- data/sig/session.rbs +2 -2
- data/sig/transcoder.rbs +4 -2
- data/sig/transcoder/form.rbs +1 -1
- metadata +11 -4
- data/lib/httpx/resolver/options.rb +0 -25
- data/sig/test.rbs +0 -9
@@ -15,7 +15,6 @@ module HTTPX
|
|
15
15
|
"AAAA" => Resolv::DNS::Resource::IN::AAAA,
|
16
16
|
}.freeze
|
17
17
|
|
18
|
-
# :nocov:
|
19
18
|
DEFAULTS = if RUBY_VERSION < "2.2"
|
20
19
|
{
|
21
20
|
**Resolv::DNS::Config.default_config_hash,
|
@@ -44,7 +43,6 @@ module HTTPX
|
|
44
43
|
false
|
45
44
|
end
|
46
45
|
end if DEFAULTS[:nameserver]
|
47
|
-
# :nocov:
|
48
46
|
|
49
47
|
DNS_PORT = 53
|
50
48
|
|
@@ -53,15 +51,15 @@ module HTTPX
|
|
53
51
|
def initialize(options)
|
54
52
|
@options = Options.new(options)
|
55
53
|
@ns_index = 0
|
56
|
-
@resolver_options =
|
57
|
-
@nameserver = @resolver_options
|
58
|
-
@_timeouts = Array(@resolver_options
|
54
|
+
@resolver_options = DEFAULTS.merge(@options.resolver_options)
|
55
|
+
@nameserver = @resolver_options[:nameserver]
|
56
|
+
@_timeouts = Array(@resolver_options[:timeouts])
|
59
57
|
@timeouts = Hash.new { |timeouts, host| timeouts[host] = @_timeouts.dup }
|
60
|
-
@_record_types = Hash.new { |types, host| types[host] = @resolver_options
|
58
|
+
@_record_types = Hash.new { |types, host| types[host] = @resolver_options[:record_types].dup }
|
61
59
|
@connections = []
|
62
60
|
@queries = {}
|
63
61
|
@read_buffer = "".b
|
64
|
-
@write_buffer = Buffer.new(@resolver_options
|
62
|
+
@write_buffer = Buffer.new(@resolver_options[:packet_size])
|
65
63
|
@state = :idle
|
66
64
|
end
|
67
65
|
|
@@ -111,9 +109,9 @@ module HTTPX
|
|
111
109
|
return if early_resolve(connection)
|
112
110
|
|
113
111
|
if @nameserver.nil?
|
114
|
-
ex = ResolveError.new("
|
112
|
+
ex = ResolveError.new("No available nameserver")
|
115
113
|
ex.set_backtrace(caller)
|
116
|
-
|
114
|
+
throw(:resolve_error, ex)
|
117
115
|
else
|
118
116
|
@connections << connection
|
119
117
|
resolve
|
@@ -164,7 +162,7 @@ module HTTPX
|
|
164
162
|
connections.each { |ch| resolve(ch) }
|
165
163
|
end
|
166
164
|
|
167
|
-
def dread(wsize = @resolver_options
|
165
|
+
def dread(wsize = @resolver_options[:packet_size])
|
168
166
|
loop do
|
169
167
|
siz = @io.read(wsize, @read_buffer)
|
170
168
|
return unless siz && siz.positive?
|
@@ -199,13 +197,14 @@ module HTTPX
|
|
199
197
|
end
|
200
198
|
end
|
201
199
|
|
202
|
-
if addresses.empty?
|
200
|
+
if addresses.nil? || addresses.empty?
|
203
201
|
hostname, connection = @queries.first
|
204
202
|
@_record_types[hostname].shift
|
205
203
|
if @_record_types[hostname].empty?
|
206
204
|
@queries.delete(hostname)
|
207
205
|
@_record_types.delete(hostname)
|
208
206
|
@connections.delete(connection)
|
207
|
+
|
209
208
|
raise NativeResolveError.new(connection, hostname)
|
210
209
|
end
|
211
210
|
else
|
@@ -223,7 +222,7 @@ module HTTPX
|
|
223
222
|
end
|
224
223
|
else
|
225
224
|
@connections.delete(connection)
|
226
|
-
Resolver.cached_lookup_set(connection.origin.host, addresses) if @resolver_options
|
225
|
+
Resolver.cached_lookup_set(connection.origin.host, addresses) if @resolver_options[:cache]
|
227
226
|
emit_addresses(connection, addresses.map { |addr| addr["data"] })
|
228
227
|
end
|
229
228
|
end
|
@@ -243,7 +242,7 @@ module HTTPX
|
|
243
242
|
log { "resolver: resolve IDN #{connection.origin.non_ascii_hostname} as #{hostname}" } if connection.origin.non_ascii_hostname
|
244
243
|
end
|
245
244
|
@queries[hostname] = connection
|
246
|
-
type = @_record_types[hostname].first
|
245
|
+
type = @_record_types[hostname].first || "A"
|
247
246
|
log { "resolver: query #{type} for #{hostname}" }
|
248
247
|
begin
|
249
248
|
@write_buffer << Resolver.encode_dns_query(hostname, type: RECORD_TYPES[type])
|
@@ -38,7 +38,7 @@ module HTTPX
|
|
38
38
|
def early_resolve(connection, hostname: connection.origin.host)
|
39
39
|
addresses = connection.addresses ||
|
40
40
|
ip_resolve(hostname) ||
|
41
|
-
(@resolver_options
|
41
|
+
(@resolver_options[:cache] && Resolver.cached_lookup(hostname)) ||
|
42
42
|
system_resolve(hostname)
|
43
43
|
return unless addresses
|
44
44
|
|
@@ -57,11 +57,13 @@ module HTTPX
|
|
57
57
|
ips.map { |ip| IPAddr.new(ip) }
|
58
58
|
end
|
59
59
|
|
60
|
-
def emit_resolve_error(connection, hostname, ex = nil)
|
60
|
+
def emit_resolve_error(connection, hostname = connection.origin.host, ex = nil)
|
61
61
|
emit(:error, connection, resolve_error(hostname, ex))
|
62
62
|
end
|
63
63
|
|
64
64
|
def resolve_error(hostname, ex = nil)
|
65
|
+
return ex if ex.is_a?(ResolveError)
|
66
|
+
|
65
67
|
message = ex ? ex.message : "Can't resolve #{hostname}"
|
66
68
|
error = ResolveError.new(message)
|
67
69
|
error.set_backtrace(ex ? ex.backtrace : caller)
|
@@ -14,9 +14,9 @@ module HTTPX
|
|
14
14
|
|
15
15
|
def initialize(options)
|
16
16
|
@options = Options.new(options)
|
17
|
-
@resolver_options =
|
17
|
+
@resolver_options = @options.resolver_options
|
18
18
|
@state = :idle
|
19
|
-
resolv_options = @resolver_options.
|
19
|
+
resolv_options = @resolver_options.dup
|
20
20
|
timeouts = resolv_options.delete(:timeouts)
|
21
21
|
resolv_options.delete(:cache)
|
22
22
|
@resolver = Resolv::DNS.new(resolv_options.empty? ? nil : resolv_options)
|
data/lib/httpx/selector.rb
CHANGED
@@ -4,19 +4,14 @@ require "io/wait"
|
|
4
4
|
|
5
5
|
module IOExtensions
|
6
6
|
refine IO do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
return unless r || w
|
17
|
-
|
18
|
-
self
|
19
|
-
end
|
7
|
+
# provides a fallback for rubies where IO#wait isn't implemented,
|
8
|
+
# but IO#wait_readable and IO#wait_writable are.
|
9
|
+
def wait(timeout = nil, _mode = :read_write)
|
10
|
+
r, w = IO.select([self], [self], nil, timeout)
|
11
|
+
|
12
|
+
return unless r || w
|
13
|
+
|
14
|
+
self
|
20
15
|
end
|
21
16
|
end
|
22
17
|
end
|
data/lib/httpx/session.rb
CHANGED
@@ -77,10 +77,16 @@ module HTTPX
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def set_connection_callbacks(connection, connections, options)
|
80
|
-
connection.on(:
|
81
|
-
other_connection =
|
80
|
+
connection.on(:misdirected) do |misdirected_request|
|
81
|
+
other_connection = connection.create_idle(ssl: { alpn_protocols: %w[http/1.1] })
|
82
|
+
other_connection.merge(connection)
|
83
|
+
catch(:coalesced) do
|
84
|
+
pool.init_connection(other_connection, options)
|
85
|
+
end
|
86
|
+
set_connection_callbacks(other_connection, connections, options)
|
82
87
|
connections << other_connection
|
83
|
-
|
88
|
+
misdirected_request.transition(:idle)
|
89
|
+
other_connection.send(misdirected_request)
|
84
90
|
end
|
85
91
|
connection.on(:altsvc) do |alt_origin, origin, alt_params|
|
86
92
|
other_connection = build_altsvc_connection(connection, connections, alt_origin, origin, alt_params, options)
|
data/lib/httpx/transcoder.rb
CHANGED
@@ -3,6 +3,24 @@
|
|
3
3
|
module HTTPX
|
4
4
|
module Transcoder
|
5
5
|
extend Registry
|
6
|
+
|
7
|
+
def self.normalize_keys(key, value, &block)
|
8
|
+
if value.respond_to?(:to_ary)
|
9
|
+
if value.empty?
|
10
|
+
block.call("#{key}[]")
|
11
|
+
else
|
12
|
+
value.to_ary.each do |element|
|
13
|
+
normalize_keys("#{key}[]", element, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
elsif value.respond_to?(:to_hash)
|
17
|
+
value.to_hash.each do |child_key, child_value|
|
18
|
+
normalize_keys("#{key}[#{child_key}]", child_value, &block)
|
19
|
+
end
|
20
|
+
else
|
21
|
+
block.call(key.to_s, value)
|
22
|
+
end
|
23
|
+
end
|
6
24
|
end
|
7
25
|
end
|
8
26
|
|
@@ -12,10 +12,18 @@ module HTTPX::Transcoder
|
|
12
12
|
|
13
13
|
def_delegator :@raw, :to_s
|
14
14
|
|
15
|
+
def_delegator :@raw, :to_str
|
16
|
+
|
15
17
|
def_delegator :@raw, :bytesize
|
16
18
|
|
17
19
|
def initialize(form)
|
18
|
-
@raw =
|
20
|
+
@raw = form.each_with_object("".b) do |(key, val), buf|
|
21
|
+
HTTPX::Transcoder.normalize_keys(key, val) do |k, v|
|
22
|
+
buf << "&" unless buf.empty?
|
23
|
+
buf << URI.encode_www_form_component(k)
|
24
|
+
buf << "=#{URI.encode_www_form_component(v.to_s)}" unless v.nil?
|
25
|
+
end
|
26
|
+
end
|
19
27
|
end
|
20
28
|
|
21
29
|
def content_type
|
data/lib/httpx/version.rb
CHANGED
data/sig/connection.rbs
CHANGED
@@ -1,2 +1,85 @@
|
|
1
|
-
|
1
|
+
module HTTPX
|
2
|
+
class Connection
|
3
|
+
interface _Parser
|
4
|
+
|
5
|
+
def on: (Symbol) { (*untyped) -> void } -> void
|
6
|
+
def empty?: () -> bool
|
7
|
+
def close: () -> void
|
8
|
+
def consume: () -> void
|
9
|
+
def <<: (string) -> void
|
10
|
+
end
|
11
|
+
|
12
|
+
include Loggable
|
13
|
+
include Callbacks
|
14
|
+
extend HTTPX::Registry[String, Class]
|
15
|
+
|
16
|
+
attr_reader origin: generic_uri
|
17
|
+
attr_reader state: Symbol
|
18
|
+
attr_reader pending: Array[Request]
|
19
|
+
attr_reader options: options
|
20
|
+
|
21
|
+
def addresses: () -> Array[ipaddr]?
|
22
|
+
|
23
|
+
def addresses=: (Array[ipaddr]) -> void
|
24
|
+
|
25
|
+
def match?: (generic_uri, options) -> bool
|
26
|
+
|
27
|
+
def mergeable?: (Connection) -> bool
|
28
|
+
|
29
|
+
def coalescable?: (Connection) -> bool
|
30
|
+
|
31
|
+
def create_idle: (options) -> Connection
|
32
|
+
| () -> Connection
|
33
|
+
|
34
|
+
def merge: (Connection) -> void
|
35
|
+
|
36
|
+
def purge_pending: () { (Request) -> void } -> void
|
37
|
+
|
38
|
+
def match_altsvcs?: (generic_uri) -> bool
|
39
|
+
|
40
|
+
def connecting?: () -> bool
|
41
|
+
def inflight?: () -> boolish
|
42
|
+
|
43
|
+
def interests: () -> io_interests?
|
44
|
+
|
45
|
+
def to_io: () -> _ToIO
|
46
|
+
|
47
|
+
def call: () -> void
|
48
|
+
|
49
|
+
def close: () -> void
|
50
|
+
def reset: () -> void
|
51
|
+
|
52
|
+
def send: (Request) -> void
|
53
|
+
|
54
|
+
def timeout: () -> Numeric?
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def initialize: (String, generic_uri, options) -> untyped
|
59
|
+
|
60
|
+
def connect: () -> void
|
61
|
+
|
62
|
+
def exhausted?: () -> boolish
|
63
|
+
|
64
|
+
def consume: () -> void
|
65
|
+
|
66
|
+
def send_pending: () -> void
|
67
|
+
|
68
|
+
def parser: () -> _Parser
|
69
|
+
|
70
|
+
def build_parser: () -> _Parser
|
71
|
+
| (String) -> _Parser
|
72
|
+
|
73
|
+
def set_parser_callbacks: (_Parser) -> void
|
74
|
+
|
75
|
+
def transition: (Symbol) -> void
|
76
|
+
|
77
|
+
def handle_response: () -> void
|
78
|
+
|
79
|
+
def on_error: (StandardError) -> void
|
80
|
+
|
81
|
+
def handle_error: (StandardError) -> void
|
82
|
+
|
83
|
+
def total_timeout: () -> Timers::Timer?
|
84
|
+
end
|
2
85
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module HTTPX
|
2
|
+
class Connection::HTTP1
|
3
|
+
include Callbacks
|
4
|
+
include Loggable
|
5
|
+
|
6
|
+
attr_reader pending: Array[Request]
|
7
|
+
|
8
|
+
@options: Options
|
9
|
+
@max_concurrent_requests: Integer
|
10
|
+
@max_requests: Integer
|
11
|
+
@parser: HTTP1
|
12
|
+
@buffer: Buffer
|
13
|
+
|
14
|
+
def interests: () -> io_interests?
|
15
|
+
|
16
|
+
def reset: () -> void
|
17
|
+
|
18
|
+
def close: () -> void
|
19
|
+
|
20
|
+
def empty?: () -> bool
|
21
|
+
|
22
|
+
def exhausted?: () -> bool
|
23
|
+
|
24
|
+
def <<: (String) -> void
|
25
|
+
|
26
|
+
def send: (Request) -> void
|
27
|
+
|
28
|
+
def consume: () -> void
|
29
|
+
|
30
|
+
def handle_error: (StandardError ex) -> void
|
31
|
+
|
32
|
+
def on_headers: (Hash[String, Array[String]] headers) -> void
|
33
|
+
|
34
|
+
def on_trailers: (Array[String, String] headers) -> void
|
35
|
+
|
36
|
+
def on_data: (string chunk) -> void
|
37
|
+
|
38
|
+
def on_complete: () -> void
|
39
|
+
|
40
|
+
def dispatch: () -> void
|
41
|
+
|
42
|
+
def ping: () -> void
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def initialize: (Buffer, options) -> untyped
|
47
|
+
|
48
|
+
def manage_connection: (Response) -> void
|
49
|
+
|
50
|
+
def disable: () -> void
|
51
|
+
|
52
|
+
def disable_pipelining: () -> void
|
53
|
+
|
54
|
+
def set_request_headers: (Request) -> void
|
55
|
+
|
56
|
+
def headline_uri: (Request) -> String
|
57
|
+
|
58
|
+
def handle: (Request request) -> void
|
59
|
+
|
60
|
+
def join_headers: (Request request) -> void
|
61
|
+
|
62
|
+
def join_body: (Request request) -> void
|
63
|
+
|
64
|
+
def capitalized: (String field) -> String
|
65
|
+
end
|
66
|
+
end
|
data/sig/connection/http2.rbs
CHANGED
@@ -1,4 +1,78 @@
|
|
1
1
|
module HTTPX
|
2
2
|
class Connection::HTTP2
|
3
|
+
include Callbacks
|
4
|
+
include Loggable
|
5
|
+
|
6
|
+
attr_reader streams: Hash[HTTP2Next::Stream, Response]
|
7
|
+
attr_reader pending: Array[Request]
|
8
|
+
|
9
|
+
@options: Options
|
10
|
+
@max_concurrent_requests: Integer
|
11
|
+
@max_requests: Integer
|
12
|
+
@drains: Hash[Request, String]
|
13
|
+
@pings: Array[String]
|
14
|
+
@buffer: Buffer
|
15
|
+
|
16
|
+
def interests: () -> io_interests
|
17
|
+
|
18
|
+
def close: () -> void
|
19
|
+
|
20
|
+
def empty?: () -> bool
|
21
|
+
|
22
|
+
def exhausted?: () -> bool
|
23
|
+
|
24
|
+
def <<: (String) -> void
|
25
|
+
|
26
|
+
def send: (Request) -> void
|
27
|
+
|
28
|
+
def consume: () -> void
|
29
|
+
|
30
|
+
def handle_error: (StandardError ex) -> void
|
31
|
+
|
32
|
+
def ping: () -> void
|
33
|
+
|
34
|
+
alias reset init_connection
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def initialize: (Buffer, options) -> untyped
|
39
|
+
|
40
|
+
def send_pending: () -> void
|
41
|
+
|
42
|
+
def headline_uri: (Request) -> String
|
43
|
+
|
44
|
+
def set_request_headers: (Request) -> void
|
45
|
+
|
46
|
+
def handle: (Request request, HTTP2Next::Stream stream) -> void
|
47
|
+
|
48
|
+
def init_connection: () -> void
|
49
|
+
|
50
|
+
def handle_stream: (HTTP2Next::Stream stream, Request request) -> void
|
51
|
+
|
52
|
+
def join_headers: (HTTP2Next::Stream stream, Request request) -> void
|
53
|
+
|
54
|
+
def join_body: (HTTP2Next::Stream stream, Request request) -> void
|
55
|
+
|
56
|
+
|
57
|
+
# def on_stream_headers: (HTTP2Next::Stream stream, Request request, Array[String, String] headers) -> void
|
58
|
+
|
59
|
+
# def on_stream_data: (HTTP2Next::Stream stream, Request request, string data) -> void
|
60
|
+
|
61
|
+
# def on_stream_close: (HTTP2Next::Stream stream, Request request, Symbol? error) -> void
|
62
|
+
|
63
|
+
def on_frame: (string bytes) -> void
|
64
|
+
|
65
|
+
def on_settings: (*untyped) -> void
|
66
|
+
|
67
|
+
def on_close: (Integer last_frame, Symbol? error, String? payload) -> void
|
68
|
+
|
69
|
+
def on_frame_sent: (HTTP2Next::frame) -> void
|
70
|
+
def on_frame_received: (HTTP2Next::frame) -> void
|
71
|
+
|
72
|
+
def on_promise: (HTTP2Next::Stream) -> void
|
73
|
+
|
74
|
+
def on_origin: (String) -> void
|
75
|
+
|
76
|
+
def on_pong: (string ping) -> void
|
3
77
|
end
|
4
78
|
end
|