httpx 0.12.0 → 0.14.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_10_1.md +1 -1
- data/doc/release_notes/0_13_0.md +58 -0
- data/doc/release_notes/0_13_1.md +5 -0
- data/doc/release_notes/0_13_2.md +9 -0
- data/doc/release_notes/0_14_0.md +79 -0
- data/doc/release_notes/0_14_1.md +7 -0
- data/lib/httpx.rb +1 -2
- data/lib/httpx/callbacks.rb +12 -3
- data/lib/httpx/chainable.rb +2 -2
- data/lib/httpx/connection.rb +29 -22
- data/lib/httpx/connection/http1.rb +35 -15
- data/lib/httpx/connection/http2.rb +61 -15
- data/lib/httpx/headers.rb +7 -3
- data/lib/httpx/io/ssl.rb +30 -17
- data/lib/httpx/io/tcp.rb +48 -27
- data/lib/httpx/io/udp.rb +31 -7
- data/lib/httpx/io/unix.rb +27 -12
- data/lib/httpx/options.rb +97 -74
- data/lib/httpx/plugins/aws_sdk_authentication.rb +5 -2
- data/lib/httpx/plugins/aws_sigv4.rb +5 -4
- data/lib/httpx/plugins/basic_authentication.rb +8 -3
- data/lib/httpx/plugins/compression.rb +24 -12
- data/lib/httpx/plugins/compression/brotli.rb +10 -7
- data/lib/httpx/plugins/compression/deflate.rb +6 -5
- data/lib/httpx/plugins/compression/gzip.rb +4 -3
- data/lib/httpx/plugins/cookies.rb +3 -7
- data/lib/httpx/plugins/digest_authentication.rb +5 -5
- data/lib/httpx/plugins/expect.rb +6 -6
- data/lib/httpx/plugins/follow_redirects.rb +4 -4
- data/lib/httpx/plugins/grpc.rb +247 -0
- data/lib/httpx/plugins/grpc/call.rb +62 -0
- data/lib/httpx/plugins/grpc/message.rb +85 -0
- data/lib/httpx/plugins/h2c.rb +43 -58
- data/lib/httpx/plugins/internal_telemetry.rb +1 -1
- data/lib/httpx/plugins/multipart/part.rb +2 -2
- data/lib/httpx/plugins/proxy.rb +3 -7
- data/lib/httpx/plugins/proxy/http.rb +5 -4
- data/lib/httpx/plugins/proxy/ssh.rb +3 -3
- data/lib/httpx/plugins/rate_limiter.rb +1 -1
- data/lib/httpx/plugins/retries.rb +14 -15
- data/lib/httpx/plugins/stream.rb +99 -75
- data/lib/httpx/plugins/upgrade.rb +84 -0
- data/lib/httpx/plugins/upgrade/h2.rb +54 -0
- data/lib/httpx/pool.rb +14 -5
- data/lib/httpx/request.rb +25 -2
- data/lib/httpx/resolver/native.rb +7 -3
- data/lib/httpx/response.rb +9 -5
- data/lib/httpx/session.rb +17 -7
- data/lib/httpx/transcoder/chunker.rb +1 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/callbacks.rbs +2 -0
- data/sig/chainable.rbs +2 -1
- data/sig/connection/http1.rbs +6 -1
- data/sig/connection/http2.rbs +6 -2
- data/sig/headers.rbs +2 -2
- data/sig/options.rbs +16 -22
- data/sig/plugins/aws_sdk_authentication.rbs +2 -0
- data/sig/plugins/aws_sigv4.rbs +0 -1
- data/sig/plugins/basic_authentication.rbs +2 -0
- data/sig/plugins/compression.rbs +7 -5
- 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/cookies.rbs +0 -1
- data/sig/plugins/digest_authentication.rbs +0 -1
- data/sig/plugins/expect.rbs +0 -2
- data/sig/plugins/follow_redirects.rbs +0 -2
- data/sig/plugins/h2c.rbs +5 -10
- data/sig/plugins/persistent.rbs +0 -1
- data/sig/plugins/proxy.rbs +0 -1
- data/sig/plugins/retries.rbs +0 -4
- data/sig/plugins/stream.rbs +17 -16
- data/sig/plugins/upgrade.rbs +23 -0
- data/sig/request.rbs +7 -2
- data/sig/response.rbs +4 -1
- data/sig/session.rbs +4 -0
- metadata +21 -7
- data/lib/httpx/timeout.rb +0 -67
- data/sig/timeout.rbs +0 -29
data/lib/httpx/io/unix.rb
CHANGED
@@ -6,34 +6,43 @@ module HTTPX
|
|
6
6
|
class UNIX < TCP
|
7
7
|
extend Forwardable
|
8
8
|
|
9
|
-
|
9
|
+
using URIExtensions
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
attr_reader :path
|
12
|
+
|
13
|
+
alias_method :host, :path
|
14
|
+
|
15
|
+
def initialize(origin, addresses, options)
|
13
16
|
@addresses = addresses
|
17
|
+
@hostname = origin.host
|
14
18
|
@state = :idle
|
15
19
|
@options = Options.new(options)
|
16
|
-
@path = @options.transport_options[:path]
|
17
20
|
@fallback_protocol = @options.fallback_protocol
|
18
21
|
if @options.io
|
19
22
|
@io = case @options.io
|
20
23
|
when Hash
|
21
|
-
@options.io[
|
24
|
+
@options.io[origin.authority]
|
22
25
|
else
|
23
26
|
@options.io
|
24
27
|
end
|
25
|
-
unless @io
|
26
|
-
|
27
|
-
|
28
|
+
raise Error, "Given IO objects do not match the request authority" unless @io
|
29
|
+
|
30
|
+
@path = @io.path
|
31
|
+
@keep_open = true
|
32
|
+
@state = :connected
|
33
|
+
else
|
34
|
+
if @options.transport_options
|
35
|
+
# :nocov:
|
36
|
+
warn ":#{__method__} is deprecated, use :addresses instead"
|
37
|
+
@path = @options.transport_options[:path]
|
38
|
+
# :nocov:
|
39
|
+
else
|
40
|
+
@path = addresses.first
|
28
41
|
end
|
29
42
|
end
|
30
43
|
@io ||= build_socket
|
31
44
|
end
|
32
45
|
|
33
|
-
def hostname
|
34
|
-
@uri.host
|
35
|
-
end
|
36
|
-
|
37
46
|
def connect
|
38
47
|
return unless closed?
|
39
48
|
|
@@ -51,6 +60,12 @@ module HTTPX
|
|
51
60
|
::IO::WaitReadable
|
52
61
|
end
|
53
62
|
|
63
|
+
# :nocov:
|
64
|
+
def inspect
|
65
|
+
"#<#{self.class}(path: #{@path}): (state: #{@state})>"
|
66
|
+
end
|
67
|
+
# :nocov:
|
68
|
+
|
54
69
|
private
|
55
70
|
|
56
71
|
def build_socket
|
data/lib/httpx/options.rb
CHANGED
@@ -4,13 +4,39 @@ module HTTPX
|
|
4
4
|
class Options
|
5
5
|
WINDOW_SIZE = 1 << 14 # 16K
|
6
6
|
MAX_BODY_THRESHOLD_SIZE = (1 << 10) * 112 # 112K
|
7
|
+
CONNECT_TIMEOUT = 60
|
8
|
+
OPERATION_TIMEOUT = 60
|
9
|
+
KEEP_ALIVE_TIMEOUT = 20
|
10
|
+
|
11
|
+
DEFAULT_OPTIONS = {
|
12
|
+
:debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
|
13
|
+
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
|
14
|
+
:ssl => {},
|
15
|
+
:http2_settings => { settings_enable_push: 0 },
|
16
|
+
:fallback_protocol => "http/1.1",
|
17
|
+
:timeout => {
|
18
|
+
connect_timeout: CONNECT_TIMEOUT,
|
19
|
+
operation_timeout: OPERATION_TIMEOUT,
|
20
|
+
keep_alive_timeout: KEEP_ALIVE_TIMEOUT,
|
21
|
+
},
|
22
|
+
:headers => {},
|
23
|
+
:window_size => WINDOW_SIZE,
|
24
|
+
:body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
|
25
|
+
:request_class => Class.new(Request),
|
26
|
+
:response_class => Class.new(Response),
|
27
|
+
:headers_class => Class.new(Headers),
|
28
|
+
:request_body_class => Class.new(Request::Body),
|
29
|
+
:response_body_class => Class.new(Response::Body),
|
30
|
+
:connection_class => Class.new(Connection),
|
31
|
+
:transport => nil,
|
32
|
+
:transport_options => nil,
|
33
|
+
:addresses => nil,
|
34
|
+
:persistent => false,
|
35
|
+
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
36
|
+
:resolver_options => { cache: true },
|
37
|
+
}.freeze
|
7
38
|
|
8
39
|
class << self
|
9
|
-
def inherited(klass)
|
10
|
-
super
|
11
|
-
klass.instance_variable_set(:@defined_options, @defined_options.dup)
|
12
|
-
end
|
13
|
-
|
14
40
|
def new(options = {})
|
15
41
|
# let enhanced options go through
|
16
42
|
return options if self == Options && options.class > self
|
@@ -19,31 +45,30 @@ module HTTPX
|
|
19
45
|
super
|
20
46
|
end
|
21
47
|
|
22
|
-
def
|
23
|
-
|
24
|
-
end
|
48
|
+
def def_option(name, layout = nil, &interpreter)
|
49
|
+
attr_reader name
|
25
50
|
|
26
|
-
|
27
|
-
|
51
|
+
if layout
|
52
|
+
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
53
|
+
def #{name}=(value)
|
54
|
+
return if value.nil?
|
28
55
|
|
29
|
-
|
56
|
+
value = begin
|
57
|
+
#{layout}
|
58
|
+
end
|
59
|
+
|
60
|
+
@#{name} = value
|
61
|
+
end
|
62
|
+
OUT
|
30
63
|
|
31
|
-
|
64
|
+
elsif interpreter
|
32
65
|
define_method(:"#{name}=") do |value|
|
33
66
|
return if value.nil?
|
34
67
|
|
35
68
|
instance_variable_set(:"@#{name}", instance_exec(value, &interpreter))
|
36
69
|
end
|
37
|
-
|
38
|
-
define_method(:"with_#{name}") do |value|
|
39
|
-
merge(name => instance_exec(value, &interpreter))
|
40
|
-
end
|
41
70
|
else
|
42
71
|
attr_writer name
|
43
|
-
|
44
|
-
define_method(:"with_#{name}") do |value|
|
45
|
-
merge(name => value)
|
46
|
-
end
|
47
72
|
end
|
48
73
|
|
49
74
|
protected :"#{name}="
|
@@ -51,75 +76,71 @@ module HTTPX
|
|
51
76
|
end
|
52
77
|
|
53
78
|
def initialize(options = {})
|
54
|
-
defaults =
|
55
|
-
:debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
|
56
|
-
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
|
57
|
-
:ssl => {},
|
58
|
-
:http2_settings => { settings_enable_push: 0 },
|
59
|
-
:fallback_protocol => "http/1.1",
|
60
|
-
:timeout => Timeout.new,
|
61
|
-
:headers => {},
|
62
|
-
:window_size => WINDOW_SIZE,
|
63
|
-
:body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
|
64
|
-
:request_class => Class.new(Request),
|
65
|
-
:response_class => Class.new(Response),
|
66
|
-
:headers_class => Class.new(Headers),
|
67
|
-
:request_body_class => Class.new(Request::Body),
|
68
|
-
:response_body_class => Class.new(Response::Body),
|
69
|
-
:connection_class => Class.new(Connection),
|
70
|
-
:transport => nil,
|
71
|
-
:transport_options => nil,
|
72
|
-
:persistent => false,
|
73
|
-
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
74
|
-
:resolver_options => { cache: true },
|
75
|
-
}
|
76
|
-
|
77
|
-
defaults.merge!(options)
|
79
|
+
defaults = DEFAULT_OPTIONS.merge(options)
|
78
80
|
defaults.each do |(k, v)|
|
79
81
|
next if v.nil?
|
80
82
|
|
81
|
-
|
83
|
+
begin
|
84
|
+
__send__(:"#{k}=", v)
|
85
|
+
rescue NoMethodError
|
86
|
+
raise Error, "unknown option: #{k}"
|
87
|
+
end
|
82
88
|
end
|
83
89
|
end
|
84
90
|
|
85
|
-
def_option(:
|
91
|
+
def_option(:origin, <<-OUT)
|
92
|
+
URI(value)
|
93
|
+
OUT
|
94
|
+
|
95
|
+
def_option(:headers, <<-OUT)
|
86
96
|
if self.headers
|
87
|
-
self.headers.merge(
|
97
|
+
self.headers.merge(value)
|
88
98
|
else
|
89
|
-
Headers.new(
|
99
|
+
Headers.new(value)
|
90
100
|
end
|
91
|
-
|
101
|
+
OUT
|
92
102
|
|
93
|
-
def_option(:timeout)
|
94
|
-
|
95
|
-
end
|
103
|
+
def_option(:timeout, <<-OUT)
|
104
|
+
timeouts = Hash[value]
|
96
105
|
|
97
|
-
|
98
|
-
|
106
|
+
if timeouts.key?(:loop_timeout)
|
107
|
+
warn ":loop_timeout is deprecated, use :operation_timeout instead"
|
108
|
+
timeouts[:operation_timeout] = timeouts.delete(:loop_timeout)
|
109
|
+
end
|
99
110
|
|
100
|
-
|
101
|
-
|
111
|
+
timeouts
|
112
|
+
OUT
|
102
113
|
|
103
|
-
def_option(:
|
104
|
-
raise Error, ":
|
114
|
+
def_option(:max_concurrent_requests, <<-OUT)
|
115
|
+
raise Error, ":max_concurrent_requests must be positive" unless value.positive?
|
105
116
|
|
106
|
-
|
107
|
-
|
117
|
+
value
|
118
|
+
OUT
|
108
119
|
|
109
|
-
def_option(:
|
110
|
-
|
111
|
-
end
|
120
|
+
def_option(:max_requests, <<-OUT)
|
121
|
+
raise Error, ":max_requests must be positive" unless value.positive?
|
112
122
|
|
113
|
-
|
114
|
-
|
115
|
-
end
|
123
|
+
value
|
124
|
+
OUT
|
116
125
|
|
117
|
-
def_option(:
|
118
|
-
|
119
|
-
|
126
|
+
def_option(:window_size, <<-OUT)
|
127
|
+
Integer(value)
|
128
|
+
OUT
|
129
|
+
|
130
|
+
def_option(:body_threshold_size, <<-OUT)
|
131
|
+
Integer(value)
|
132
|
+
OUT
|
133
|
+
|
134
|
+
def_option(:transport, <<-OUT)
|
135
|
+
transport = value.to_s
|
136
|
+
raise Error, "\#{transport} is an unsupported transport type" unless IO.registry.key?(transport)
|
120
137
|
|
121
138
|
transport
|
122
|
-
|
139
|
+
OUT
|
140
|
+
|
141
|
+
def_option(:addresses, <<-OUT)
|
142
|
+
Array(value)
|
143
|
+
OUT
|
123
144
|
|
124
145
|
%w[
|
125
146
|
params form json body ssl http2_settings
|
@@ -153,6 +174,8 @@ module HTTPX
|
|
153
174
|
|
154
175
|
h1 = to_hash
|
155
176
|
|
177
|
+
return self if h1 == h2
|
178
|
+
|
156
179
|
merged = h1.merge(h2) do |k, v1, v2|
|
157
180
|
case k
|
158
181
|
when :headers, :ssl, :http2_settings, :timeout
|
@@ -166,10 +189,10 @@ module HTTPX
|
|
166
189
|
end
|
167
190
|
|
168
191
|
def to_hash
|
169
|
-
hash_pairs =
|
170
|
-
|
171
|
-
|
172
|
-
Hash[
|
192
|
+
hash_pairs = instance_variables.map do |ivar|
|
193
|
+
[ivar[1..-1].to_sym, instance_variable_get(ivar)]
|
194
|
+
end
|
195
|
+
Hash[hash_pairs]
|
173
196
|
end
|
174
197
|
|
175
198
|
def initialize_dup(other)
|
@@ -32,9 +32,8 @@ module HTTPX
|
|
32
32
|
class << self
|
33
33
|
attr_reader :credentials, :region
|
34
34
|
|
35
|
-
def load_dependencies(
|
35
|
+
def load_dependencies(_klass)
|
36
36
|
require "aws-sdk-core"
|
37
|
-
klass.plugin(:aws_sigv4)
|
38
37
|
|
39
38
|
client = Class.new(Seahorse::Client::Base) do
|
40
39
|
@identifier = :httpx
|
@@ -50,6 +49,10 @@ module HTTPX
|
|
50
49
|
@region = client.config[:region]
|
51
50
|
end
|
52
51
|
|
52
|
+
def configure(klass)
|
53
|
+
klass.plugin(:aws_sigv4)
|
54
|
+
end
|
55
|
+
|
53
56
|
def extra_options(options)
|
54
57
|
options.merge(max_concurrent_requests: 1)
|
55
58
|
end
|
@@ -143,13 +143,14 @@ module HTTPX
|
|
143
143
|
class << self
|
144
144
|
def extra_options(options)
|
145
145
|
Class.new(options.class) do
|
146
|
-
def_option(:sigv4_signer)
|
147
|
-
|
148
|
-
|
149
|
-
end.new
|
146
|
+
def_option(:sigv4_signer, <<-OUT)
|
147
|
+
value.is_a?(#{Signer}) ? value : #{Signer}.new(value)
|
148
|
+
OUT
|
149
|
+
end.new(options)
|
150
150
|
end
|
151
151
|
|
152
152
|
def load_dependencies(klass)
|
153
|
+
require "digest/sha2"
|
153
154
|
require "openssl"
|
154
155
|
klass.plugin(:expect)
|
155
156
|
klass.plugin(:compression)
|
@@ -8,9 +8,14 @@ module HTTPX
|
|
8
8
|
# https://gitlab.com/honeyryderchuck/httpx/wikis/Authentication#basic-authentication
|
9
9
|
#
|
10
10
|
module BasicAuthentication
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
class << self
|
12
|
+
def load_dependencies(_klass)
|
13
|
+
require "base64"
|
14
|
+
end
|
15
|
+
|
16
|
+
def configure(klass)
|
17
|
+
klass.plugin(:authentication)
|
18
|
+
end
|
14
19
|
end
|
15
20
|
|
16
21
|
module InstanceMethods
|
@@ -13,23 +13,31 @@ module HTTPX
|
|
13
13
|
# https://gitlab.com/honeyryderchuck/httpx/wikis/Compression
|
14
14
|
#
|
15
15
|
module Compression
|
16
|
-
extend Registry
|
17
|
-
|
18
16
|
class << self
|
19
|
-
def
|
17
|
+
def configure(klass)
|
20
18
|
klass.plugin(:"compression/gzip")
|
21
19
|
klass.plugin(:"compression/deflate")
|
22
20
|
end
|
23
21
|
|
24
22
|
def extra_options(options)
|
23
|
+
encodings = Module.new do
|
24
|
+
extend Registry
|
25
|
+
end
|
26
|
+
|
25
27
|
Class.new(options.class) do
|
26
|
-
def_option(:compression_threshold_size)
|
27
|
-
bytes = Integer(
|
28
|
+
def_option(:compression_threshold_size, <<-OUT)
|
29
|
+
bytes = Integer(value)
|
28
30
|
raise Error, ":expect_threshold_size must be positive" unless bytes.positive?
|
29
31
|
|
30
32
|
bytes
|
31
|
-
|
32
|
-
|
33
|
+
OUT
|
34
|
+
|
35
|
+
def_option(:encodings, <<-OUT)
|
36
|
+
raise Error, ":encodings must be a registry" unless value.respond_to?(:registry)
|
37
|
+
|
38
|
+
value
|
39
|
+
OUT
|
40
|
+
end.new(options).merge(encodings: encodings)
|
33
41
|
end
|
34
42
|
end
|
35
43
|
|
@@ -37,7 +45,11 @@ module HTTPX
|
|
37
45
|
def initialize(*)
|
38
46
|
super
|
39
47
|
# forego compression in the Range cases
|
40
|
-
|
48
|
+
if @headers.key?("range")
|
49
|
+
@headers.delete("accept-encoding")
|
50
|
+
else
|
51
|
+
@headers["accept-encoding"] ||= @options.encodings.registry.keys
|
52
|
+
end
|
41
53
|
end
|
42
54
|
end
|
43
55
|
|
@@ -52,16 +64,16 @@ module HTTPX
|
|
52
64
|
@headers.get("content-encoding").each do |encoding|
|
53
65
|
next if encoding == "identity"
|
54
66
|
|
55
|
-
@body = Encoder.new(@body,
|
67
|
+
@body = Encoder.new(@body, options.encodings.registry(encoding).deflater)
|
56
68
|
end
|
57
|
-
@headers["content-length"] = @body.bytesize unless
|
69
|
+
@headers["content-length"] = @body.bytesize unless unbounded_body?
|
58
70
|
end
|
59
71
|
end
|
60
72
|
|
61
73
|
module ResponseBodyMethods
|
62
74
|
attr_reader :encodings
|
63
75
|
|
64
|
-
def initialize(
|
76
|
+
def initialize(*)
|
65
77
|
@encodings = []
|
66
78
|
|
67
79
|
super
|
@@ -80,7 +92,7 @@ module HTTPX
|
|
80
92
|
@_inflaters = @headers.get("content-encoding").map do |encoding|
|
81
93
|
next if encoding == "identity"
|
82
94
|
|
83
|
-
inflater =
|
95
|
+
inflater = @options.encodings.registry(encoding).inflater(compressed_length)
|
84
96
|
# do not uncompress if there is no decoder available. In fact, we can't reliably
|
85
97
|
# continue decompressing beyond that, so ignore.
|
86
98
|
break unless inflater
|
@@ -4,24 +4,27 @@ module HTTPX
|
|
4
4
|
module Plugins
|
5
5
|
module Compression
|
6
6
|
module Brotli
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
class << self
|
8
|
+
def load_dependencies(_klass)
|
9
|
+
require "brotli"
|
10
|
+
end
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
def configure(klass)
|
13
|
+
klass.plugin(:compression)
|
14
|
+
klass.default_options.encodings.register "br", self
|
15
|
+
end
|
14
16
|
end
|
15
17
|
|
16
18
|
module Deflater
|
17
19
|
module_function
|
18
20
|
|
19
|
-
def deflate(raw, buffer, chunk_size:)
|
21
|
+
def deflate(raw, buffer = "".b, chunk_size: 16_384)
|
20
22
|
while (chunk = raw.read(chunk_size))
|
21
23
|
compressed = ::Brotli.deflate(chunk)
|
22
24
|
buffer << compressed
|
23
25
|
yield compressed if block_given?
|
24
26
|
end
|
27
|
+
buffer
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|