httpx 0.13.0 → 0.14.2
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 +2 -2
- 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/doc/release_notes/0_14_2.md +6 -0
- data/lib/httpx.rb +1 -2
- data/lib/httpx/callbacks.rb +12 -3
- data/lib/httpx/connection.rb +12 -9
- data/lib/httpx/connection/http1.rb +32 -14
- data/lib/httpx/connection/http2.rb +61 -15
- data/lib/httpx/headers.rb +7 -3
- data/lib/httpx/io/tcp.rb +3 -1
- data/lib/httpx/io/udp.rb +31 -7
- data/lib/httpx/options.rb +91 -56
- 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 +8 -8
- data/lib/httpx/plugins/compression/brotli.rb +4 -3
- data/lib/httpx/plugins/compression/deflate.rb +4 -3
- data/lib/httpx/plugins/compression/gzip.rb +2 -1
- data/lib/httpx/plugins/cookies.rb +3 -7
- data/lib/httpx/plugins/digest_authentication.rb +4 -4
- data/lib/httpx/plugins/expect.rb +6 -6
- data/lib/httpx/plugins/follow_redirects.rb +3 -3
- 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/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 +13 -14
- data/lib/httpx/plugins/stream.rb +96 -74
- data/lib/httpx/plugins/upgrade.rb +6 -5
- data/lib/httpx/request.rb +25 -2
- data/lib/httpx/resolver/native.rb +7 -3
- data/lib/httpx/response.rb +4 -0
- 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/connection/http1.rbs +5 -1
- data/sig/connection/http2.rbs +6 -2
- data/sig/headers.rbs +2 -2
- data/sig/options.rbs +9 -2
- data/sig/plugins/aws_sdk_authentication.rbs +2 -0
- data/sig/plugins/basic_authentication.rbs +2 -0
- data/sig/plugins/compression.rbs +2 -2
- data/sig/plugins/multipart.rbs +1 -1
- data/sig/plugins/stream.rbs +17 -16
- data/sig/request.rbs +7 -2
- data/sig/response.rbs +1 -0
- data/sig/session.rbs +4 -0
- metadata +18 -7
- data/lib/httpx/timeout.rb +0 -67
- data/sig/timeout.rbs +0 -29
data/lib/httpx/headers.rb
CHANGED
@@ -103,16 +103,20 @@ module HTTPX
|
|
103
103
|
# returns the enumerable headers store in pairs of header field + the values in
|
104
104
|
# the comma-separated string format
|
105
105
|
#
|
106
|
-
def each
|
107
|
-
return enum_for(__method__) { @headers.size } unless block_given?
|
106
|
+
def each(extra_headers = nil)
|
107
|
+
return enum_for(__method__, extra_headers) { @headers.size } unless block_given?
|
108
108
|
|
109
109
|
@headers.each do |field, value|
|
110
110
|
yield(field, value.join(", ")) unless value.empty?
|
111
111
|
end
|
112
|
+
|
113
|
+
extra_headers.each do |field, value|
|
114
|
+
yield(field, value) unless value.empty?
|
115
|
+
end if extra_headers
|
112
116
|
end
|
113
117
|
|
114
118
|
def ==(other)
|
115
|
-
|
119
|
+
other == to_hash
|
116
120
|
end
|
117
121
|
|
118
122
|
# the headers store in Hash format
|
data/lib/httpx/io/tcp.rb
CHANGED
@@ -63,7 +63,7 @@ module HTTPX
|
|
63
63
|
@ip_index -= 1
|
64
64
|
retry
|
65
65
|
rescue Errno::ETIMEDOUT => e
|
66
|
-
raise ConnectTimeoutError.new(@options.timeout
|
66
|
+
raise ConnectTimeoutError.new(@options.timeout[:connect_timeout], e.message) if @ip_index <= 0
|
67
67
|
|
68
68
|
@ip_index -= 1
|
69
69
|
retry
|
@@ -120,6 +120,8 @@ module HTTPX
|
|
120
120
|
end
|
121
121
|
transition(:connected)
|
122
122
|
@interests = :w
|
123
|
+
rescue Errno::EALREADY
|
124
|
+
@interests = :w
|
123
125
|
end
|
124
126
|
private :try_connect
|
125
127
|
|
data/lib/httpx/io/udp.rb
CHANGED
@@ -39,16 +39,20 @@ module HTTPX
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
def write(buffer)
|
43
|
-
siz = @io.send(buffer.to_s, 0, @host, @port)
|
44
|
-
log { "WRITE: #{siz} bytes..." }
|
45
|
-
buffer.shift!(siz)
|
46
|
-
siz
|
47
|
-
end
|
48
|
-
|
49
42
|
# :nocov:
|
50
43
|
if (RUBY_ENGINE == "truffleruby" && RUBY_ENGINE_VERSION < "21.1.0") ||
|
51
44
|
RUBY_VERSION < "2.3"
|
45
|
+
def write(buffer)
|
46
|
+
siz = @io.sendmsg_nonblock(buffer.to_s, 0, Socket.sockaddr_in(@port, @host.to_s))
|
47
|
+
log { "WRITE: #{siz} bytes..." }
|
48
|
+
buffer.shift!(siz)
|
49
|
+
siz
|
50
|
+
rescue ::IO::WaitWritable
|
51
|
+
0
|
52
|
+
rescue EOFError
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
52
56
|
def read(size, buffer)
|
53
57
|
data, _ = @io.recvfrom_nonblock(size)
|
54
58
|
buffer.replace(data)
|
@@ -59,6 +63,18 @@ module HTTPX
|
|
59
63
|
rescue IOError
|
60
64
|
end
|
61
65
|
else
|
66
|
+
|
67
|
+
def write(buffer)
|
68
|
+
siz = @io.sendmsg_nonblock(buffer.to_s, 0, Socket.sockaddr_in(@port, @host.to_s), exception: false)
|
69
|
+
return 0 if siz == :wait_writable
|
70
|
+
return if siz.nil?
|
71
|
+
|
72
|
+
log { "WRITE: #{siz} bytes..." }
|
73
|
+
|
74
|
+
buffer.shift!(siz)
|
75
|
+
siz
|
76
|
+
end
|
77
|
+
|
62
78
|
def read(size, buffer)
|
63
79
|
ret = @io.recvfrom_nonblock(size, 0, buffer, exception: false)
|
64
80
|
return 0 if ret == :wait_readable
|
@@ -68,6 +84,14 @@ module HTTPX
|
|
68
84
|
rescue IOError
|
69
85
|
end
|
70
86
|
end
|
87
|
+
|
88
|
+
# In JRuby, sendmsg_nonblock is not implemented
|
89
|
+
def write(buffer)
|
90
|
+
siz = @io.send(buffer.to_s, 0, @host, @port)
|
91
|
+
log { "WRITE: #{siz} bytes..." }
|
92
|
+
buffer.shift!(siz)
|
93
|
+
siz
|
94
|
+
end if RUBY_ENGINE == "jruby"
|
71
95
|
# :nocov:
|
72
96
|
end
|
73
97
|
end
|
data/lib/httpx/options.rb
CHANGED
@@ -4,6 +4,37 @@ 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
40
|
def new(options = {})
|
@@ -14,10 +45,23 @@ module HTTPX
|
|
14
45
|
super
|
15
46
|
end
|
16
47
|
|
17
|
-
def def_option(name, &interpreter)
|
48
|
+
def def_option(name, layout = nil, &interpreter)
|
18
49
|
attr_reader name
|
19
50
|
|
20
|
-
if
|
51
|
+
if layout
|
52
|
+
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
53
|
+
def #{name}=(value)
|
54
|
+
return if value.nil?
|
55
|
+
|
56
|
+
value = begin
|
57
|
+
#{layout}
|
58
|
+
end
|
59
|
+
|
60
|
+
@#{name} = value
|
61
|
+
end
|
62
|
+
OUT
|
63
|
+
|
64
|
+
elsif interpreter
|
21
65
|
define_method(:"#{name}=") do |value|
|
22
66
|
return if value.nil?
|
23
67
|
|
@@ -32,80 +76,71 @@ module HTTPX
|
|
32
76
|
end
|
33
77
|
|
34
78
|
def initialize(options = {})
|
35
|
-
defaults =
|
36
|
-
:debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
|
37
|
-
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
|
38
|
-
:ssl => {},
|
39
|
-
:http2_settings => { settings_enable_push: 0 },
|
40
|
-
:fallback_protocol => "http/1.1",
|
41
|
-
:timeout => Timeout.new,
|
42
|
-
:headers => {},
|
43
|
-
:window_size => WINDOW_SIZE,
|
44
|
-
:body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
|
45
|
-
:request_class => Class.new(Request),
|
46
|
-
:response_class => Class.new(Response),
|
47
|
-
:headers_class => Class.new(Headers),
|
48
|
-
:request_body_class => Class.new(Request::Body),
|
49
|
-
:response_body_class => Class.new(Response::Body),
|
50
|
-
:connection_class => Class.new(Connection),
|
51
|
-
:transport => nil,
|
52
|
-
:transport_options => nil,
|
53
|
-
:addresses => nil,
|
54
|
-
:persistent => false,
|
55
|
-
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
56
|
-
:resolver_options => { cache: true },
|
57
|
-
}
|
58
|
-
|
59
|
-
defaults.merge!(options)
|
79
|
+
defaults = DEFAULT_OPTIONS.merge(options)
|
60
80
|
defaults.each do |(k, v)|
|
61
81
|
next if v.nil?
|
62
82
|
|
63
|
-
|
83
|
+
begin
|
84
|
+
__send__(:"#{k}=", v)
|
85
|
+
rescue NoMethodError
|
86
|
+
raise Error, "unknown option: #{k}"
|
87
|
+
end
|
64
88
|
end
|
65
89
|
end
|
66
90
|
|
67
|
-
def_option(:
|
91
|
+
def_option(:origin, <<-OUT)
|
92
|
+
URI(value)
|
93
|
+
OUT
|
94
|
+
|
95
|
+
def_option(:headers, <<-OUT)
|
68
96
|
if self.headers
|
69
|
-
self.headers.merge(
|
97
|
+
self.headers.merge(value)
|
70
98
|
else
|
71
|
-
Headers.new(
|
99
|
+
Headers.new(value)
|
72
100
|
end
|
73
|
-
|
101
|
+
OUT
|
74
102
|
|
75
|
-
def_option(:timeout)
|
76
|
-
|
77
|
-
|
103
|
+
def_option(:timeout, <<-OUT)
|
104
|
+
timeouts = Hash[value]
|
105
|
+
|
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
|
78
110
|
|
79
|
-
|
80
|
-
|
111
|
+
timeouts
|
112
|
+
OUT
|
81
113
|
|
82
|
-
|
83
|
-
|
114
|
+
def_option(:max_concurrent_requests, <<-OUT)
|
115
|
+
raise Error, ":max_concurrent_requests must be positive" unless value.positive?
|
84
116
|
|
85
|
-
|
86
|
-
|
117
|
+
value
|
118
|
+
OUT
|
87
119
|
|
88
|
-
|
89
|
-
|
120
|
+
def_option(:max_requests, <<-OUT)
|
121
|
+
raise Error, ":max_requests must be positive" unless value.positive?
|
90
122
|
|
91
|
-
|
92
|
-
|
93
|
-
end
|
123
|
+
value
|
124
|
+
OUT
|
94
125
|
|
95
|
-
def_option(:
|
96
|
-
Integer(
|
97
|
-
|
126
|
+
def_option(:window_size, <<-OUT)
|
127
|
+
Integer(value)
|
128
|
+
OUT
|
129
|
+
|
130
|
+
def_option(:body_threshold_size, <<-OUT)
|
131
|
+
Integer(value)
|
132
|
+
OUT
|
98
133
|
|
99
|
-
def_option(:transport)
|
100
|
-
transport =
|
101
|
-
raise Error, "
|
134
|
+
def_option(:transport, <<-OUT)
|
135
|
+
transport = value.to_s
|
136
|
+
raise Error, "\#{transport} is an unsupported transport type" unless IO.registry.key?(transport)
|
102
137
|
|
103
138
|
transport
|
104
|
-
|
139
|
+
OUT
|
105
140
|
|
106
|
-
def_option(:addresses)
|
107
|
-
Array(
|
108
|
-
|
141
|
+
def_option(:addresses, <<-OUT)
|
142
|
+
Array(value)
|
143
|
+
OUT
|
109
144
|
|
110
145
|
%w[
|
111
146
|
params form json body ssl http2_settings
|
@@ -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
|
@@ -25,18 +25,18 @@ module HTTPX
|
|
25
25
|
end
|
26
26
|
|
27
27
|
Class.new(options.class) do
|
28
|
-
def_option(:compression_threshold_size)
|
29
|
-
bytes = Integer(
|
28
|
+
def_option(:compression_threshold_size, <<-OUT)
|
29
|
+
bytes = Integer(value)
|
30
30
|
raise Error, ":expect_threshold_size must be positive" unless bytes.positive?
|
31
31
|
|
32
32
|
bytes
|
33
|
-
|
33
|
+
OUT
|
34
34
|
|
35
|
-
def_option(:encodings)
|
36
|
-
raise Error, ":encodings must be a registry" unless
|
35
|
+
def_option(:encodings, <<-OUT)
|
36
|
+
raise Error, ":encodings must be a registry" unless value.respond_to?(:registry)
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
value
|
39
|
+
OUT
|
40
40
|
end.new(options).merge(encodings: encodings)
|
41
41
|
end
|
42
42
|
end
|
@@ -66,7 +66,7 @@ module HTTPX
|
|
66
66
|
|
67
67
|
@body = Encoder.new(@body, options.encodings.registry(encoding).deflater)
|
68
68
|
end
|
69
|
-
@headers["content-length"] = @body.bytesize unless
|
69
|
+
@headers["content-length"] = @body.bytesize unless unbounded_body?
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -5,12 +5,12 @@ module HTTPX
|
|
5
5
|
module Compression
|
6
6
|
module Brotli
|
7
7
|
class << self
|
8
|
-
def load_dependencies(
|
9
|
-
klass.plugin(:compression)
|
8
|
+
def load_dependencies(_klass)
|
10
9
|
require "brotli"
|
11
10
|
end
|
12
11
|
|
13
12
|
def configure(klass)
|
13
|
+
klass.plugin(:compression)
|
14
14
|
klass.default_options.encodings.register "br", self
|
15
15
|
end
|
16
16
|
end
|
@@ -18,12 +18,13 @@ module HTTPX
|
|
18
18
|
module Deflater
|
19
19
|
module_function
|
20
20
|
|
21
|
-
def deflate(raw, buffer, chunk_size:)
|
21
|
+
def deflate(raw, buffer = "".b, chunk_size: 16_384)
|
22
22
|
while (chunk = raw.read(chunk_size))
|
23
23
|
compressed = ::Brotli.deflate(chunk)
|
24
24
|
buffer << compressed
|
25
25
|
yield compressed if block_given?
|
26
26
|
end
|
27
|
+
buffer
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
@@ -4,20 +4,20 @@ module HTTPX
|
|
4
4
|
module Plugins
|
5
5
|
module Compression
|
6
6
|
module Deflate
|
7
|
-
def self.load_dependencies(
|
7
|
+
def self.load_dependencies(_klass)
|
8
8
|
require "stringio"
|
9
9
|
require "zlib"
|
10
|
-
klass.plugin(:"compression/gzip")
|
11
10
|
end
|
12
11
|
|
13
12
|
def self.configure(klass)
|
13
|
+
klass.plugin(:"compression/gzip")
|
14
14
|
klass.default_options.encodings.register "deflate", self
|
15
15
|
end
|
16
16
|
|
17
17
|
module Deflater
|
18
18
|
module_function
|
19
19
|
|
20
|
-
def deflate(raw, buffer, chunk_size:)
|
20
|
+
def deflate(raw, buffer = "".b, chunk_size: 16_384)
|
21
21
|
deflater = Zlib::Deflate.new
|
22
22
|
while (chunk = raw.read(chunk_size))
|
23
23
|
compressed = deflater.deflate(chunk)
|
@@ -27,6 +27,7 @@ module HTTPX
|
|
27
27
|
last = deflater.finish
|
28
28
|
buffer << last
|
29
29
|
yield last if block_given?
|
30
|
+
buffer
|
30
31
|
ensure
|
31
32
|
deflater.close if deflater
|
32
33
|
end
|