httpx-patched 1.6.2.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 +7 -0
- data/LICENSE.txt +191 -0
- data/README.md +162 -0
- data/doc/release_notes/0_0_1.md +7 -0
- data/doc/release_notes/0_0_2.md +9 -0
- data/doc/release_notes/0_0_3.md +9 -0
- data/doc/release_notes/0_0_4.md +7 -0
- data/doc/release_notes/0_0_5.md +5 -0
- data/doc/release_notes/0_10_0.md +66 -0
- data/doc/release_notes/0_10_1.md +37 -0
- data/doc/release_notes/0_10_2.md +5 -0
- data/doc/release_notes/0_11_0.md +74 -0
- data/doc/release_notes/0_11_1.md +5 -0
- data/doc/release_notes/0_11_2.md +5 -0
- data/doc/release_notes/0_11_3.md +5 -0
- data/doc/release_notes/0_12_0.md +55 -0
- 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/doc/release_notes/0_14_2.md +6 -0
- data/doc/release_notes/0_14_3.md +5 -0
- data/doc/release_notes/0_14_4.md +5 -0
- data/doc/release_notes/0_14_5.md +11 -0
- data/doc/release_notes/0_15_0.md +53 -0
- data/doc/release_notes/0_15_1.md +8 -0
- data/doc/release_notes/0_15_2.md +9 -0
- data/doc/release_notes/0_15_3.md +5 -0
- data/doc/release_notes/0_15_4.md +5 -0
- data/doc/release_notes/0_16_0.md +93 -0
- data/doc/release_notes/0_16_1.md +5 -0
- data/doc/release_notes/0_17_0.md +49 -0
- data/doc/release_notes/0_18_0.md +69 -0
- data/doc/release_notes/0_18_1.md +12 -0
- data/doc/release_notes/0_18_2.md +10 -0
- data/doc/release_notes/0_18_3.md +7 -0
- data/doc/release_notes/0_18_4.md +14 -0
- data/doc/release_notes/0_18_5.md +10 -0
- data/doc/release_notes/0_18_6.md +5 -0
- data/doc/release_notes/0_18_7.md +5 -0
- data/doc/release_notes/0_19_0.md +39 -0
- data/doc/release_notes/0_19_1.md +5 -0
- data/doc/release_notes/0_19_2.md +7 -0
- data/doc/release_notes/0_19_3.md +6 -0
- data/doc/release_notes/0_19_4.md +14 -0
- data/doc/release_notes/0_19_5.md +13 -0
- data/doc/release_notes/0_19_6.md +5 -0
- data/doc/release_notes/0_19_7.md +5 -0
- data/doc/release_notes/0_19_8.md +5 -0
- data/doc/release_notes/0_1_0.md +9 -0
- data/doc/release_notes/0_20_0.md +36 -0
- data/doc/release_notes/0_20_1.md +5 -0
- data/doc/release_notes/0_20_2.md +7 -0
- data/doc/release_notes/0_20_3.md +6 -0
- data/doc/release_notes/0_20_4.md +17 -0
- data/doc/release_notes/0_20_5.md +3 -0
- data/doc/release_notes/0_21_0.md +96 -0
- data/doc/release_notes/0_21_1.md +12 -0
- data/doc/release_notes/0_22_0.md +13 -0
- data/doc/release_notes/0_22_1.md +11 -0
- data/doc/release_notes/0_22_2.md +5 -0
- data/doc/release_notes/0_22_3.md +55 -0
- data/doc/release_notes/0_22_4.md +6 -0
- data/doc/release_notes/0_22_5.md +6 -0
- data/doc/release_notes/0_23_0.md +42 -0
- data/doc/release_notes/0_23_1.md +5 -0
- data/doc/release_notes/0_23_2.md +5 -0
- data/doc/release_notes/0_23_3.md +6 -0
- data/doc/release_notes/0_23_4.md +5 -0
- data/doc/release_notes/0_24_0.md +48 -0
- data/doc/release_notes/0_24_1.md +12 -0
- data/doc/release_notes/0_24_2.md +12 -0
- data/doc/release_notes/0_24_3.md +12 -0
- data/doc/release_notes/0_24_4.md +18 -0
- data/doc/release_notes/0_24_5.md +6 -0
- data/doc/release_notes/0_24_6.md +5 -0
- data/doc/release_notes/0_24_7.md +10 -0
- data/doc/release_notes/0_2_0.md +5 -0
- data/doc/release_notes/0_2_1.md +16 -0
- data/doc/release_notes/0_3_0.md +12 -0
- data/doc/release_notes/0_3_1.md +6 -0
- data/doc/release_notes/0_4_0.md +51 -0
- data/doc/release_notes/0_4_1.md +3 -0
- data/doc/release_notes/0_5_0.md +15 -0
- data/doc/release_notes/0_5_1.md +14 -0
- data/doc/release_notes/0_6_0.md +5 -0
- data/doc/release_notes/0_6_1.md +6 -0
- data/doc/release_notes/0_6_2.md +6 -0
- data/doc/release_notes/0_6_3.md +13 -0
- data/doc/release_notes/0_6_4.md +21 -0
- data/doc/release_notes/0_6_5.md +22 -0
- data/doc/release_notes/0_6_6.md +19 -0
- data/doc/release_notes/0_6_7.md +5 -0
- data/doc/release_notes/0_7_0.md +46 -0
- data/doc/release_notes/0_8_0.md +27 -0
- data/doc/release_notes/0_8_1.md +8 -0
- data/doc/release_notes/0_8_2.md +7 -0
- data/doc/release_notes/0_9_0.md +38 -0
- data/doc/release_notes/1_0_0.md +60 -0
- data/doc/release_notes/1_0_1.md +5 -0
- data/doc/release_notes/1_0_2.md +7 -0
- data/doc/release_notes/1_1_0.md +32 -0
- data/doc/release_notes/1_1_1.md +17 -0
- data/doc/release_notes/1_1_2.md +12 -0
- data/doc/release_notes/1_1_3.md +18 -0
- data/doc/release_notes/1_1_4.md +6 -0
- data/doc/release_notes/1_1_5.md +12 -0
- data/doc/release_notes/1_2_0.md +49 -0
- data/doc/release_notes/1_2_1.md +6 -0
- data/doc/release_notes/1_2_2.md +10 -0
- data/doc/release_notes/1_2_3.md +16 -0
- data/doc/release_notes/1_2_4.md +8 -0
- data/doc/release_notes/1_2_5.md +7 -0
- data/doc/release_notes/1_2_6.md +13 -0
- data/doc/release_notes/1_3_0.md +18 -0
- data/doc/release_notes/1_3_1.md +17 -0
- data/doc/release_notes/1_3_2.md +6 -0
- data/doc/release_notes/1_3_3.md +5 -0
- data/doc/release_notes/1_3_4.md +6 -0
- data/doc/release_notes/1_4_0.md +43 -0
- data/doc/release_notes/1_4_1.md +19 -0
- data/doc/release_notes/1_4_2.md +20 -0
- data/doc/release_notes/1_4_3.md +11 -0
- data/doc/release_notes/1_4_4.md +14 -0
- data/doc/release_notes/1_5_0.md +126 -0
- data/doc/release_notes/1_5_1.md +6 -0
- data/doc/release_notes/1_6_0.md +50 -0
- data/doc/release_notes/1_6_1.md +17 -0
- data/doc/release_notes/1_6_2.md +11 -0
- data/lib/httpx/adapters/datadog.rb +359 -0
- data/lib/httpx/adapters/faraday.rb +303 -0
- data/lib/httpx/adapters/sentry.rb +121 -0
- data/lib/httpx/adapters/webmock.rb +175 -0
- data/lib/httpx/altsvc.rb +163 -0
- data/lib/httpx/base64.rb +27 -0
- data/lib/httpx/buffer.rb +61 -0
- data/lib/httpx/callbacks.rb +35 -0
- data/lib/httpx/chainable.rb +106 -0
- data/lib/httpx/connection/http1.rb +399 -0
- data/lib/httpx/connection/http2.rb +468 -0
- data/lib/httpx/connection.rb +954 -0
- data/lib/httpx/domain_name.rb +145 -0
- data/lib/httpx/errors.rb +111 -0
- data/lib/httpx/extensions.rb +59 -0
- data/lib/httpx/headers.rb +176 -0
- data/lib/httpx/io/ssl.rb +163 -0
- data/lib/httpx/io/tcp.rb +239 -0
- data/lib/httpx/io/udp.rb +62 -0
- data/lib/httpx/io/unix.rb +71 -0
- data/lib/httpx/io.rb +11 -0
- data/lib/httpx/loggable.rb +56 -0
- data/lib/httpx/options.rb +463 -0
- data/lib/httpx/parser/http1.rb +186 -0
- data/lib/httpx/plugins/auth/basic.rb +20 -0
- data/lib/httpx/plugins/auth/digest.rb +102 -0
- data/lib/httpx/plugins/auth/ntlm.rb +35 -0
- data/lib/httpx/plugins/auth/socks5.rb +22 -0
- data/lib/httpx/plugins/auth.rb +25 -0
- data/lib/httpx/plugins/aws_sdk_authentication.rb +111 -0
- data/lib/httpx/plugins/aws_sigv4.rb +239 -0
- data/lib/httpx/plugins/basic_auth.rb +29 -0
- data/lib/httpx/plugins/brotli.rb +50 -0
- data/lib/httpx/plugins/callbacks.rb +127 -0
- data/lib/httpx/plugins/circuit_breaker/circuit.rb +100 -0
- data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +53 -0
- data/lib/httpx/plugins/circuit_breaker.rb +147 -0
- data/lib/httpx/plugins/content_digest.rb +204 -0
- data/lib/httpx/plugins/cookies/cookie.rb +174 -0
- data/lib/httpx/plugins/cookies/jar.rb +95 -0
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +143 -0
- data/lib/httpx/plugins/cookies.rb +107 -0
- data/lib/httpx/plugins/digest_auth.rb +67 -0
- data/lib/httpx/plugins/expect.rb +120 -0
- data/lib/httpx/plugins/fiber_concurrency.rb +195 -0
- data/lib/httpx/plugins/follow_redirects.rb +233 -0
- data/lib/httpx/plugins/grpc/call.rb +63 -0
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +90 -0
- data/lib/httpx/plugins/grpc/message.rb +55 -0
- data/lib/httpx/plugins/grpc.rb +282 -0
- data/lib/httpx/plugins/h2c.rb +127 -0
- data/lib/httpx/plugins/internal_telemetry.rb +107 -0
- data/lib/httpx/plugins/ntlm_auth.rb +62 -0
- data/lib/httpx/plugins/oauth.rb +183 -0
- data/lib/httpx/plugins/persistent.rb +82 -0
- data/lib/httpx/plugins/proxy/http.rb +184 -0
- data/lib/httpx/plugins/proxy/socks4.rb +135 -0
- data/lib/httpx/plugins/proxy/socks5.rb +194 -0
- data/lib/httpx/plugins/proxy/ssh.rb +94 -0
- data/lib/httpx/plugins/proxy.rb +349 -0
- data/lib/httpx/plugins/push_promise.rb +81 -0
- data/lib/httpx/plugins/query.rb +35 -0
- data/lib/httpx/plugins/rate_limiter.rb +55 -0
- data/lib/httpx/plugins/response_cache/file_store.rb +140 -0
- data/lib/httpx/plugins/response_cache/store.rb +33 -0
- data/lib/httpx/plugins/response_cache.rb +333 -0
- data/lib/httpx/plugins/retries.rb +230 -0
- data/lib/httpx/plugins/ssrf_filter.rb +145 -0
- data/lib/httpx/plugins/stream.rb +183 -0
- data/lib/httpx/plugins/stream_bidi.rb +315 -0
- data/lib/httpx/plugins/upgrade/h2.rb +64 -0
- data/lib/httpx/plugins/upgrade.rb +86 -0
- data/lib/httpx/plugins/webdav.rb +86 -0
- data/lib/httpx/plugins/xml.rb +76 -0
- data/lib/httpx/pmatch_extensions.rb +33 -0
- data/lib/httpx/pool.rb +190 -0
- data/lib/httpx/punycode.rb +22 -0
- data/lib/httpx/request/body.rb +158 -0
- data/lib/httpx/request.rb +328 -0
- data/lib/httpx/resolver/entry.rb +30 -0
- data/lib/httpx/resolver/https.rb +256 -0
- data/lib/httpx/resolver/multi.rb +102 -0
- data/lib/httpx/resolver/native.rb +547 -0
- data/lib/httpx/resolver/resolver.rb +173 -0
- data/lib/httpx/resolver/system.rb +255 -0
- data/lib/httpx/resolver.rb +189 -0
- data/lib/httpx/response/body.rb +242 -0
- data/lib/httpx/response/buffer.rb +115 -0
- data/lib/httpx/response.rb +304 -0
- data/lib/httpx/selector.rb +282 -0
- data/lib/httpx/session.rb +612 -0
- data/lib/httpx/session_extensions.rb +30 -0
- data/lib/httpx/timers.rb +133 -0
- data/lib/httpx/transcoder/body.rb +43 -0
- data/lib/httpx/transcoder/chunker.rb +115 -0
- data/lib/httpx/transcoder/deflate.rb +37 -0
- data/lib/httpx/transcoder/form.rb +68 -0
- data/lib/httpx/transcoder/gzip.rb +71 -0
- data/lib/httpx/transcoder/json.rb +71 -0
- data/lib/httpx/transcoder/multipart/decoder.rb +141 -0
- data/lib/httpx/transcoder/multipart/encoder.rb +120 -0
- data/lib/httpx/transcoder/multipart/mime_type_detector.rb +78 -0
- data/lib/httpx/transcoder/multipart/part.rb +35 -0
- data/lib/httpx/transcoder/multipart.rb +31 -0
- data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
- data/lib/httpx/transcoder/utils/deflater.rb +75 -0
- data/lib/httpx/transcoder.rb +91 -0
- data/lib/httpx/utils.rb +75 -0
- data/lib/httpx/version.rb +5 -0
- data/lib/httpx.rb +66 -0
- data/sig/altsvc.rbs +33 -0
- data/sig/buffer.rbs +27 -0
- data/sig/callbacks.rbs +15 -0
- data/sig/chainable.rbs +55 -0
- data/sig/connection/http1.rbs +85 -0
- data/sig/connection/http2.rbs +116 -0
- data/sig/connection.rbs +169 -0
- data/sig/domain_name.rbs +17 -0
- data/sig/errors.rbs +69 -0
- data/sig/headers.rbs +49 -0
- data/sig/httpx.rbs +27 -0
- data/sig/io/ssl.rbs +27 -0
- data/sig/io/tcp.rbs +72 -0
- data/sig/io/udp.rbs +25 -0
- data/sig/io/unix.rbs +26 -0
- data/sig/io.rbs +3 -0
- data/sig/loggable.rbs +17 -0
- data/sig/options.rbs +202 -0
- data/sig/parser/http1.rbs +59 -0
- data/sig/plugins/auth/basic.rbs +17 -0
- data/sig/plugins/auth/digest.rbs +25 -0
- data/sig/plugins/auth/ntlm.rbs +20 -0
- data/sig/plugins/auth/socks5.rbs +18 -0
- data/sig/plugins/auth.rbs +13 -0
- data/sig/plugins/aws_sdk_authentication.rbs +43 -0
- data/sig/plugins/aws_sigv4.rbs +78 -0
- data/sig/plugins/basic_auth.rbs +15 -0
- data/sig/plugins/brotli.rbs +22 -0
- data/sig/plugins/callbacks.rbs +38 -0
- data/sig/plugins/circuit_breaker.rbs +71 -0
- data/sig/plugins/compression.rbs +57 -0
- data/sig/plugins/content_digest.rbs +51 -0
- data/sig/plugins/cookies/cookie.rbs +55 -0
- data/sig/plugins/cookies/jar.rbs +26 -0
- data/sig/plugins/cookies/set_cookie_parser.rbs +22 -0
- data/sig/plugins/cookies.rbs +28 -0
- data/sig/plugins/digest_auth.rbs +21 -0
- data/sig/plugins/expect.rbs +15 -0
- data/sig/plugins/fiber_concurrency.rbs +51 -0
- data/sig/plugins/follow_redirects.rbs +47 -0
- data/sig/plugins/grpc/call.rbs +23 -0
- data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
- data/sig/plugins/grpc/message.rbs +17 -0
- data/sig/plugins/grpc.rbs +65 -0
- data/sig/plugins/h2c.rbs +27 -0
- data/sig/plugins/ntlm_auth.rbs +21 -0
- data/sig/plugins/oauth.rbs +68 -0
- data/sig/plugins/persistent.rbs +14 -0
- data/sig/plugins/proxy/http.rbs +30 -0
- data/sig/plugins/proxy/socks4.rbs +37 -0
- data/sig/plugins/proxy/socks5.rbs +49 -0
- data/sig/plugins/proxy/ssh.rbs +18 -0
- data/sig/plugins/proxy.rbs +70 -0
- data/sig/plugins/push_promise.rbs +23 -0
- data/sig/plugins/query.rbs +18 -0
- data/sig/plugins/rate_limiter.rbs +13 -0
- data/sig/plugins/response_cache/file_store.rbs +19 -0
- data/sig/plugins/response_cache/store.rbs +13 -0
- data/sig/plugins/response_cache.rbs +86 -0
- data/sig/plugins/retries.rbs +66 -0
- data/sig/plugins/ssrf_filter.rbs +26 -0
- data/sig/plugins/stream.rbs +54 -0
- data/sig/plugins/stream_bidi.rbs +68 -0
- data/sig/plugins/upgrade/h2.rbs +9 -0
- data/sig/plugins/upgrade.rbs +29 -0
- data/sig/plugins/webdav.rbs +23 -0
- data/sig/plugins/xml.rbs +37 -0
- data/sig/pool.rbs +51 -0
- data/sig/punycode.rbs +5 -0
- data/sig/request/body.rbs +34 -0
- data/sig/request.rbs +88 -0
- data/sig/resolver/entry.rbs +13 -0
- data/sig/resolver/https.rbs +45 -0
- data/sig/resolver/multi.rbs +32 -0
- data/sig/resolver/native.rbs +74 -0
- data/sig/resolver/resolver.rbs +64 -0
- data/sig/resolver/system.rbs +34 -0
- data/sig/resolver.rbs +48 -0
- data/sig/response/body.rbs +52 -0
- data/sig/response/buffer.rbs +23 -0
- data/sig/response.rbs +103 -0
- data/sig/selector.rbs +68 -0
- data/sig/session.rbs +104 -0
- data/sig/timers.rbs +54 -0
- data/sig/transcoder/body.rbs +24 -0
- data/sig/transcoder/chunker.rbs +49 -0
- data/sig/transcoder/deflate.rbs +12 -0
- data/sig/transcoder/form.rbs +34 -0
- data/sig/transcoder/gzip.rbs +27 -0
- data/sig/transcoder/json.rbs +28 -0
- data/sig/transcoder/multipart.rbs +103 -0
- data/sig/transcoder/utils/body_reader.rbs +15 -0
- data/sig/transcoder/utils/deflater.rbs +28 -0
- data/sig/transcoder.rbs +43 -0
- data/sig/utils.rbs +19 -0
- metadata +518 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "delegate"
|
|
4
|
+
require "stringio"
|
|
5
|
+
require "tempfile"
|
|
6
|
+
|
|
7
|
+
module HTTPX
|
|
8
|
+
# wraps and delegates to an internal buffer, which can be a StringIO or a Tempfile.
|
|
9
|
+
class Response::Buffer < SimpleDelegator
|
|
10
|
+
attr_reader :buffer
|
|
11
|
+
protected :buffer
|
|
12
|
+
|
|
13
|
+
# initializes buffer with the +threshold_size+ over which the payload gets buffer to a tempfile,
|
|
14
|
+
# the initial +bytesize+, and the +encoding+.
|
|
15
|
+
def initialize(threshold_size:, bytesize: 0, encoding: Encoding::BINARY)
|
|
16
|
+
@threshold_size = threshold_size
|
|
17
|
+
@bytesize = bytesize
|
|
18
|
+
@encoding = encoding
|
|
19
|
+
@buffer = StringIO.new("".b)
|
|
20
|
+
super(@buffer)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def initialize_dup(other)
|
|
24
|
+
super
|
|
25
|
+
|
|
26
|
+
# create new descriptor in READ-ONLY mode
|
|
27
|
+
@buffer =
|
|
28
|
+
case other.buffer
|
|
29
|
+
when StringIO
|
|
30
|
+
StringIO.new(other.buffer.string, mode: File::RDONLY)
|
|
31
|
+
else
|
|
32
|
+
other.buffer.class.new(other.buffer.path, encoding: Encoding::BINARY, mode: File::RDONLY).tap do |temp|
|
|
33
|
+
FileUtils.copy_file(other.buffer.path, temp.path)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# size in bytes of the buffered content.
|
|
39
|
+
def size
|
|
40
|
+
@bytesize
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# writes the +chunk+ into the buffer.
|
|
44
|
+
def write(chunk)
|
|
45
|
+
@bytesize += chunk.bytesize
|
|
46
|
+
try_upgrade_buffer
|
|
47
|
+
@buffer.write(chunk)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# returns the buffered content as a string.
|
|
51
|
+
def to_s
|
|
52
|
+
case @buffer
|
|
53
|
+
when StringIO
|
|
54
|
+
begin
|
|
55
|
+
@buffer.string.force_encoding(@encoding)
|
|
56
|
+
rescue ArgumentError
|
|
57
|
+
@buffer.string
|
|
58
|
+
end
|
|
59
|
+
when Tempfile
|
|
60
|
+
rewind
|
|
61
|
+
content = @buffer.read
|
|
62
|
+
begin
|
|
63
|
+
content.force_encoding(@encoding)
|
|
64
|
+
rescue ArgumentError # ex: unknown encoding name - utf
|
|
65
|
+
content
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# closes the buffer.
|
|
71
|
+
def close
|
|
72
|
+
@buffer.close
|
|
73
|
+
@buffer.unlink if @buffer.respond_to?(:unlink)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def ==(other)
|
|
77
|
+
super || begin
|
|
78
|
+
return false unless other.is_a?(Response::Buffer)
|
|
79
|
+
|
|
80
|
+
buffer_pos = @buffer.pos
|
|
81
|
+
other_pos = other.buffer.pos
|
|
82
|
+
@buffer.rewind
|
|
83
|
+
other.buffer.rewind
|
|
84
|
+
begin
|
|
85
|
+
FileUtils.compare_stream(@buffer, other.buffer)
|
|
86
|
+
ensure
|
|
87
|
+
@buffer.pos = buffer_pos
|
|
88
|
+
other.buffer.pos = other_pos
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
# initializes the buffer into a StringIO, or turns it into a Tempfile when the threshold
|
|
96
|
+
# has been reached.
|
|
97
|
+
def try_upgrade_buffer
|
|
98
|
+
return unless @bytesize > @threshold_size
|
|
99
|
+
|
|
100
|
+
return if @buffer.is_a?(Tempfile)
|
|
101
|
+
|
|
102
|
+
aux = @buffer
|
|
103
|
+
|
|
104
|
+
@buffer = Tempfile.new("httpx", encoding: Encoding::BINARY, mode: File::RDWR)
|
|
105
|
+
|
|
106
|
+
if aux
|
|
107
|
+
aux.rewind
|
|
108
|
+
IO.copy_stream(aux, @buffer)
|
|
109
|
+
aux.close
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
__setobj__(@buffer)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "objspace"
|
|
4
|
+
require "stringio"
|
|
5
|
+
require "tempfile"
|
|
6
|
+
require "fileutils"
|
|
7
|
+
require "forwardable"
|
|
8
|
+
|
|
9
|
+
module HTTPX
|
|
10
|
+
# Defines a HTTP response is handled internally, with a few properties exposed as attributes.
|
|
11
|
+
#
|
|
12
|
+
# It delegates the following methods to the corresponding HTTPX::Request:
|
|
13
|
+
#
|
|
14
|
+
# * HTTPX::Request#uri
|
|
15
|
+
# * HTTPX::Request#peer_address
|
|
16
|
+
#
|
|
17
|
+
# It implements (indirectly, via the +body+) the IO write protocol to internally buffer payloads.
|
|
18
|
+
#
|
|
19
|
+
# It implements the IO reader protocol in order for users to buffer/stream it, acts as an enumerable
|
|
20
|
+
# (of payload chunks).
|
|
21
|
+
#
|
|
22
|
+
class Response
|
|
23
|
+
extend Forwardable
|
|
24
|
+
include Callbacks
|
|
25
|
+
|
|
26
|
+
# the HTTP response status code
|
|
27
|
+
attr_reader :status
|
|
28
|
+
|
|
29
|
+
# an HTTPX::Headers object containing the response HTTP headers.
|
|
30
|
+
attr_reader :headers
|
|
31
|
+
|
|
32
|
+
# a HTTPX::Response::Body object wrapping the response body. The following methods are delegated to it:
|
|
33
|
+
#
|
|
34
|
+
# * HTTPX::Response::Body#to_s
|
|
35
|
+
# * HTTPX::Response::Body#to_str
|
|
36
|
+
# * HTTPX::Response::Body#read
|
|
37
|
+
# * HTTPX::Response::Body#copy_to
|
|
38
|
+
# * HTTPX::Response::Body#close
|
|
39
|
+
attr_reader :body
|
|
40
|
+
|
|
41
|
+
# The HTTP protocol version used to fetch the response.
|
|
42
|
+
attr_reader :version
|
|
43
|
+
|
|
44
|
+
# returns the response body buffered in a string.
|
|
45
|
+
def_delegator :@body, :to_s
|
|
46
|
+
|
|
47
|
+
def_delegator :@body, :to_str
|
|
48
|
+
|
|
49
|
+
# implements the IO reader +#read+ interface.
|
|
50
|
+
def_delegator :@body, :read
|
|
51
|
+
|
|
52
|
+
# copies the response body to a different location.
|
|
53
|
+
def_delegator :@body, :copy_to
|
|
54
|
+
|
|
55
|
+
# the corresponding request uri.
|
|
56
|
+
def_delegator :@request, :uri
|
|
57
|
+
|
|
58
|
+
# the IP address of the peer server.
|
|
59
|
+
def_delegator :@request, :peer_address
|
|
60
|
+
|
|
61
|
+
# inits the instance with the corresponding +request+ to this response, an the
|
|
62
|
+
# response HTTP +status+, +version+ and HTTPX::Headers instance of +headers+.
|
|
63
|
+
def initialize(request, status, version, headers)
|
|
64
|
+
@request = request
|
|
65
|
+
@options = request.options
|
|
66
|
+
@version = version
|
|
67
|
+
@status = Integer(status)
|
|
68
|
+
@headers = @options.headers_class.new(headers)
|
|
69
|
+
@body = @options.response_body_class.new(self, @options)
|
|
70
|
+
@finished = complete?
|
|
71
|
+
@content_type = nil
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# dupped initialization
|
|
75
|
+
def initialize_dup(orig)
|
|
76
|
+
super
|
|
77
|
+
# if a response gets dupped, the body handle must also get dupped to prevent
|
|
78
|
+
# two responses from using the same file handle to read.
|
|
79
|
+
@body = orig.body.dup
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# closes the respective +@request+ and +@body+.
|
|
83
|
+
def close
|
|
84
|
+
@request.close
|
|
85
|
+
@body.close
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# merges headers defined in +h+ into the response headers.
|
|
89
|
+
def merge_headers(h)
|
|
90
|
+
@headers = @headers.merge(h)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# writes +data+ chunk into the response body.
|
|
94
|
+
def <<(data)
|
|
95
|
+
@body.write(data)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# returns the HTTPX::ContentType for the response, as per what's declared in the content-type header.
|
|
99
|
+
#
|
|
100
|
+
# response.content_type #=> #<HTTPX::ContentType:xxx @header_value="text/plain">
|
|
101
|
+
# response.content_type.mime_type #=> "text/plain"
|
|
102
|
+
def content_type
|
|
103
|
+
@content_type ||= ContentType.new(@headers["content-type"])
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# returns whether the response has been fully fetched.
|
|
107
|
+
def finished?
|
|
108
|
+
@finished
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# marks the response as finished, freezes the headers.
|
|
112
|
+
def finish!
|
|
113
|
+
@finished = true
|
|
114
|
+
@headers.freeze
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# returns whether the response contains body payload.
|
|
118
|
+
def bodyless?
|
|
119
|
+
@request.verb == "HEAD" ||
|
|
120
|
+
@status < 200 || # informational response
|
|
121
|
+
@status == 204 ||
|
|
122
|
+
@status == 205 ||
|
|
123
|
+
@status == 304 || begin
|
|
124
|
+
content_length = @headers["content-length"]
|
|
125
|
+
return false if content_length.nil?
|
|
126
|
+
|
|
127
|
+
content_length == "0"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def complete?
|
|
132
|
+
bodyless? || (@request.verb == "CONNECT" && @status == 200)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# :nocov:
|
|
136
|
+
def inspect
|
|
137
|
+
"#<#{self.class}:#{object_id} " \
|
|
138
|
+
"HTTP/#{version} " \
|
|
139
|
+
"@status=#{@status} " \
|
|
140
|
+
"@headers=#{@headers} " \
|
|
141
|
+
"@body=#{@body.bytesize}>"
|
|
142
|
+
end
|
|
143
|
+
# :nocov:
|
|
144
|
+
|
|
145
|
+
# returns an instance of HTTPX::HTTPError if the response has a 4xx or 5xx
|
|
146
|
+
# status code, or nothing.
|
|
147
|
+
#
|
|
148
|
+
# ok_response.error #=> nil
|
|
149
|
+
# not_found_response.error #=> HTTPX::HTTPError instance, status 404
|
|
150
|
+
def error
|
|
151
|
+
return if @status < 400
|
|
152
|
+
|
|
153
|
+
HTTPError.new(self)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# it raises the exception returned by +error+, or itself otherwise.
|
|
157
|
+
#
|
|
158
|
+
# ok_response.raise_for_status #=> ok_response
|
|
159
|
+
# not_found_response.raise_for_status #=> raises HTTPX::HTTPError exception
|
|
160
|
+
def raise_for_status
|
|
161
|
+
return self unless (err = error)
|
|
162
|
+
|
|
163
|
+
raise err
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# decodes the response payload into a ruby object **if** the payload is valid json.
|
|
167
|
+
#
|
|
168
|
+
# response.json #≈> { "foo" => "bar" } for "{\"foo\":\"bar\"}" payload
|
|
169
|
+
# response.json(symbolize_names: true) #≈> { foo: "bar" } for "{\"foo\":\"bar\"}" payload
|
|
170
|
+
def json(*args)
|
|
171
|
+
decode(Transcoder::JSON, *args)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# decodes the response payload into a ruby object **if** the payload is valid
|
|
175
|
+
# "application/x-www-urlencoded" or "multipart/form-data".
|
|
176
|
+
def form
|
|
177
|
+
decode(Transcoder::Form)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def xml
|
|
181
|
+
# TODO: remove at next major version.
|
|
182
|
+
warn "DEPRECATION WARNING: calling `.#{__method__}` on plain HTTPX responses is deprecated. " \
|
|
183
|
+
"Use HTTPX.plugin(:xml) sessions and call `.#{__method__}` in its responses instead."
|
|
184
|
+
require "httpx/plugins/xml"
|
|
185
|
+
decode(Plugins::XML::Transcoder)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
private
|
|
189
|
+
|
|
190
|
+
# decodes the response payload using the given +transcoder+, which implements the decoding logic.
|
|
191
|
+
#
|
|
192
|
+
# +transcoder+ must implement the internal transcoder API, i.e. respond to <tt>decode(HTTPX::Response response)</tt>,
|
|
193
|
+
# which returns a decoder which responds to <tt>call(HTTPX::Response response, **kwargs)</tt>
|
|
194
|
+
def decode(transcoder, *args)
|
|
195
|
+
# TODO: check if content-type is a valid format, i.e. "application/json" for json parsing
|
|
196
|
+
|
|
197
|
+
decoder = transcoder.decode(self)
|
|
198
|
+
|
|
199
|
+
raise Error, "no decoder available for \"#{transcoder}\"" unless decoder
|
|
200
|
+
|
|
201
|
+
@body.rewind
|
|
202
|
+
|
|
203
|
+
decoder.call(self, *args)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Helper class which decodes the HTTP "content-type" header.
|
|
208
|
+
class ContentType
|
|
209
|
+
MIME_TYPE_RE = %r{^([^/]+/[^;]+)(?:$|;)}.freeze
|
|
210
|
+
CHARSET_RE = /;\s*charset=([^;]+)/i.freeze
|
|
211
|
+
|
|
212
|
+
def initialize(header_value)
|
|
213
|
+
@header_value = header_value
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# returns the mime type declared in the header.
|
|
217
|
+
#
|
|
218
|
+
# ContentType.new("application/json; charset=utf-8").mime_type #=> "application/json"
|
|
219
|
+
def mime_type
|
|
220
|
+
return @mime_type if defined?(@mime_type)
|
|
221
|
+
|
|
222
|
+
m = @header_value.to_s[MIME_TYPE_RE, 1]
|
|
223
|
+
m && @mime_type = m.strip.downcase
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# returns the charset declared in the header.
|
|
227
|
+
#
|
|
228
|
+
# ContentType.new("application/json; charset=utf-8").charset #=> "utf-8"
|
|
229
|
+
# ContentType.new("text/plain").charset #=> nil
|
|
230
|
+
def charset
|
|
231
|
+
return @charset if defined?(@charset)
|
|
232
|
+
|
|
233
|
+
m = @header_value.to_s[CHARSET_RE, 1]
|
|
234
|
+
m && @charset = m.strip.delete('"')
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Wraps an error which has happened while processing an HTTP Request. It has partial
|
|
239
|
+
# public API parity with HTTPX::Response, so users should rely on it to infer whether
|
|
240
|
+
# the returned response is one or the other.
|
|
241
|
+
#
|
|
242
|
+
# response = HTTPX.get("https://some-domain/path") #=> response is HTTPX::Response or HTTPX::ErrorResponse
|
|
243
|
+
# response.raise_for_status #=> raises if it wraps an error
|
|
244
|
+
class ErrorResponse
|
|
245
|
+
include Loggable
|
|
246
|
+
extend Forwardable
|
|
247
|
+
|
|
248
|
+
# the corresponding HTTPX::Request instance.
|
|
249
|
+
attr_reader :request
|
|
250
|
+
|
|
251
|
+
# the HTTPX::Response instance, when there is one (i.e. error happens fetching the response).
|
|
252
|
+
attr_reader :response
|
|
253
|
+
|
|
254
|
+
# the wrapped exception.
|
|
255
|
+
attr_reader :error
|
|
256
|
+
|
|
257
|
+
# the request uri
|
|
258
|
+
def_delegator :@request, :uri
|
|
259
|
+
|
|
260
|
+
# the IP address of the peer server.
|
|
261
|
+
def_delegator :@request, :peer_address
|
|
262
|
+
|
|
263
|
+
def initialize(request, error)
|
|
264
|
+
@request = request
|
|
265
|
+
@response = request.response if request.response.is_a?(Response)
|
|
266
|
+
@error = error
|
|
267
|
+
@options = request.options
|
|
268
|
+
log_exception(@error)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# returns the exception full message.
|
|
272
|
+
def to_s
|
|
273
|
+
@error.full_message(highlight: false)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# closes the error resources.
|
|
277
|
+
def close
|
|
278
|
+
@response.close if @response
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# always true for error responses.
|
|
282
|
+
def finished?
|
|
283
|
+
true
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def finish!; end
|
|
287
|
+
|
|
288
|
+
# raises the wrapped exception.
|
|
289
|
+
def raise_for_status
|
|
290
|
+
raise @error
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# buffers lost chunks to error response
|
|
294
|
+
def <<(data)
|
|
295
|
+
return unless @response
|
|
296
|
+
|
|
297
|
+
@response << data
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
require_relative "response/body"
|
|
303
|
+
require_relative "response/buffer"
|
|
304
|
+
require_relative "pmatch_extensions" if RUBY_VERSION >= "2.7.0"
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "io/wait"
|
|
4
|
+
|
|
5
|
+
module HTTPX
|
|
6
|
+
#
|
|
7
|
+
# Implements the selector loop, where it registers and monitors "Selectable" objects.
|
|
8
|
+
#
|
|
9
|
+
# A Selectable object is an object which can calculate the **interests** (<tt>:r</tt>, <tt>:w</tt> or <tt>:rw</tt>,
|
|
10
|
+
# respectively "read", "write" or "read-write") it wants to monitor for, and returns (via <tt>to_io</tt> method) an
|
|
11
|
+
# IO object which can be passed to functions such as IO.select . More exhaustively, a Selectable **must** implement
|
|
12
|
+
# the following methods:
|
|
13
|
+
#
|
|
14
|
+
# state :: returns the state as a Symbol, must return <tt>:closed</tt> when disposed of resources.
|
|
15
|
+
# to_io :: returns the IO object.
|
|
16
|
+
# call :: gets called when the IO is ready.
|
|
17
|
+
# interests :: returns the current interests to monitor for, as described above.
|
|
18
|
+
# timeout :: returns nil or an integer, representing how long to wait for interests.
|
|
19
|
+
# handle_socket_timeout(Numeric) :: called when waiting for interest times out.
|
|
20
|
+
#
|
|
21
|
+
class Selector
|
|
22
|
+
extend Forwardable
|
|
23
|
+
|
|
24
|
+
READABLE = %i[rw r].freeze
|
|
25
|
+
WRITABLE = %i[rw w].freeze
|
|
26
|
+
|
|
27
|
+
private_constant :READABLE
|
|
28
|
+
private_constant :WRITABLE
|
|
29
|
+
|
|
30
|
+
def_delegator :@timers, :after
|
|
31
|
+
|
|
32
|
+
def_delegator :@selectables, :empty?
|
|
33
|
+
|
|
34
|
+
def initialize
|
|
35
|
+
@timers = Timers.new
|
|
36
|
+
@selectables = []
|
|
37
|
+
@is_timer_interval = false
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def each(&blk)
|
|
41
|
+
@selectables.each(&blk)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def next_tick
|
|
45
|
+
catch(:jump_tick) do
|
|
46
|
+
timeout = next_timeout
|
|
47
|
+
if timeout && timeout.negative?
|
|
48
|
+
@timers.fire
|
|
49
|
+
throw(:jump_tick)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
begin
|
|
53
|
+
select(timeout) do |c|
|
|
54
|
+
c.log(level: 2) { "[#{c.state}] selected#{" after #{timeout} secs" unless timeout.nil?}..." }
|
|
55
|
+
|
|
56
|
+
c.call
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@timers.fire
|
|
60
|
+
rescue TimeoutError => e
|
|
61
|
+
@timers.fire(e)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
rescue StandardError => e
|
|
65
|
+
each_connection do |c|
|
|
66
|
+
c.emit(:error, e)
|
|
67
|
+
end
|
|
68
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
|
69
|
+
each_connection do |conn|
|
|
70
|
+
conn.force_reset
|
|
71
|
+
conn.disconnect
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
raise
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def terminate
|
|
78
|
+
# array may change during iteration
|
|
79
|
+
selectables = @selectables.reject(&:inflight?)
|
|
80
|
+
|
|
81
|
+
selectables.delete_if do |sel|
|
|
82
|
+
sel.terminate
|
|
83
|
+
sel.state == :closed
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
until selectables.empty?
|
|
87
|
+
next_tick
|
|
88
|
+
|
|
89
|
+
selectables &= @selectables
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def find_resolver(options)
|
|
94
|
+
res = @selectables.find do |c|
|
|
95
|
+
c.is_a?(Resolver::Resolver) && options == c.options
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
res.multi if res
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def each_connection(&block)
|
|
102
|
+
return enum_for(__method__) unless block
|
|
103
|
+
|
|
104
|
+
@selectables.each do |c|
|
|
105
|
+
case c
|
|
106
|
+
when Resolver::Resolver
|
|
107
|
+
c.each_connection(&block)
|
|
108
|
+
when Connection
|
|
109
|
+
yield c
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def find_connection(request_uri, options)
|
|
115
|
+
each_connection.find do |connection|
|
|
116
|
+
connection.match?(request_uri, options)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def find_mergeable_connection(connection)
|
|
121
|
+
each_connection.find do |ch|
|
|
122
|
+
ch != connection && ch.mergeable?(connection)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# deregisters +io+ from selectables.
|
|
127
|
+
def deregister(io)
|
|
128
|
+
@selectables.delete(io)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# register +io+.
|
|
132
|
+
def register(io)
|
|
133
|
+
return if @selectables.include?(io)
|
|
134
|
+
|
|
135
|
+
@selectables << io
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
def select(interval, &block)
|
|
141
|
+
has_no_selectables = @selectables.empty?
|
|
142
|
+
# do not cause an infinite loop here.
|
|
143
|
+
#
|
|
144
|
+
# this may happen if timeout calculation actually triggered an error which causes
|
|
145
|
+
# the connections to be reaped (such as the total timeout error) before #select
|
|
146
|
+
# gets called.
|
|
147
|
+
return if interval.nil? && has_no_selectables
|
|
148
|
+
|
|
149
|
+
# @type var r: (selectable | Array[selectable])?
|
|
150
|
+
# @type var w: (selectable | Array[selectable])?
|
|
151
|
+
r, w = nil
|
|
152
|
+
|
|
153
|
+
@selectables.delete_if do |io|
|
|
154
|
+
interests = io.interests
|
|
155
|
+
|
|
156
|
+
is_closed = io.state == :closed
|
|
157
|
+
|
|
158
|
+
next(is_closed) if is_closed
|
|
159
|
+
|
|
160
|
+
io.log(level: 2) { "[#{io.state}] registering for select (#{interests})#{" for #{interval} seconds" unless interval.nil?}" }
|
|
161
|
+
|
|
162
|
+
if READABLE.include?(interests)
|
|
163
|
+
r = r.nil? ? io : (Array(r) << io)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
if WRITABLE.include?(interests)
|
|
167
|
+
w = w.nil? ? io : (Array(w) << io)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
is_closed
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
case r
|
|
174
|
+
when Array
|
|
175
|
+
w = Array(w) unless w.nil?
|
|
176
|
+
|
|
177
|
+
select_many(r, w, interval, &block)
|
|
178
|
+
when nil
|
|
179
|
+
case w
|
|
180
|
+
when Array
|
|
181
|
+
select_many(r, w, interval, &block)
|
|
182
|
+
when nil
|
|
183
|
+
return unless interval && has_no_selectables
|
|
184
|
+
|
|
185
|
+
# no selectables
|
|
186
|
+
# TODO: replace with sleep?
|
|
187
|
+
select_many(r, w, interval, &block)
|
|
188
|
+
else
|
|
189
|
+
select_one(w, :w, interval, &block)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
else
|
|
193
|
+
case w
|
|
194
|
+
when Array
|
|
195
|
+
select_many(Array(r), w, interval, &block)
|
|
196
|
+
when nil
|
|
197
|
+
select_one(r, :r, interval, &block)
|
|
198
|
+
else
|
|
199
|
+
if r == w
|
|
200
|
+
select_one(r, :rw, interval, &block)
|
|
201
|
+
else
|
|
202
|
+
select_many(Array(r), Array(w), interval, &block)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def select_many(r, w, interval, &block)
|
|
209
|
+
readers, writers = ::IO.select(r, w, nil, interval)
|
|
210
|
+
|
|
211
|
+
if readers.nil? && writers.nil? && interval
|
|
212
|
+
[*r, *w].each { |io| io.handle_socket_timeout(interval) }
|
|
213
|
+
return
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
if writers
|
|
217
|
+
readers.each do |io|
|
|
218
|
+
yield io
|
|
219
|
+
|
|
220
|
+
# so that we don't yield 2 times
|
|
221
|
+
writers.delete(io)
|
|
222
|
+
end if readers
|
|
223
|
+
|
|
224
|
+
writers.each(&block)
|
|
225
|
+
else
|
|
226
|
+
readers.each(&block) if readers
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def select_one(io, interests, interval)
|
|
231
|
+
result =
|
|
232
|
+
case interests
|
|
233
|
+
when :r then io.to_io.wait_readable(interval)
|
|
234
|
+
when :w then io.to_io.wait_writable(interval)
|
|
235
|
+
when :rw then rw_wait(io, interval)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
unless result || interval.nil?
|
|
239
|
+
io.handle_socket_timeout(interval) unless @is_timer_interval
|
|
240
|
+
return
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
yield io
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def next_timeout
|
|
247
|
+
@is_timer_interval = false
|
|
248
|
+
|
|
249
|
+
timer_interval = @timers.wait_interval
|
|
250
|
+
|
|
251
|
+
connection_interval = @selectables.filter_map(&:timeout).min
|
|
252
|
+
|
|
253
|
+
return connection_interval unless timer_interval
|
|
254
|
+
|
|
255
|
+
if connection_interval.nil? || timer_interval <= connection_interval
|
|
256
|
+
@is_timer_interval = true
|
|
257
|
+
|
|
258
|
+
return timer_interval
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
connection_interval
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
if RUBY_ENGINE == "jruby"
|
|
265
|
+
def rw_wait(io, interval)
|
|
266
|
+
io.to_io.wait(interval, :read_write)
|
|
267
|
+
end
|
|
268
|
+
elsif IO.const_defined?(:READABLE)
|
|
269
|
+
def rw_wait(io, interval)
|
|
270
|
+
io.to_io.wait(IO::READABLE | IO::WRITABLE, interval)
|
|
271
|
+
end
|
|
272
|
+
else
|
|
273
|
+
def rw_wait(io, interval)
|
|
274
|
+
if interval
|
|
275
|
+
io.to_io.wait(interval, :read_write)
|
|
276
|
+
else
|
|
277
|
+
io.to_io.wait(:read_write)
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
end
|