httpx 0.20.5 → 0.21.0
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_13_0.md +1 -1
- data/doc/release_notes/0_21_0.md +94 -0
- data/lib/httpx/connection/http1.rb +2 -1
- data/lib/httpx/connection.rb +41 -2
- data/lib/httpx/errors.rb +18 -0
- data/lib/httpx/extensions.rb +8 -4
- data/lib/httpx/io/unix.rb +1 -1
- data/lib/httpx/options.rb +7 -3
- data/lib/httpx/plugins/circuit_breaker/circuit.rb +76 -0
- data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +44 -0
- data/lib/httpx/plugins/circuit_breaker.rb +115 -0
- data/lib/httpx/plugins/cookies.rb +1 -1
- data/lib/httpx/plugins/expect.rb +1 -1
- data/lib/httpx/plugins/multipart/decoder.rb +1 -1
- data/lib/httpx/plugins/proxy.rb +7 -1
- data/lib/httpx/plugins/retries.rb +1 -1
- data/lib/httpx/plugins/webdav.rb +78 -0
- data/lib/httpx/request.rb +15 -25
- data/lib/httpx/resolver/https.rb +2 -7
- data/lib/httpx/resolver/native.rb +2 -1
- data/lib/httpx/response.rb +27 -9
- data/lib/httpx/timers.rb +3 -0
- data/lib/httpx/transcoder/form.rb +1 -1
- data/lib/httpx/transcoder/json.rb +19 -3
- data/lib/httpx/transcoder/xml.rb +57 -0
- data/lib/httpx/transcoder.rb +1 -0
- data/lib/httpx/version.rb +1 -1
- data/sig/buffer.rbs +1 -1
- data/sig/chainable.rbs +1 -0
- data/sig/connection.rbs +12 -4
- data/sig/errors.rbs +13 -0
- data/sig/io.rbs +6 -0
- data/sig/options.rbs +4 -1
- data/sig/plugins/circuit_breaker.rbs +61 -0
- data/sig/plugins/compression/brotli.rbs +1 -1
- data/sig/plugins/compression/deflate.rbs +1 -1
- data/sig/plugins/compression/gzip.rbs +3 -3
- data/sig/plugins/compression.rbs +1 -1
- data/sig/plugins/multipart.rbs +1 -1
- data/sig/plugins/proxy/socks5.rbs +3 -2
- data/sig/plugins/proxy.rbs +1 -1
- data/sig/registry.rbs +5 -4
- data/sig/request.rbs +7 -1
- data/sig/resolver/native.rbs +5 -2
- data/sig/response.rbs +3 -1
- data/sig/timers.rbs +1 -1
- data/sig/transcoder/json.rbs +4 -1
- data/sig/transcoder/xml.rbs +21 -0
- data/sig/transcoder.rbs +2 -2
- data/sig/utils.rbs +2 -2
- metadata +12 -2
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTPX
|
4
|
+
module Plugins
|
5
|
+
#
|
6
|
+
# This plugin implements convenience methods for performing WEBDAV requests.
|
7
|
+
#
|
8
|
+
# https://gitlab.com/honeyryderchuck/httpx/wikis/WEBDAV
|
9
|
+
#
|
10
|
+
module WebDav
|
11
|
+
module InstanceMethods
|
12
|
+
def copy(src, dest)
|
13
|
+
request(:copy, src, headers: { "destination" => @options.origin.merge(dest) })
|
14
|
+
end
|
15
|
+
|
16
|
+
def move(src, dest)
|
17
|
+
request(:move, src, headers: { "destination" => @options.origin.merge(dest) })
|
18
|
+
end
|
19
|
+
|
20
|
+
def lock(path, timeout: nil, &blk)
|
21
|
+
headers = {}
|
22
|
+
headers["timeout"] = if timeout && timeout.positive?
|
23
|
+
"Second-#{timeout}"
|
24
|
+
else
|
25
|
+
"Infinite, Second-4100000000"
|
26
|
+
end
|
27
|
+
xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" \
|
28
|
+
"<D:lockinfo xmlns:D=\"DAV:\">" \
|
29
|
+
"<D:lockscope><D:exclusive/></D:lockscope>" \
|
30
|
+
"<D:locktype><D:write/></D:locktype>" \
|
31
|
+
"<D:owner>null</D:owner>" \
|
32
|
+
"</D:lockinfo>"
|
33
|
+
response = request(:lock, path, headers: headers, xml: xml)
|
34
|
+
|
35
|
+
return response unless blk && response.status == 200
|
36
|
+
|
37
|
+
lock_token = response.headers["lock-token"]
|
38
|
+
|
39
|
+
begin
|
40
|
+
blk.call(response)
|
41
|
+
ensure
|
42
|
+
unlock(path, lock_token)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def unlock(path, lock_token)
|
47
|
+
request(:unlock, path, headers: { "lock-token" => lock_token })
|
48
|
+
end
|
49
|
+
|
50
|
+
def mkcol(dir)
|
51
|
+
request(:mkcol, dir)
|
52
|
+
end
|
53
|
+
|
54
|
+
def propfind(path, xml = nil)
|
55
|
+
body = case xml
|
56
|
+
when :acl
|
57
|
+
'<?xml version="1.0" encoding="utf-8" ?><D:propfind xmlns:D="DAV:"><D:prop><D:owner/>' \
|
58
|
+
"<D:supported-privilege-set/><D:current-user-privilege-set/><D:acl/></D:prop></D:propfind>"
|
59
|
+
when nil
|
60
|
+
'<?xml version="1.0" encoding="utf-8"?><DAV:propfind xmlns:DAV="DAV:"><DAV:allprop/></DAV:propfind>'
|
61
|
+
else
|
62
|
+
xml
|
63
|
+
end
|
64
|
+
|
65
|
+
request(:propfind, path, headers: { "depth" => "1" }, xml: body)
|
66
|
+
end
|
67
|
+
|
68
|
+
def proppatch(path, xml)
|
69
|
+
body = "<?xml version=\"1.0\"?>" \
|
70
|
+
"<D:propertyupdate xmlns:D=\"DAV:\" xmlns:Z=\"http://ns.example.com/standards/z39.50/\">#{xml}</D:propertyupdate>"
|
71
|
+
request(:proppatch, path, xml: body)
|
72
|
+
end
|
73
|
+
# %i[ orderpatch acl report search]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
register_plugin(:webdav, WebDav)
|
77
|
+
end
|
78
|
+
end
|
data/lib/httpx/request.rb
CHANGED
@@ -9,29 +9,6 @@ module HTTPX
|
|
9
9
|
include Callbacks
|
10
10
|
using URIExtensions
|
11
11
|
|
12
|
-
METHODS = [
|
13
|
-
# RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
|
14
|
-
:options, :get, :head, :post, :put, :delete, :trace, :connect,
|
15
|
-
|
16
|
-
# RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV
|
17
|
-
:propfind, :proppatch, :mkcol, :copy, :move, :lock, :unlock,
|
18
|
-
|
19
|
-
# RFC 3648: WebDAV Ordered Collections Protocol
|
20
|
-
:orderpatch,
|
21
|
-
|
22
|
-
# RFC 3744: WebDAV Access Control Protocol
|
23
|
-
:acl,
|
24
|
-
|
25
|
-
# RFC 6352: vCard Extensions to WebDAV -- CardDAV
|
26
|
-
:report,
|
27
|
-
|
28
|
-
# RFC 5789: PATCH Method for HTTP
|
29
|
-
:patch,
|
30
|
-
|
31
|
-
# draft-reschke-webdav-search: WebDAV Search
|
32
|
-
:search
|
33
|
-
].freeze
|
34
|
-
|
35
12
|
USER_AGENT = "httpx.rb/#{VERSION}"
|
36
13
|
|
37
14
|
attr_reader :verb, :uri, :headers, :body, :state, :options, :response
|
@@ -54,8 +31,6 @@ module HTTPX
|
|
54
31
|
@uri = origin.merge("#{base_path}#{@uri}")
|
55
32
|
end
|
56
33
|
|
57
|
-
raise(Error, "unknown method: #{verb}") unless METHODS.include?(@verb)
|
58
|
-
|
59
34
|
@headers = @options.headers_class.new(@options.headers)
|
60
35
|
@headers["user-agent"] ||= USER_AGENT
|
61
36
|
@headers["accept"] ||= "*/*"
|
@@ -64,6 +39,18 @@ module HTTPX
|
|
64
39
|
@state = :idle
|
65
40
|
end
|
66
41
|
|
42
|
+
def read_timeout
|
43
|
+
@options.timeout[:read_timeout]
|
44
|
+
end
|
45
|
+
|
46
|
+
def write_timeout
|
47
|
+
@options.timeout[:write_timeout]
|
48
|
+
end
|
49
|
+
|
50
|
+
def request_timeout
|
51
|
+
@options.timeout[:request_timeout]
|
52
|
+
end
|
53
|
+
|
67
54
|
def trailers?
|
68
55
|
defined?(@trailers)
|
69
56
|
end
|
@@ -108,6 +95,7 @@ module HTTPX
|
|
108
95
|
|
109
96
|
def path
|
110
97
|
path = uri.path.dup
|
98
|
+
path = +"" if path.nil?
|
111
99
|
path << "/" if path.empty?
|
112
100
|
path << "?#{query}" unless query.empty?
|
113
101
|
path
|
@@ -174,6 +162,8 @@ module HTTPX
|
|
174
162
|
Transcoder.registry("form").encode(options.form)
|
175
163
|
elsif options.json
|
176
164
|
Transcoder.registry("json").encode(options.json)
|
165
|
+
elsif options.xml
|
166
|
+
Transcoder.registry("xml").encode(options.xml)
|
177
167
|
end
|
178
168
|
return if @body.nil?
|
179
169
|
|
data/lib/httpx/resolver/https.rb
CHANGED
@@ -102,7 +102,7 @@ module HTTPX
|
|
102
102
|
@requests[request] = hostname
|
103
103
|
resolver_connection.send(request)
|
104
104
|
@connections << connection
|
105
|
-
rescue ResolveError, Resolv::DNS::EncodeError
|
105
|
+
rescue ResolveError, Resolv::DNS::EncodeError => e
|
106
106
|
@queries.delete(hostname)
|
107
107
|
emit_resolve_error(connection, connection.origin.host, e)
|
108
108
|
end
|
@@ -129,7 +129,7 @@ module HTTPX
|
|
129
129
|
def parse(request, response)
|
130
130
|
begin
|
131
131
|
answers = decode_response_body(response)
|
132
|
-
rescue Resolv::DNS::DecodeError
|
132
|
+
rescue Resolv::DNS::DecodeError => e
|
133
133
|
host, connection = @queries.first
|
134
134
|
@queries.delete(host)
|
135
135
|
emit_resolve_error(connection, connection.origin.host, e)
|
@@ -203,11 +203,6 @@ module HTTPX
|
|
203
203
|
|
204
204
|
def decode_response_body(response)
|
205
205
|
case response.headers["content-type"]
|
206
|
-
when "application/dns-json",
|
207
|
-
"application/json",
|
208
|
-
%r{^application/x-javascript} # because google...
|
209
|
-
payload = JSON.parse(response.to_s)
|
210
|
-
payload["Answer"]
|
211
206
|
when "application/dns-udpwireformat",
|
212
207
|
"application/dns-message"
|
213
208
|
Resolver.decode_dns_answer(response.to_s)
|
@@ -77,7 +77,8 @@ module HTTPX
|
|
77
77
|
nil
|
78
78
|
rescue Errno::EHOSTUNREACH => e
|
79
79
|
@ns_index += 1
|
80
|
-
|
80
|
+
nameserver = @nameserver
|
81
|
+
if nameserver && @ns_index < nameserver.size
|
81
82
|
log { "resolver: failed resolving on nameserver #{@nameserver[@ns_index - 1]} (#{e.message})" }
|
82
83
|
transition(:idle)
|
83
84
|
else
|
data/lib/httpx/response.rb
CHANGED
@@ -31,6 +31,7 @@ module HTTPX
|
|
31
31
|
@status = Integer(status)
|
32
32
|
@headers = @options.headers_class.new(headers)
|
33
33
|
@body = @options.response_body_class.new(self, @options)
|
34
|
+
@finished = complete?
|
34
35
|
end
|
35
36
|
|
36
37
|
def merge_headers(h)
|
@@ -41,15 +42,24 @@ module HTTPX
|
|
41
42
|
@body.write(data)
|
42
43
|
end
|
43
44
|
|
45
|
+
def content_type
|
46
|
+
@content_type ||= ContentType.new(@headers["content-type"])
|
47
|
+
end
|
48
|
+
|
49
|
+
def finished?
|
50
|
+
@finished
|
51
|
+
end
|
52
|
+
|
53
|
+
def finish!
|
54
|
+
@finished = true
|
55
|
+
@headers.freeze
|
56
|
+
end
|
57
|
+
|
44
58
|
def bodyless?
|
45
59
|
@request.verb == :head ||
|
46
60
|
no_data?
|
47
61
|
end
|
48
62
|
|
49
|
-
def content_type
|
50
|
-
@content_type ||= ContentType.new(@headers["content-type"])
|
51
|
-
end
|
52
|
-
|
53
63
|
def complete?
|
54
64
|
bodyless? || (@request.verb == :connect && @status == 200)
|
55
65
|
end
|
@@ -76,17 +86,21 @@ module HTTPX
|
|
76
86
|
raise err
|
77
87
|
end
|
78
88
|
|
79
|
-
def json(
|
80
|
-
decode("json",
|
89
|
+
def json(*args)
|
90
|
+
decode("json", *args)
|
81
91
|
end
|
82
92
|
|
83
93
|
def form
|
84
94
|
decode("form")
|
85
95
|
end
|
86
96
|
|
97
|
+
def xml
|
98
|
+
decode("xml")
|
99
|
+
end
|
100
|
+
|
87
101
|
private
|
88
102
|
|
89
|
-
def decode(format,
|
103
|
+
def decode(format, *args)
|
90
104
|
# TODO: check if content-type is a valid format, i.e. "application/json" for json parsing
|
91
105
|
transcoder = Transcoder.registry(format)
|
92
106
|
|
@@ -96,13 +110,13 @@ module HTTPX
|
|
96
110
|
|
97
111
|
raise Error, "no decoder available for \"#{format}\"" unless decoder
|
98
112
|
|
99
|
-
decoder.call(self,
|
113
|
+
decoder.call(self, *args)
|
100
114
|
rescue Registry::Error
|
101
115
|
raise Error, "no decoder available for \"#{format}\""
|
102
116
|
end
|
103
117
|
|
104
118
|
def no_data?
|
105
|
-
@status < 200 ||
|
119
|
+
@status < 200 || # informational response
|
106
120
|
@status == 204 ||
|
107
121
|
@status == 205 ||
|
108
122
|
@status == 304 || begin
|
@@ -339,6 +353,10 @@ module HTTPX
|
|
339
353
|
end
|
340
354
|
end
|
341
355
|
|
356
|
+
def finished?
|
357
|
+
true
|
358
|
+
end
|
359
|
+
|
342
360
|
def raise_for_status
|
343
361
|
raise @error
|
344
362
|
end
|
data/lib/httpx/timers.rb
CHANGED
@@ -37,9 +37,12 @@ module HTTPX
|
|
37
37
|
elapsed_time = Utils.elapsed_time(@next_interval_at)
|
38
38
|
|
39
39
|
@intervals.delete_if { |interval| interval.elapse(elapsed_time) <= 0 }
|
40
|
+
|
41
|
+
@next_interval_at = nil if @intervals.empty?
|
40
42
|
end
|
41
43
|
|
42
44
|
def cancel
|
45
|
+
@next_interval_at = nil
|
43
46
|
@intervals.clear
|
44
47
|
end
|
45
48
|
|
@@ -36,7 +36,7 @@ module HTTPX::Transcoder
|
|
36
36
|
module Decoder
|
37
37
|
module_function
|
38
38
|
|
39
|
-
def call(response,
|
39
|
+
def call(response, *)
|
40
40
|
URI.decode_www_form(response.to_s).each_with_object({}) do |(field, value), params|
|
41
41
|
HTTPX::Transcoder.normalize_query(params, field, value, PARAM_DEPTH_LIMIT)
|
42
42
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "forwardable"
|
4
|
-
require "json"
|
5
4
|
|
6
5
|
module HTTPX::Transcoder
|
7
6
|
module JSON
|
@@ -19,7 +18,7 @@ module HTTPX::Transcoder
|
|
19
18
|
def_delegator :@raw, :bytesize
|
20
19
|
|
21
20
|
def initialize(json)
|
22
|
-
@raw =
|
21
|
+
@raw = JSON.json_dump(json)
|
23
22
|
@charset = @raw.encoding.name.downcase
|
24
23
|
end
|
25
24
|
|
@@ -37,8 +36,25 @@ module HTTPX::Transcoder
|
|
37
36
|
|
38
37
|
raise HTTPX::Error, "invalid json mime type (#{content_type})" unless JSON_REGEX.match?(content_type)
|
39
38
|
|
40
|
-
|
39
|
+
method(:json_load)
|
41
40
|
end
|
41
|
+
|
42
|
+
# rubocop:disable Style/SingleLineMethods
|
43
|
+
if defined?(MultiJson)
|
44
|
+
def json_load(*args); MultiJson.load(*args); end
|
45
|
+
def json_dump(*args); MultiJson.dump(*args); end
|
46
|
+
elsif defined?(Oj)
|
47
|
+
def json_load(response, *args); Oj.load(response.to_s, *args); end
|
48
|
+
def json_dump(*args); Oj.dump(*args); end
|
49
|
+
elsif defined?(Yajl)
|
50
|
+
def json_load(response, *args); Yajl::Parser.new(*args).parse(response.to_s); end
|
51
|
+
def json_dump(*args); Yajl::Encoder.encode(*args); end
|
52
|
+
else
|
53
|
+
require "json"
|
54
|
+
def json_load(*args); ::JSON.parse(*args); end
|
55
|
+
def json_dump(*args); ::JSON.dump(*args); end
|
56
|
+
end
|
57
|
+
# rubocop:enable Style/SingleLineMethods
|
42
58
|
end
|
43
59
|
register "json", JSON
|
44
60
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
require "forwardable"
|
5
|
+
require "uri"
|
6
|
+
|
7
|
+
module HTTPX::Transcoder
|
8
|
+
module Xml
|
9
|
+
using HTTPX::RegexpExtensions
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
MIME_TYPES = %r{\b(application|text)/(.+\+)?xml\b}.freeze
|
14
|
+
|
15
|
+
class Encoder
|
16
|
+
def initialize(xml)
|
17
|
+
@raw = xml
|
18
|
+
end
|
19
|
+
|
20
|
+
def content_type
|
21
|
+
charset = @raw.respond_to?(:encoding) ? @raw.encoding.to_s.downcase : "utf-8"
|
22
|
+
"application/xml; charset=#{charset}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def bytesize
|
26
|
+
@raw.to_s.bytesize
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
@raw.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def encode(xml)
|
35
|
+
Encoder.new(xml)
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
require "nokogiri"
|
40
|
+
|
41
|
+
# rubocop:disable Lint/DuplicateMethods
|
42
|
+
def decode(response)
|
43
|
+
content_type = response.content_type.mime_type
|
44
|
+
|
45
|
+
raise HTTPX::Error, "invalid form mime type (#{content_type})" unless MIME_TYPES.match?(content_type)
|
46
|
+
|
47
|
+
Nokogiri::XML.method(:parse)
|
48
|
+
end
|
49
|
+
rescue LoadError
|
50
|
+
def decode(_response)
|
51
|
+
raise HTTPX::Error, "\"nokogiri\" is required in order to decode XML"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
# rubocop:enable Lint/DuplicateMethods
|
55
|
+
end
|
56
|
+
register "xml", Xml
|
57
|
+
end
|
data/lib/httpx/transcoder.rb
CHANGED
data/lib/httpx/version.rb
CHANGED
data/sig/buffer.rbs
CHANGED
data/sig/chainable.rbs
CHANGED
@@ -33,6 +33,7 @@ module HTTPX
|
|
33
33
|
| (:aws_sigv4, ?options) -> Plugins::awsSigV4Session
|
34
34
|
| (:grpc, ?options) -> Plugins::grpcSession
|
35
35
|
| (:response_cache, ?options) -> Plugins::sessionResponseCache
|
36
|
+
| (:circuit_breaker, ?options) -> Plugins::sessionCircuitBreaker
|
36
37
|
| (Symbol | Module, ?options) { (Class) -> void } -> Session
|
37
38
|
| (Symbol | Module, ?options) -> Session
|
38
39
|
|
data/sig/connection.rbs
CHANGED
@@ -28,7 +28,7 @@ module HTTPX
|
|
28
28
|
attr_reader options: Options
|
29
29
|
attr_writer timers: Timers
|
30
30
|
|
31
|
-
@
|
31
|
+
@type: io_type
|
32
32
|
@window_size: Integer
|
33
33
|
@read_buffer: Buffer
|
34
34
|
@write_buffer: Buffer
|
@@ -40,7 +40,7 @@ module HTTPX
|
|
40
40
|
|
41
41
|
def addresses=: (Array[ipaddr]) -> void
|
42
42
|
|
43
|
-
def match?: (URI::Generic, options) -> bool
|
43
|
+
def match?: (URI::Generic uri, Options options) -> bool
|
44
44
|
|
45
45
|
def mergeable?: (Connection) -> bool
|
46
46
|
|
@@ -54,13 +54,15 @@ module HTTPX
|
|
54
54
|
|
55
55
|
def match_altsvcs?: (URI::Generic uri) -> bool
|
56
56
|
|
57
|
+
def match_altsvc_options?: (URI::Generic uri, Options options) -> bool
|
58
|
+
|
57
59
|
def connecting?: () -> bool
|
58
60
|
|
59
61
|
def inflight?: () -> boolish
|
60
62
|
|
61
63
|
def interests: () -> io_interests?
|
62
64
|
|
63
|
-
def to_io: () -> IO
|
65
|
+
def to_io: () -> ::IO
|
64
66
|
|
65
67
|
def call: () -> void
|
66
68
|
|
@@ -77,7 +79,7 @@ module HTTPX
|
|
77
79
|
|
78
80
|
private
|
79
81
|
|
80
|
-
def initialize: (
|
82
|
+
def initialize: (io_type, URI::Generic, options) -> untyped
|
81
83
|
|
82
84
|
def connect: () -> void
|
83
85
|
|
@@ -103,5 +105,11 @@ module HTTPX
|
|
103
105
|
def handle_error: (StandardError) -> void
|
104
106
|
|
105
107
|
def purge_after_closed: () -> void
|
108
|
+
|
109
|
+
def set_request_timeouts: (Request request) -> void
|
110
|
+
|
111
|
+
def write_timeout_callback: (Request request, Numeric write_timeout) -> void
|
112
|
+
|
113
|
+
def read_timeout_callback: (Request request, Numeric read_timeout, ?singleton(RequestTimeoutError) error_type) -> void
|
106
114
|
end
|
107
115
|
end
|
data/sig/errors.rbs
CHANGED
@@ -23,6 +23,19 @@ module HTTPX
|
|
23
23
|
class ResolveTimeoutError < TimeoutError
|
24
24
|
end
|
25
25
|
|
26
|
+
class RequestTimeoutError < TimeoutError
|
27
|
+
attr_reader request: Request
|
28
|
+
attr_reader response: response?
|
29
|
+
|
30
|
+
def initialize: (Request request, response? response, Numeric timeout) -> void
|
31
|
+
end
|
32
|
+
|
33
|
+
class ReadTimeoutError < RequestTimeoutError
|
34
|
+
end
|
35
|
+
|
36
|
+
class WriteTimeoutError < RequestTimeoutError
|
37
|
+
end
|
38
|
+
|
26
39
|
class ResolveError < Error
|
27
40
|
end
|
28
41
|
|
data/sig/io.rbs
ADDED
data/sig/options.rbs
CHANGED
@@ -10,7 +10,7 @@ module HTTPX
|
|
10
10
|
SETTINGS_TIMEOUT: Integer
|
11
11
|
DEFAULT_OPTIONS: Hash[Symbol, untyped]
|
12
12
|
|
13
|
-
type timeout_type = :connect_timeout | :settings_timeout | :operation_timeout | :keep_alive_timeout | :total_timeout
|
13
|
+
type timeout_type = :connect_timeout | :settings_timeout | :operation_timeout | :keep_alive_timeout | :total_timeout | :read_timeout | :write_timeout | :request_timeout
|
14
14
|
type timeout = Hash[timeout_type, Numeric]
|
15
15
|
|
16
16
|
def self.new: (?options) -> instance
|
@@ -65,6 +65,9 @@ module HTTPX
|
|
65
65
|
# body
|
66
66
|
attr_reader origin: URI::Generic?
|
67
67
|
|
68
|
+
# base_path
|
69
|
+
attr_reader base_path: String?
|
70
|
+
|
68
71
|
# ssl
|
69
72
|
|
70
73
|
# http2_settings
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module HTTPX
|
2
|
+
module Plugins
|
3
|
+
module CircuitBreaker
|
4
|
+
|
5
|
+
class CircuitStore
|
6
|
+
@circuits: Hash[String, Circuit]
|
7
|
+
|
8
|
+
def try_open: (generic_uri uri, response response) -> void
|
9
|
+
|
10
|
+
def try_respond: (Request request) -> response?
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def get_circuit_for_uri: (generic_uri uri) -> Circuit
|
15
|
+
|
16
|
+
def initialize: (Options & _CircuitOptions options) -> void
|
17
|
+
end
|
18
|
+
|
19
|
+
class Circuit
|
20
|
+
@state: :closed | :open | :half_open
|
21
|
+
@max_attempts: Integer
|
22
|
+
@reset_attempts_in: Float
|
23
|
+
@break_in: Float
|
24
|
+
@circuit_breaker_half_open_drip_rate: Float
|
25
|
+
@attempts: Integer
|
26
|
+
|
27
|
+
@response: response?
|
28
|
+
@opened_at: Float?
|
29
|
+
@attempted_at: Float?
|
30
|
+
|
31
|
+
def respond: () -> response?
|
32
|
+
|
33
|
+
def try_open: (response) -> void
|
34
|
+
|
35
|
+
def try_close: () -> void
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def initialize: (Integer max_attempts, Float reset_attempts_in, Float break_in, Float circuit_breaker_half_open_drip_rate) -> void
|
40
|
+
end
|
41
|
+
|
42
|
+
interface _CircuitOptions
|
43
|
+
def circuit_breaker_max_attempts: () -> Integer
|
44
|
+
def circuit_breaker_reset_attempts_in: () -> Float
|
45
|
+
def circuit_breaker_break_in: () -> Float
|
46
|
+
def circuit_breaker_half_open_drip_rate: () -> Float
|
47
|
+
def circuit_breaker_break_on: () -> (^(Response) -> boolish | nil)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.load_dependencies: (singleton(Session)) -> void
|
51
|
+
def self.extra_options: (Options) -> (Options & _CircuitOptions)
|
52
|
+
|
53
|
+
module InstanceMethods
|
54
|
+
@circuit_store: CircuitStore
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
type sessionCircuitBreaker = Session & CircuitBreaker::InstanceMethods
|
60
|
+
end
|
61
|
+
end
|
@@ -6,7 +6,7 @@ module HTTPX
|
|
6
6
|
def self.configure: (singleton(Session)) -> void
|
7
7
|
|
8
8
|
def self?.deflater: () -> _Deflater
|
9
|
-
def self?.inflater: (
|
9
|
+
def self?.inflater: (Integer | Float bytesize) -> GZIP::Inflater
|
10
10
|
|
11
11
|
module Deflater
|
12
12
|
extend _Deflater
|
@@ -6,15 +6,15 @@ module HTTPX
|
|
6
6
|
def self.configure: (singleton(Session)) -> void
|
7
7
|
|
8
8
|
def self?.deflater: () -> _Deflater
|
9
|
-
def self?.inflater: (
|
9
|
+
def self?.inflater: (Integer | Float bytesize) -> Inflater
|
10
10
|
|
11
11
|
class Deflater
|
12
12
|
include _Deflater
|
13
13
|
|
14
14
|
@compressed_chunk: String
|
15
|
-
|
15
|
+
|
16
16
|
private
|
17
|
-
|
17
|
+
|
18
18
|
def initialize: () -> untyped
|
19
19
|
def write: (string) -> void
|
20
20
|
def compressed_chunk: () -> String
|
data/sig/plugins/compression.rbs
CHANGED
data/sig/plugins/multipart.rbs
CHANGED
@@ -4,14 +4,15 @@ module HTTPX
|
|
4
4
|
module Plugins
|
5
5
|
module Proxy
|
6
6
|
module Socks5
|
7
|
-
|
7
|
+
VERSION: Integer
|
8
|
+
|
8
9
|
module ConnectionMethods
|
9
10
|
def __socks5_proxy_connect: () -> void
|
10
11
|
def __socks5_on_packet: (String packet) -> void
|
11
12
|
def __socks5_check_version: (int) -> void
|
12
13
|
def __on_socks5_error: (string) -> void
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
class SocksParser
|
16
17
|
include Callbacks
|
17
18
|
|