httpx 0.9.0 → 0.10.0
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/LICENSE.txt +48 -0
- data/README.md +2 -0
- data/doc/release_notes/0_10_0.md +66 -0
- data/lib/httpx.rb +2 -0
- data/lib/httpx/adapters/faraday.rb +1 -1
- data/lib/httpx/chainable.rb +2 -2
- data/lib/httpx/connection.rb +3 -9
- data/lib/httpx/connection/http1.rb +1 -1
- data/lib/httpx/domain_name.rb +440 -0
- data/lib/httpx/errors.rb +1 -0
- data/lib/httpx/extensions.rb +21 -1
- data/lib/httpx/io/ssl.rb +0 -1
- data/lib/httpx/io/tcp.rb +6 -5
- data/lib/httpx/io/udp.rb +4 -1
- data/lib/httpx/options.rb +2 -0
- data/lib/httpx/parser/http1.rb +14 -17
- data/lib/httpx/plugins/compression.rb +28 -63
- data/lib/httpx/plugins/compression/brotli.rb +10 -14
- data/lib/httpx/plugins/compression/deflate.rb +7 -6
- data/lib/httpx/plugins/compression/gzip.rb +23 -5
- data/lib/httpx/plugins/cookies.rb +21 -60
- data/lib/httpx/plugins/cookies/cookie.rb +173 -0
- data/lib/httpx/plugins/cookies/jar.rb +74 -0
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +142 -0
- data/lib/httpx/plugins/expect.rb +3 -5
- data/lib/httpx/plugins/follow_redirects.rb +20 -2
- data/lib/httpx/plugins/h2c.rb +1 -1
- data/lib/httpx/plugins/multipart.rb +0 -8
- data/lib/httpx/plugins/persistent.rb +6 -1
- data/lib/httpx/plugins/proxy/socks4.rb +3 -1
- data/lib/httpx/plugins/rate_limiter.rb +51 -0
- data/lib/httpx/plugins/retries.rb +3 -2
- data/lib/httpx/plugins/stream.rb +109 -13
- data/lib/httpx/pool.rb +6 -6
- data/lib/httpx/request.rb +7 -19
- data/lib/httpx/resolver/https.rb +7 -2
- data/lib/httpx/resolver/native.rb +7 -3
- data/lib/httpx/response.rb +16 -23
- data/lib/httpx/selector.rb +2 -4
- data/lib/httpx/session.rb +17 -11
- data/lib/httpx/transcoder/chunker.rb +0 -2
- data/lib/httpx/transcoder/form.rb +0 -6
- data/lib/httpx/transcoder/json.rb +0 -4
- data/lib/httpx/utils.rb +45 -0
- data/lib/httpx/version.rb +1 -1
- data/sig/buffer.rbs +24 -0
- data/sig/callbacks.rbs +14 -0
- data/sig/chainable.rbs +37 -0
- data/sig/connection.rbs +2 -0
- data/sig/connection/http2.rbs +4 -0
- data/sig/domain_name.rbs +17 -0
- data/sig/errors.rbs +3 -0
- data/sig/headers.rbs +42 -0
- data/sig/httpx.rbs +14 -0
- data/sig/loggable.rbs +11 -0
- data/sig/missing.rbs +12 -0
- data/sig/options.rbs +118 -0
- data/sig/parser/http1.rbs +50 -0
- data/sig/plugins/authentication.rbs +11 -0
- data/sig/plugins/basic_authentication.rbs +13 -0
- data/sig/plugins/compression.rbs +55 -0
- data/sig/plugins/compression/brotli.rbs +21 -0
- data/sig/plugins/compression/deflate.rbs +17 -0
- data/sig/plugins/compression/gzip.rbs +29 -0
- data/sig/plugins/cookies.rbs +26 -0
- data/sig/plugins/cookies/cookie.rbs +50 -0
- data/sig/plugins/cookies/jar.rbs +27 -0
- data/sig/plugins/digest_authentication.rbs +33 -0
- data/sig/plugins/expect.rbs +19 -0
- data/sig/plugins/follow_redirects.rbs +37 -0
- data/sig/plugins/h2c.rbs +26 -0
- data/sig/plugins/multipart.rbs +19 -0
- data/sig/plugins/persistent.rbs +17 -0
- data/sig/plugins/proxy.rbs +47 -0
- data/sig/plugins/proxy/http.rbs +14 -0
- data/sig/plugins/proxy/socks4.rbs +33 -0
- data/sig/plugins/proxy/socks5.rbs +36 -0
- data/sig/plugins/proxy/ssh.rbs +18 -0
- data/sig/plugins/push_promise.rbs +22 -0
- data/sig/plugins/rate_limiter.rbs +11 -0
- data/sig/plugins/retries.rbs +48 -0
- data/sig/plugins/stream.rbs +39 -0
- data/sig/pool.rbs +2 -0
- data/sig/registry.rbs +9 -0
- data/sig/request.rbs +61 -0
- data/sig/response.rbs +87 -0
- data/sig/session.rbs +49 -0
- data/sig/test.rbs +9 -0
- data/sig/timeout.rbs +29 -0
- data/sig/transcoder.rbs +16 -0
- data/sig/transcoder/body.rbs +18 -0
- data/sig/transcoder/chunker.rbs +32 -0
- data/sig/transcoder/form.rbs +16 -0
- data/sig/transcoder/json.rbs +14 -0
- metadata +60 -17
data/lib/httpx/response.rb
CHANGED
@@ -75,11 +75,11 @@ module HTTPX
|
|
75
75
|
@status == 204 ||
|
76
76
|
@status == 205 ||
|
77
77
|
@status == 304 || begin
|
78
|
-
|
79
|
-
|
78
|
+
content_length = @headers["content-length"]
|
79
|
+
return false if content_length.nil?
|
80
80
|
|
81
|
-
|
82
|
-
|
81
|
+
content_length == "0"
|
82
|
+
end
|
83
83
|
end
|
84
84
|
|
85
85
|
class Body
|
@@ -95,6 +95,8 @@ module HTTPX
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def write(chunk)
|
98
|
+
return if @state == :closed
|
99
|
+
|
98
100
|
@length += chunk.bytesize
|
99
101
|
transition
|
100
102
|
@buffer.write(chunk)
|
@@ -116,7 +118,7 @@ module HTTPX
|
|
116
118
|
return enum_for(__method__) unless block_given?
|
117
119
|
|
118
120
|
begin
|
119
|
-
|
121
|
+
if @buffer
|
120
122
|
rewind
|
121
123
|
while (chunk = @buffer.read(@window_size))
|
122
124
|
yield(chunk.force_encoding(@encoding))
|
@@ -155,20 +157,19 @@ module HTTPX
|
|
155
157
|
if dest.respond_to?(:path) && @buffer.respond_to?(:path)
|
156
158
|
FileUtils.mv(@buffer.path, dest.path)
|
157
159
|
else
|
158
|
-
@buffer.rewind
|
159
160
|
::IO.copy_stream(@buffer, dest)
|
160
161
|
end
|
161
162
|
end
|
162
163
|
|
163
164
|
# closes/cleans the buffer, resets everything
|
164
165
|
def close
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
166
|
+
if @buffer
|
167
|
+
@buffer.close
|
168
|
+
@buffer.unlink if @buffer.respond_to?(:unlink)
|
169
|
+
@buffer = nil
|
170
|
+
end
|
170
171
|
@length = 0
|
171
|
-
@state = :
|
172
|
+
@state = :closed
|
172
173
|
end
|
173
174
|
|
174
175
|
def ==(other)
|
@@ -186,7 +187,7 @@ module HTTPX
|
|
186
187
|
private
|
187
188
|
|
188
189
|
def rewind
|
189
|
-
return
|
190
|
+
return unless @buffer
|
190
191
|
|
191
192
|
@buffer.rewind
|
192
193
|
end
|
@@ -267,15 +268,7 @@ module HTTPX
|
|
267
268
|
@error.message
|
268
269
|
end
|
269
270
|
|
270
|
-
def
|
271
|
-
@error.class.name
|
272
|
-
end
|
273
|
-
|
274
|
-
def headers
|
275
|
-
{}
|
276
|
-
end
|
277
|
-
|
278
|
-
def body
|
271
|
+
def to_s
|
279
272
|
@error.backtrace.join("\n")
|
280
273
|
end
|
281
274
|
|
@@ -285,7 +278,7 @@ module HTTPX
|
|
285
278
|
|
286
279
|
# rubocop:disable Style/MissingRespondToMissing
|
287
280
|
def method_missing(meth, *, &block)
|
288
|
-
raise NoMethodError, "undefined response method `#{meth}' for error response" if
|
281
|
+
raise NoMethodError, "undefined response method `#{meth}' for error response" if @options.response_class.public_method_defined?(meth)
|
289
282
|
|
290
283
|
super
|
291
284
|
end
|
data/lib/httpx/selector.rb
CHANGED
@@ -51,7 +51,7 @@ class HTTPX::Selector
|
|
51
51
|
READ_INTERESTS = %i[r rw].freeze
|
52
52
|
WRITE_INTERESTS = %i[w rw].freeze
|
53
53
|
|
54
|
-
def select_many(interval)
|
54
|
+
def select_many(interval, &block)
|
55
55
|
selectables, r, w = nil
|
56
56
|
|
57
57
|
# first, we group IOs based on interest type. On call to #interests however,
|
@@ -102,9 +102,7 @@ class HTTPX::Selector
|
|
102
102
|
writers.delete(io)
|
103
103
|
end if readers
|
104
104
|
|
105
|
-
writers.each
|
106
|
-
yield io
|
107
|
-
end if writers
|
105
|
+
writers.each(&block) if writers
|
108
106
|
end
|
109
107
|
|
110
108
|
def select_one(interval)
|
data/lib/httpx/session.rb
CHANGED
@@ -66,7 +66,8 @@ module HTTPX
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def find_connection(request, connections, options)
|
69
|
-
uri =
|
69
|
+
uri = request.uri
|
70
|
+
|
70
71
|
connection = pool.find_connection(uri, options) || build_connection(uri, options)
|
71
72
|
unless connections.nil? || connections.include?(connection)
|
72
73
|
connections << connection
|
@@ -135,10 +136,10 @@ module HTTPX
|
|
135
136
|
reqs.map do |verb, uri, opts = EMPTY_HASH|
|
136
137
|
build_request(verb, uri, request_options.merge(opts))
|
137
138
|
end
|
138
|
-
when 2
|
139
|
+
when 2
|
139
140
|
verb, uris = args
|
140
141
|
if uris.respond_to?(:each)
|
141
|
-
uris.map do |uri,
|
142
|
+
uris.enum_for(:each).map do |uri, opts = EMPTY_HASH|
|
142
143
|
build_request(verb, uri, request_options.merge(opts))
|
143
144
|
end
|
144
145
|
else
|
@@ -189,15 +190,13 @@ module HTTPX
|
|
189
190
|
begin
|
190
191
|
# guarantee ordered responses
|
191
192
|
loop do
|
192
|
-
|
193
|
-
|
194
|
-
pool.next_tick until (response = fetch_response(request, connections, request_options))
|
193
|
+
request = requests.first
|
194
|
+
pool.next_tick until (response = fetch_response(request, connections, request_options))
|
195
195
|
|
196
|
-
|
197
|
-
|
196
|
+
responses << response
|
197
|
+
requests.shift
|
198
198
|
|
199
|
-
|
200
|
-
end
|
199
|
+
break if requests.empty? || pool.empty?
|
201
200
|
end
|
202
201
|
responses
|
203
202
|
ensure
|
@@ -221,7 +220,7 @@ module HTTPX
|
|
221
220
|
def plugin(pl, options = nil, &block)
|
222
221
|
# raise Error, "Cannot add a plugin to a frozen config" if frozen?
|
223
222
|
pl = Plugins.load_plugin(pl) if pl.is_a?(Symbol)
|
224
|
-
|
223
|
+
if !@plugins.include?(pl)
|
225
224
|
@plugins << pl
|
226
225
|
pl.load_dependencies(self, &block) if pl.respond_to?(:load_dependencies)
|
227
226
|
@default_options = @default_options.dup
|
@@ -245,6 +244,13 @@ module HTTPX
|
|
245
244
|
opts.connection_class.__send__(:include, pl::ConnectionMethods) if defined?(pl::ConnectionMethods)
|
246
245
|
pl.configure(self, &block) if pl.respond_to?(:configure)
|
247
246
|
|
247
|
+
@default_options.freeze
|
248
|
+
elsif options
|
249
|
+
# this can happen when two plugins are loaded, an one of them calls the other under the hood,
|
250
|
+
# albeit changing some default.
|
251
|
+
@default_options = @default_options.dup
|
252
|
+
@default_options = @default_options.merge(options)
|
253
|
+
|
248
254
|
@default_options.freeze
|
249
255
|
end
|
250
256
|
self
|
@@ -14,8 +14,6 @@ module HTTPX::Transcoder
|
|
14
14
|
|
15
15
|
def_delegator :@raw, :bytesize
|
16
16
|
|
17
|
-
def_delegator :@raw, :force_encoding
|
18
|
-
|
19
17
|
def initialize(form)
|
20
18
|
@raw = URI.encode_www_form(form)
|
21
19
|
end
|
@@ -23,10 +21,6 @@ module HTTPX::Transcoder
|
|
23
21
|
def content_type
|
24
22
|
"application/x-www-form-urlencoded"
|
25
23
|
end
|
26
|
-
|
27
|
-
def to_str
|
28
|
-
@raw.to_s
|
29
|
-
end
|
30
24
|
end
|
31
25
|
|
32
26
|
def encode(form)
|
@@ -10,14 +10,10 @@ module HTTPX::Transcoder
|
|
10
10
|
class Encoder
|
11
11
|
extend Forwardable
|
12
12
|
|
13
|
-
def_delegator :@raw, :to_str
|
14
|
-
|
15
13
|
def_delegator :@raw, :to_s
|
16
14
|
|
17
15
|
def_delegator :@raw, :bytesize
|
18
16
|
|
19
|
-
def_delegator :@raw, :force_encoding
|
20
|
-
|
21
17
|
def initialize(json)
|
22
18
|
@raw = ::JSON.dump(json)
|
23
19
|
@charset = @raw.encoding.name.downcase
|
data/lib/httpx/utils.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTPX
|
4
|
+
module Utils
|
5
|
+
using URIExtensions
|
6
|
+
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# The value of this field can be either an HTTP-date or a number of
|
10
|
+
# seconds to delay after the response is received.
|
11
|
+
def parse_retry_after(retry_after)
|
12
|
+
# first: bet on it being an integer
|
13
|
+
Integer(retry_after)
|
14
|
+
rescue ArgumentError
|
15
|
+
# Then it's a datetime
|
16
|
+
time = Time.httpdate(retry_after)
|
17
|
+
time - Time.now
|
18
|
+
end
|
19
|
+
|
20
|
+
if RUBY_VERSION < "2.3"
|
21
|
+
def uri(*args)
|
22
|
+
URI(*args)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
|
26
|
+
URIParser = URI::RFC2396_Parser.new
|
27
|
+
|
28
|
+
def uri(uri)
|
29
|
+
return Kernel.URI(uri) unless uri.is_a?(String) && !uri.ascii_only?
|
30
|
+
|
31
|
+
uri = Kernel.URI(URIParser.escape(uri))
|
32
|
+
|
33
|
+
non_ascii_hostname = URIParser.unescape(uri.host)
|
34
|
+
|
35
|
+
non_ascii_hostname.force_encoding(Encoding::UTF_8)
|
36
|
+
|
37
|
+
idna_hostname = DomainName.new(non_ascii_hostname).hostname
|
38
|
+
|
39
|
+
uri.host = idna_hostname
|
40
|
+
uri.non_ascii_hostname = non_ascii_hostname
|
41
|
+
uri
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/httpx/version.rb
CHANGED
data/sig/buffer.rbs
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module HTTPX
|
2
|
+
class Buffer
|
3
|
+
include _ToS
|
4
|
+
include _ToStr
|
5
|
+
|
6
|
+
@buffer: String
|
7
|
+
|
8
|
+
attr_reader limit: Integer
|
9
|
+
|
10
|
+
def full?: () -> bool
|
11
|
+
def shift!: (Integer) -> void
|
12
|
+
|
13
|
+
# delegated
|
14
|
+
def <<: (string data) -> void
|
15
|
+
def empty?: () -> bool
|
16
|
+
def bytesize: () -> Integer
|
17
|
+
def clear: () -> void
|
18
|
+
def replace: (string) -> void
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def initialize: (Integer limit) -> untyped
|
23
|
+
end
|
24
|
+
end
|
data/sig/callbacks.rbs
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module HTTPX
|
2
|
+
interface _Callable
|
3
|
+
def call: (*untyped) -> void
|
4
|
+
end
|
5
|
+
|
6
|
+
module Callbacks
|
7
|
+
def on: (Symbol) { (*untyped) -> void } -> void
|
8
|
+
def once: (Symbol) { (*untyped) -> void } -> void
|
9
|
+
def emit: (Symbol, *untyped) -> void
|
10
|
+
|
11
|
+
def callbacks: () -> Hash[Symbol, Array[_Callable]]
|
12
|
+
| (Symbol) -> Array[_Callable]
|
13
|
+
end
|
14
|
+
end
|
data/sig/chainable.rbs
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module HTTPX
|
2
|
+
module Chainable
|
3
|
+
def request: (*untyped, **untyped) -> (response | Array[response])
|
4
|
+
def accept: (String) -> Session
|
5
|
+
def wrap: () { (Session) -> void } -> void
|
6
|
+
| () -> void
|
7
|
+
|
8
|
+
def with: (options) -> Session
|
9
|
+
| (options) { (Session) -> Session} -> Session
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
def plugin: (:authentication) -> Plugins::sessionAuthentication
|
15
|
+
| (:basic_authentication) -> Plugins::sessionBasicAuthentication
|
16
|
+
| (:digest_authentication) -> Plugins::sessionDigestAuthentication
|
17
|
+
| (:compression) -> Session
|
18
|
+
| (:cookies) -> Plugins::sessionCookies
|
19
|
+
| (:expect) -> Session
|
20
|
+
| (:follow_redirects) -> Plugins::sessionFollowRedirects
|
21
|
+
| (:h2c) -> Plugins::sessionH2C
|
22
|
+
| (:multipart) -> Session
|
23
|
+
| (:persistent) -> Plugins::sessionPersistent
|
24
|
+
| (:proxy) -> Plugins::sessionProxy
|
25
|
+
| (:push_promise) -> Plugins::sessionPushPromise
|
26
|
+
| (:retries) -> Plugins::sessionRetries
|
27
|
+
| (:stream) -> Plugins::sessionStream
|
28
|
+
| (Symbol | Module, ?options?) { (Class) -> void } -> Session
|
29
|
+
| (Symbol | Module, ?options?) -> Session
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def default_options: () -> Options
|
34
|
+
def branch: (options) -> Session
|
35
|
+
| (options) { (Session) -> Session } -> Session
|
36
|
+
end
|
37
|
+
end
|
data/sig/connection.rbs
ADDED
data/sig/domain_name.rbs
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module HTTPX
|
2
|
+
class DomainName
|
3
|
+
type domain = string | DomainName
|
4
|
+
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
def normalize: (String) -> String
|
8
|
+
|
9
|
+
def cookie_domain?: (domain, ?bool?) -> bool
|
10
|
+
|
11
|
+
def self.new: (domain) -> untyped
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def initialize: (string) -> untyped
|
16
|
+
end
|
17
|
+
end
|
data/sig/errors.rbs
ADDED
data/sig/headers.rbs
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module HTTPX
|
2
|
+
class Headers
|
3
|
+
include _ToS
|
4
|
+
|
5
|
+
@headers: headers_hash
|
6
|
+
|
7
|
+
def self.new: (?untyped headers) -> Headers
|
8
|
+
|
9
|
+
def ==: (untyped other) -> bool
|
10
|
+
|
11
|
+
def []: (headers_key field) -> _ToS?
|
12
|
+
def []=: (headers_key field, headers_value value) -> void
|
13
|
+
|
14
|
+
def add: (headers_key field, string value) -> void
|
15
|
+
def delete: (headers_key field) -> void
|
16
|
+
|
17
|
+
def each: () { (headers_key, String) -> void } -> void
|
18
|
+
| () -> Enumerable[[headers_key, String], void]
|
19
|
+
|
20
|
+
def get: (headers_key field) -> Array[String]
|
21
|
+
def key?: (headers_key downcased_key) -> bool
|
22
|
+
|
23
|
+
def merge: (_Each[headers_key, headers_value] other) -> Headers
|
24
|
+
|
25
|
+
def same_headers?: (untyped headers) -> bool
|
26
|
+
|
27
|
+
def to_a: () -> Array[[headers_key, String]]
|
28
|
+
def inspect: () -> String
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def initialize: (headers?) -> untyped
|
33
|
+
def array_value: (headers_value) -> Array[String]
|
34
|
+
def downcased: (headers_key) -> String
|
35
|
+
end
|
36
|
+
|
37
|
+
type headers_key = String | Symbol
|
38
|
+
type headers_value = _ToS | Array[_ToS]
|
39
|
+
type headers_hash = Hash[headers_key, headers_value]
|
40
|
+
type headers_input = headers_hash | Array[[headers_key, string]]
|
41
|
+
type headers = Headers | headers_input
|
42
|
+
end
|
data/sig/httpx.rbs
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module HTTPX
|
2
|
+
extend Chainable
|
3
|
+
|
4
|
+
VERSION: String
|
5
|
+
|
6
|
+
type uri = URI::HTTP | URI::HTTPS | string
|
7
|
+
|
8
|
+
type verb = :options | :get | :head | :post | :put | :delete | :trace | :connect |
|
9
|
+
:propfind | :proppatch | :mkcol | :copy | :move | :lock | :unlock | :orderpatch |
|
10
|
+
:acl | :report | :patch | :search
|
11
|
+
|
12
|
+
module Plugins
|
13
|
+
end
|
14
|
+
end
|