httpx 0.8.0 → 0.10.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 +4 -4
- data/LICENSE.txt +48 -0
- data/README.md +9 -5
- 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 +39 -0
- data/doc/release_notes/0_1_0.md +9 -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/lib/httpx.rb +2 -0
- data/lib/httpx/adapters/faraday.rb +1 -1
- data/lib/httpx/chainable.rb +11 -11
- data/lib/httpx/connection.rb +23 -31
- data/lib/httpx/connection/http1.rb +30 -4
- data/lib/httpx/connection/http2.rb +29 -10
- data/lib/httpx/domain_name.rb +440 -0
- data/lib/httpx/errors.rb +2 -1
- data/lib/httpx/extensions.rb +22 -2
- data/lib/httpx/headers.rb +2 -2
- 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 +5 -1
- data/lib/httpx/parser/http1.rb +14 -17
- data/lib/httpx/plugins/compression.rb +46 -65
- 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 +12 -1
- data/lib/httpx/plugins/follow_redirects.rb +20 -2
- data/lib/httpx/plugins/h2c.rb +1 -1
- data/lib/httpx/plugins/multipart.rb +12 -6
- data/lib/httpx/plugins/persistent.rb +6 -1
- data/lib/httpx/plugins/proxy.rb +16 -2
- data/lib/httpx/plugins/proxy/socks4.rb +14 -14
- 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 +14 -17
- data/lib/httpx/request.rb +8 -20
- data/lib/httpx/resolver.rb +7 -10
- data/lib/httpx/resolver/https.rb +22 -24
- data/lib/httpx/resolver/native.rb +19 -16
- data/lib/httpx/resolver/resolver_mixin.rb +4 -2
- data/lib/httpx/resolver/system.rb +2 -2
- data/lib/httpx/response.rb +16 -25
- data/lib/httpx/selector.rb +11 -18
- data/lib/httpx/session.rb +40 -26
- data/lib/httpx/transcoder.rb +18 -0
- data/lib/httpx/transcoder/chunker.rb +0 -2
- data/lib/httpx/transcoder/form.rb +9 -7
- 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 +85 -0
- data/sig/connection/http1.rbs +66 -0
- data/sig/connection/http2.rbs +78 -0
- data/sig/domain_name.rbs +17 -0
- data/sig/errors.rbs +3 -0
- data/sig/headers.rbs +42 -0
- data/sig/httpx.rbs +15 -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 +21 -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 +36 -0
- data/sig/registry.rbs +9 -0
- data/sig/request.rbs +61 -0
- data/sig/resolver.rbs +26 -0
- data/sig/resolver/https.rbs +49 -0
- data/sig/resolver/native.rbs +60 -0
- data/sig/resolver/resolver_mixin.rbs +27 -0
- data/sig/resolver/system.rbs +17 -0
- data/sig/response.rbs +87 -0
- data/sig/selector.rbs +20 -0
- data/sig/session.rbs +49 -0
- data/sig/timeout.rbs +29 -0
- data/sig/transcoder.rbs +18 -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 +128 -22
- data/lib/httpx/resolver/options.rb +0 -25
data/lib/httpx/errors.rb
CHANGED
|
@@ -28,6 +28,7 @@ module HTTPX
|
|
|
28
28
|
|
|
29
29
|
NativeResolveError = Class.new(ResolveError) do
|
|
30
30
|
attr_reader :connection, :host
|
|
31
|
+
|
|
31
32
|
def initialize(connection, host, message = "Can't resolve #{host}")
|
|
32
33
|
@connection = connection
|
|
33
34
|
@host = host
|
|
@@ -40,7 +41,7 @@ module HTTPX
|
|
|
40
41
|
|
|
41
42
|
def initialize(response)
|
|
42
43
|
@response = response
|
|
43
|
-
super("HTTP Error: #{@response.status}")
|
|
44
|
+
super("HTTP Error: #{@response.status} #{@response.headers}\n#{@response.body}")
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
def status
|
data/lib/httpx/extensions.rb
CHANGED
|
@@ -11,7 +11,7 @@ module HTTPX
|
|
|
11
11
|
#
|
|
12
12
|
# Why not using Refinements? Because they don't work for Method (tested with ruby 2.1.9).
|
|
13
13
|
#
|
|
14
|
-
module CurryMethods
|
|
14
|
+
module CurryMethods
|
|
15
15
|
# Backport for the Method#curry method, which is part of ruby core since 2.2 .
|
|
16
16
|
#
|
|
17
17
|
def curry(*args)
|
|
@@ -54,11 +54,31 @@ module HTTPX
|
|
|
54
54
|
Numeric.__send__(:include, NegMethods)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
module RegexpExtensions
|
|
58
|
+
# If you wonder why this is there: the oauth feature uses a refinement to enhance the
|
|
59
|
+
# Regexp class locally with #match? , but this is never tested, because ActiveSupport
|
|
60
|
+
# monkey-patches the same method... Please ActiveSupport, stop being so intrusive!
|
|
61
|
+
# :nocov:
|
|
62
|
+
refine(Regexp) do
|
|
63
|
+
def match?(*args)
|
|
64
|
+
!match(*args).nil?
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
57
69
|
module URIExtensions
|
|
58
70
|
refine URI::Generic do
|
|
71
|
+
def non_ascii_hostname
|
|
72
|
+
@non_ascii_hostname
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def non_ascii_hostname=(hostname)
|
|
76
|
+
@non_ascii_hostname = hostname
|
|
77
|
+
end
|
|
78
|
+
|
|
59
79
|
def authority
|
|
60
80
|
port_string = port == default_port ? nil : ":#{port}"
|
|
61
|
-
"#{host}#{port_string}"
|
|
81
|
+
"#{@non_ascii_hostname || host}#{port_string}"
|
|
62
82
|
end
|
|
63
83
|
|
|
64
84
|
def origin
|
data/lib/httpx/headers.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module HTTPX
|
|
4
4
|
class Headers
|
|
5
|
-
EMPTY = [].freeze
|
|
5
|
+
EMPTY = [].freeze
|
|
6
6
|
|
|
7
7
|
class << self
|
|
8
8
|
def new(headers = nil)
|
|
@@ -67,7 +67,7 @@ module HTTPX
|
|
|
67
67
|
#
|
|
68
68
|
def [](field)
|
|
69
69
|
a = @headers[downcased(field)] || return
|
|
70
|
-
a.join(",")
|
|
70
|
+
a.join(", ")
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
# sets +value+ (if not nil) as single value for the +field+ header.
|
data/lib/httpx/io/ssl.rb
CHANGED
data/lib/httpx/io/tcp.rb
CHANGED
|
@@ -7,11 +7,7 @@ module HTTPX
|
|
|
7
7
|
class TCP
|
|
8
8
|
include Loggable
|
|
9
9
|
|
|
10
|
-
attr_reader :ip, :port
|
|
11
|
-
|
|
12
|
-
attr_reader :addresses
|
|
13
|
-
|
|
14
|
-
attr_reader :state
|
|
10
|
+
attr_reader :ip, :port, :addresses, :state
|
|
15
11
|
|
|
16
12
|
alias_method :host, :ip
|
|
17
13
|
|
|
@@ -86,6 +82,7 @@ module HTTPX
|
|
|
86
82
|
# :nocov:
|
|
87
83
|
def read(size, buffer)
|
|
88
84
|
@io.read_nonblock(size, buffer)
|
|
85
|
+
log { "READ: #{buffer.bytesize} bytes..." }
|
|
89
86
|
buffer.bytesize
|
|
90
87
|
rescue ::IO::WaitReadable
|
|
91
88
|
buffer.clear
|
|
@@ -96,6 +93,7 @@ module HTTPX
|
|
|
96
93
|
|
|
97
94
|
def write(buffer)
|
|
98
95
|
siz = @io.write_nonblock(buffer)
|
|
96
|
+
log { "WRITE: #{siz} bytes..." }
|
|
99
97
|
buffer.shift!(siz)
|
|
100
98
|
siz
|
|
101
99
|
rescue ::IO::WaitWritable
|
|
@@ -113,6 +111,7 @@ module HTTPX
|
|
|
113
111
|
end
|
|
114
112
|
return if ret.nil?
|
|
115
113
|
|
|
114
|
+
log { "READ: #{buffer.bytesize} bytes..." }
|
|
116
115
|
buffer.bytesize
|
|
117
116
|
end
|
|
118
117
|
|
|
@@ -121,6 +120,8 @@ module HTTPX
|
|
|
121
120
|
return 0 if siz == :wait_writable
|
|
122
121
|
return if siz.nil?
|
|
123
122
|
|
|
123
|
+
log { "WRITE: #{siz} bytes..." }
|
|
124
|
+
|
|
124
125
|
buffer.shift!(siz)
|
|
125
126
|
siz
|
|
126
127
|
end
|
data/lib/httpx/io/udp.rb
CHANGED
|
@@ -7,11 +7,12 @@ module HTTPX
|
|
|
7
7
|
class UDP
|
|
8
8
|
include Loggable
|
|
9
9
|
|
|
10
|
-
def initialize(uri, _,
|
|
10
|
+
def initialize(uri, _, options)
|
|
11
11
|
ip = IPAddr.new(uri.host)
|
|
12
12
|
@host = ip.to_s
|
|
13
13
|
@port = uri.port
|
|
14
14
|
@io = UDPSocket.new(ip.family)
|
|
15
|
+
@options = options
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def to_io
|
|
@@ -40,6 +41,7 @@ module HTTPX
|
|
|
40
41
|
|
|
41
42
|
def write(buffer)
|
|
42
43
|
siz = @io.send(buffer, 0, @host, @port)
|
|
44
|
+
log { "WRITE: #{siz} bytes..." }
|
|
43
45
|
buffer.shift!(siz)
|
|
44
46
|
siz
|
|
45
47
|
end
|
|
@@ -49,6 +51,7 @@ module HTTPX
|
|
|
49
51
|
def read(size, buffer)
|
|
50
52
|
data, _ = @io.recvfrom_nonblock(size)
|
|
51
53
|
buffer.replace(data)
|
|
54
|
+
log { "READ: #{buffer.bytesize} bytes..." }
|
|
52
55
|
buffer.bytesize
|
|
53
56
|
rescue ::IO::WaitReadable
|
|
54
57
|
0
|
data/lib/httpx/options.rb
CHANGED
|
@@ -76,6 +76,8 @@ module HTTPX
|
|
|
76
76
|
|
|
77
77
|
defaults.merge!(options)
|
|
78
78
|
defaults.each do |(k, v)|
|
|
79
|
+
next if v.nil?
|
|
80
|
+
|
|
79
81
|
__send__(:"#{k}=", v)
|
|
80
82
|
end
|
|
81
83
|
end
|
|
@@ -146,8 +148,10 @@ module HTTPX
|
|
|
146
148
|
end
|
|
147
149
|
|
|
148
150
|
def merge(other)
|
|
149
|
-
h1 = to_hash
|
|
150
151
|
h2 = other.to_hash
|
|
152
|
+
return self if h2.empty?
|
|
153
|
+
|
|
154
|
+
h1 = to_hash
|
|
151
155
|
|
|
152
156
|
merged = h1.merge(h2) do |k, v1, v2|
|
|
153
157
|
case k
|
data/lib/httpx/parser/http1.rb
CHANGED
|
@@ -9,10 +9,9 @@ module HTTPX
|
|
|
9
9
|
|
|
10
10
|
attr_reader :status_code, :http_version, :headers
|
|
11
11
|
|
|
12
|
-
def initialize(observer
|
|
12
|
+
def initialize(observer)
|
|
13
13
|
@observer = observer
|
|
14
14
|
@state = :idle
|
|
15
|
-
@header_separator = header_separator
|
|
16
15
|
@buffer = "".b
|
|
17
16
|
@headers = {}
|
|
18
17
|
end
|
|
@@ -40,25 +39,25 @@ module HTTPX
|
|
|
40
39
|
private
|
|
41
40
|
|
|
42
41
|
def parse
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
loop do
|
|
43
|
+
state = @state
|
|
44
|
+
case @state
|
|
45
|
+
when :idle
|
|
46
|
+
parse_headline
|
|
47
|
+
when :headers, :trailers
|
|
48
|
+
parse_headers
|
|
49
|
+
when :data
|
|
50
|
+
parse_data
|
|
51
|
+
end
|
|
52
|
+
return if @buffer.empty? || state == @state
|
|
53
53
|
end
|
|
54
|
-
parse if !@buffer.empty? && state != @state
|
|
55
54
|
end
|
|
56
55
|
|
|
57
56
|
def parse_headline
|
|
58
57
|
idx = @buffer.index("\n")
|
|
59
58
|
return unless idx
|
|
60
59
|
|
|
61
|
-
(m = %r{\AHTTP(
|
|
60
|
+
(m = %r{\AHTTP(?:/(\d+\.\d+))?\s+(\d\d\d)(?:\s+(.*))?}in.match(@buffer)) ||
|
|
62
61
|
raise(Error, "wrong head line format")
|
|
63
62
|
version, code, _ = m.captures
|
|
64
63
|
raise(Error, "unsupported HTTP version (HTTP/#{version})") unless VERSIONS.include?(version)
|
|
@@ -91,12 +90,10 @@ module HTTPX
|
|
|
91
90
|
@observer.on_trailers(headers)
|
|
92
91
|
headers.clear
|
|
93
92
|
nextstate(:complete)
|
|
94
|
-
else
|
|
95
|
-
raise Error, "wrong header format"
|
|
96
93
|
end
|
|
97
94
|
return
|
|
98
95
|
end
|
|
99
|
-
separator_index = line.index(
|
|
96
|
+
separator_index = line.index(":")
|
|
100
97
|
raise Error, "wrong header format" unless separator_index
|
|
101
98
|
|
|
102
99
|
key = line[0..separator_index - 1]
|
|
@@ -14,13 +14,23 @@ module HTTPX
|
|
|
14
14
|
#
|
|
15
15
|
module Compression
|
|
16
16
|
extend Registry
|
|
17
|
-
def self.load_dependencies(klass)
|
|
18
|
-
klass.plugin(:"compression/gzip")
|
|
19
|
-
klass.plugin(:"compression/deflate")
|
|
20
|
-
end
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
class << self
|
|
19
|
+
def load_dependencies(klass)
|
|
20
|
+
klass.plugin(:"compression/gzip")
|
|
21
|
+
klass.plugin(:"compression/deflate")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def extra_options(options)
|
|
25
|
+
Class.new(options.class) do
|
|
26
|
+
def_option(:compression_threshold_size) do |bytes|
|
|
27
|
+
bytes = Integer(bytes)
|
|
28
|
+
raise Error, ":expect_threshold_size must be positive" unless bytes.positive?
|
|
29
|
+
|
|
30
|
+
bytes
|
|
31
|
+
end
|
|
32
|
+
end.new(options).merge(headers: { "accept-encoding" => Compression.registry.keys })
|
|
33
|
+
end
|
|
24
34
|
end
|
|
25
35
|
|
|
26
36
|
module RequestMethods
|
|
@@ -32,14 +42,17 @@ module HTTPX
|
|
|
32
42
|
end
|
|
33
43
|
|
|
34
44
|
module RequestBodyMethods
|
|
35
|
-
def initialize(
|
|
45
|
+
def initialize(*, options)
|
|
36
46
|
super
|
|
37
47
|
return if @body.nil?
|
|
38
48
|
|
|
49
|
+
threshold = options.compression_threshold_size
|
|
50
|
+
return if threshold && !unbounded_body? && @body.bytesize < threshold
|
|
51
|
+
|
|
39
52
|
@headers.get("content-encoding").each do |encoding|
|
|
40
53
|
next if encoding == "identity"
|
|
41
54
|
|
|
42
|
-
@body = Encoder.new(@body, Compression.registry(encoding).
|
|
55
|
+
@body = Encoder.new(@body, Compression.registry(encoding).deflater)
|
|
43
56
|
end
|
|
44
57
|
@headers["content-length"] = @body.bytesize unless chunked?
|
|
45
58
|
end
|
|
@@ -55,57 +68,53 @@ module HTTPX
|
|
|
55
68
|
|
|
56
69
|
return unless @headers.key?("content-encoding")
|
|
57
70
|
|
|
58
|
-
|
|
71
|
+
# remove encodings that we are able to decode
|
|
72
|
+
@headers["content-encoding"] = @headers.get("content-encoding") - @encodings
|
|
73
|
+
|
|
74
|
+
compressed_length = if @headers.key?("content-length")
|
|
75
|
+
@headers["content-length"].to_i
|
|
76
|
+
else
|
|
77
|
+
Float::INFINITY
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
@_inflaters = @headers.get("content-encoding").map do |encoding|
|
|
59
81
|
next if encoding == "identity"
|
|
60
82
|
|
|
61
|
-
|
|
83
|
+
inflater = Compression.registry(encoding).inflater(compressed_length)
|
|
62
84
|
# do not uncompress if there is no decoder available. In fact, we can't reliably
|
|
63
85
|
# continue decompressing beyond that, so ignore.
|
|
64
|
-
break unless
|
|
86
|
+
break unless inflater
|
|
65
87
|
|
|
66
88
|
@encodings << encoding
|
|
67
|
-
|
|
89
|
+
inflater
|
|
68
90
|
end.compact
|
|
69
91
|
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@_compressed_length = if @headers.key?("content-length")
|
|
74
|
-
@headers["content-length"].to_i
|
|
75
|
-
else
|
|
76
|
-
Float::INFINITY
|
|
77
|
-
end
|
|
92
|
+
# this can happen if the only declared encoding is "identity"
|
|
93
|
+
remove_instance_variable(:@_inflaters) if @_inflaters.empty?
|
|
78
94
|
end
|
|
79
95
|
|
|
80
96
|
def write(chunk)
|
|
81
|
-
return super unless defined?(@
|
|
97
|
+
return super unless defined?(@_inflaters)
|
|
82
98
|
|
|
83
|
-
@_compressed_length -= chunk.bytesize
|
|
84
99
|
chunk = decompress(chunk)
|
|
85
100
|
super(chunk)
|
|
86
101
|
end
|
|
87
102
|
|
|
88
|
-
def close
|
|
89
|
-
super
|
|
90
|
-
|
|
91
|
-
return unless defined?(@_decoders)
|
|
92
|
-
|
|
93
|
-
@_decoders.each(&:close)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
103
|
private
|
|
97
104
|
|
|
98
105
|
def decompress(buffer)
|
|
99
|
-
@
|
|
100
|
-
buffer =
|
|
101
|
-
buffer << decoder.finish if @_compressed_length <= 0
|
|
106
|
+
@_inflaters.reverse_each do |inflater|
|
|
107
|
+
buffer = inflater.inflate(buffer)
|
|
102
108
|
end
|
|
103
109
|
buffer
|
|
104
110
|
end
|
|
105
111
|
end
|
|
106
112
|
|
|
107
113
|
class Encoder
|
|
114
|
+
attr_reader :content_type
|
|
115
|
+
|
|
108
116
|
def initialize(body, deflater)
|
|
117
|
+
@content_type = body.content_type
|
|
109
118
|
@body = body.respond_to?(:read) ? body : StringIO.new(body.to_s)
|
|
110
119
|
@buffer = StringIO.new("".b, File::RDWR)
|
|
111
120
|
@deflater = deflater
|
|
@@ -114,11 +123,10 @@ module HTTPX
|
|
|
114
123
|
def each(&blk)
|
|
115
124
|
return enum_for(__method__) unless block_given?
|
|
116
125
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
deflate(&blk)
|
|
126
|
+
return deflate(&blk) if @buffer.size.zero?
|
|
127
|
+
|
|
128
|
+
@buffer.rewind
|
|
129
|
+
@buffer.each(&blk)
|
|
122
130
|
end
|
|
123
131
|
|
|
124
132
|
def bytesize
|
|
@@ -126,17 +134,6 @@ module HTTPX
|
|
|
126
134
|
@buffer.size
|
|
127
135
|
end
|
|
128
136
|
|
|
129
|
-
def to_s
|
|
130
|
-
deflate
|
|
131
|
-
@buffer.rewind
|
|
132
|
-
@buffer.read
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def close
|
|
136
|
-
@buffer.close
|
|
137
|
-
@body.close
|
|
138
|
-
end
|
|
139
|
-
|
|
140
137
|
private
|
|
141
138
|
|
|
142
139
|
def deflate(&blk)
|
|
@@ -146,22 +143,6 @@ module HTTPX
|
|
|
146
143
|
@deflater.deflate(@body, @buffer, chunk_size: 16_384, &blk)
|
|
147
144
|
end
|
|
148
145
|
end
|
|
149
|
-
|
|
150
|
-
class Decoder
|
|
151
|
-
extend Forwardable
|
|
152
|
-
|
|
153
|
-
def_delegator :@inflater, :finish
|
|
154
|
-
|
|
155
|
-
def_delegator :@inflater, :close
|
|
156
|
-
|
|
157
|
-
def initialize(inflater)
|
|
158
|
-
@inflater = inflater
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def decode(chunk)
|
|
162
|
-
@inflater.inflate(chunk)
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
146
|
end
|
|
166
147
|
register_plugin :compression, Compression
|
|
167
148
|
end
|
|
@@ -13,7 +13,7 @@ module HTTPX
|
|
|
13
13
|
Compression.register "br", self
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
module
|
|
16
|
+
module Deflater
|
|
17
17
|
module_function
|
|
18
18
|
|
|
19
19
|
def deflate(raw, buffer, chunk_size:)
|
|
@@ -25,28 +25,24 @@ module HTTPX
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def inflate(text)
|
|
32
|
-
::Brotli.inflate(text)
|
|
28
|
+
class Inflater
|
|
29
|
+
def initialize(bytesize)
|
|
30
|
+
@bytesize = bytesize
|
|
33
31
|
end
|
|
34
32
|
|
|
35
|
-
def
|
|
36
|
-
|
|
37
|
-
def finish
|
|
38
|
-
""
|
|
33
|
+
def inflate(chunk)
|
|
34
|
+
::Brotli.inflate(chunk)
|
|
39
35
|
end
|
|
40
36
|
end
|
|
41
37
|
|
|
42
38
|
module_function
|
|
43
39
|
|
|
44
|
-
def
|
|
45
|
-
|
|
40
|
+
def deflater
|
|
41
|
+
Deflater
|
|
46
42
|
end
|
|
47
43
|
|
|
48
|
-
def
|
|
49
|
-
|
|
44
|
+
def inflater(bytesize)
|
|
45
|
+
Inflater.new(bytesize)
|
|
50
46
|
end
|
|
51
47
|
end
|
|
52
48
|
end
|