httpx 0.20.5 → 0.21.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/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
|
|