httpx 0.24.6 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +0 -48
- data/README.md +4 -13
- data/doc/release_notes/0_24_4.md +3 -3
- data/doc/release_notes/1_0_0.md +60 -0
- data/lib/httpx/adapters/datadog.rb +28 -97
- data/lib/httpx/adapters/faraday.rb +9 -52
- data/lib/httpx/adapters/webmock.rb +2 -7
- data/lib/httpx/altsvc.rb +4 -22
- data/lib/httpx/base64.rb +27 -0
- data/lib/httpx/chainable.rb +0 -23
- data/lib/httpx/connection.rb +11 -32
- data/lib/httpx/domain_name.rb +5 -12
- data/lib/httpx/errors.rb +0 -2
- data/lib/httpx/extensions.rb +0 -124
- data/lib/httpx/io/ssl.rb +26 -59
- data/lib/httpx/io/tcp.rb +27 -68
- data/lib/httpx/io/udp.rb +13 -48
- data/lib/httpx/io/unix.rb +1 -8
- data/lib/httpx/loggable.rb +4 -19
- data/lib/httpx/options.rb +24 -84
- data/lib/httpx/plugins/{authentication → auth}/basic.rb +1 -5
- data/lib/httpx/plugins/{authentication → auth}/digest.rb +2 -5
- data/lib/httpx/plugins/{authentication → auth}/ntlm.rb +1 -3
- data/lib/httpx/plugins/{authentication → auth}/socks5.rb +0 -2
- data/lib/httpx/plugins/auth.rb +25 -0
- data/lib/httpx/plugins/aws_sigv4.rb +0 -1
- data/lib/httpx/plugins/{basic_authentication.rb → basic_auth.rb} +5 -6
- data/lib/httpx/plugins/brotli.rb +50 -0
- data/lib/httpx/plugins/circuit_breaker/circuit.rb +40 -16
- data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +16 -5
- data/lib/httpx/plugins/circuit_breaker.rb +11 -4
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +0 -2
- data/lib/httpx/plugins/cookies.rb +1 -1
- data/lib/httpx/plugins/{digest_authentication.rb → digest_auth.rb} +5 -5
- data/lib/httpx/plugins/follow_redirects.rb +21 -24
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +82 -0
- data/lib/httpx/plugins/grpc/message.rb +7 -39
- data/lib/httpx/plugins/grpc.rb +15 -21
- data/lib/httpx/plugins/h2c.rb +0 -1
- data/lib/httpx/plugins/{ntlm_authentication.rb → ntlm_auth.rb} +5 -5
- data/lib/httpx/plugins/oauth.rb +2 -2
- data/lib/httpx/plugins/proxy/http.rb +0 -2
- data/lib/httpx/plugins/proxy/socks4.rb +0 -4
- data/lib/httpx/plugins/proxy/socks5.rb +1 -5
- data/lib/httpx/plugins/proxy.rb +3 -32
- data/lib/httpx/plugins/retries.rb +3 -4
- data/lib/httpx/plugins/stream.rb +4 -6
- data/lib/httpx/punycode.rb +9 -291
- data/lib/httpx/request/body.rb +145 -0
- data/lib/httpx/request.rb +2 -119
- data/lib/httpx/resolver/https.rb +1 -1
- data/lib/httpx/resolver/native.rb +6 -14
- data/lib/httpx/resolver/resolver.rb +1 -1
- data/lib/httpx/resolver/system.rb +11 -9
- data/lib/httpx/response/body.rb +206 -0
- data/lib/httpx/response/buffer.rb +90 -0
- data/lib/httpx/response.rb +5 -208
- data/lib/httpx/selector.rb +0 -2
- data/lib/httpx/session.rb +0 -10
- data/lib/httpx/transcoder/body.rb +0 -1
- data/lib/httpx/transcoder/deflate.rb +37 -0
- data/lib/httpx/transcoder/form.rb +52 -32
- data/lib/httpx/transcoder/gzip.rb +74 -0
- data/lib/httpx/transcoder/json.rb +2 -4
- data/lib/httpx/transcoder/multipart/decoder.rb +139 -0
- data/lib/httpx/{plugins → transcoder}/multipart/encoder.rb +3 -3
- data/lib/httpx/{plugins → transcoder}/multipart/mime_type_detector.rb +1 -1
- data/lib/httpx/{plugins → transcoder}/multipart/part.rb +3 -2
- data/lib/httpx/transcoder/multipart.rb +17 -0
- data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
- data/lib/httpx/transcoder/utils/deflater.rb +72 -0
- data/lib/httpx/transcoder/xml.rb +0 -2
- data/lib/httpx/transcoder.rb +2 -2
- data/lib/httpx/utils.rb +10 -20
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +0 -8
- data/sig/chainable.rbs +5 -6
- data/sig/connection.rbs +0 -1
- data/sig/errors.rbs +0 -3
- data/sig/httpx.rbs +2 -1
- data/sig/io/unix.rbs +1 -1
- data/sig/options.rbs +12 -8
- data/sig/plugins/{authentication → auth}/basic.rbs +0 -2
- data/sig/plugins/auth.rbs +13 -0
- data/sig/plugins/{basic_authentication.rbs → basic_auth.rbs} +2 -2
- data/sig/plugins/brotli.rbs +22 -0
- data/sig/plugins/circuit_breaker.rbs +7 -3
- data/sig/plugins/compression.rbs +0 -2
- data/sig/plugins/{digest_authentication.rbs → digest_auth.rbs} +2 -2
- data/sig/plugins/follow_redirects.rbs +0 -1
- data/sig/plugins/grpc/call.rbs +19 -0
- data/sig/plugins/grpc/grpc_encoding.rbs +33 -0
- data/sig/plugins/grpc/message.rbs +17 -0
- data/sig/plugins/grpc.rbs +2 -32
- data/sig/plugins/{ntlm_authentication.rbs → ntlm_auth.rbs} +2 -2
- data/sig/plugins/oauth.rbs +1 -1
- data/sig/plugins/proxy/socks4.rbs +2 -3
- data/sig/plugins/proxy/socks5.rbs +0 -1
- data/sig/plugins/proxy/ssh.rbs +1 -1
- data/sig/plugins/response_cache.rbs +5 -2
- data/sig/request/body.rbs +42 -0
- data/sig/request.rbs +1 -27
- data/sig/resolver/resolver.rbs +1 -1
- data/sig/response/body.rbs +52 -0
- data/sig/response/buffer.rbs +24 -0
- data/sig/response.rbs +0 -39
- data/sig/transcoder/body.rbs +4 -3
- data/sig/transcoder/deflate.rbs +11 -0
- data/sig/transcoder/form.rbs +5 -3
- data/sig/transcoder/gzip.rbs +24 -0
- data/sig/transcoder/json.rbs +4 -2
- data/sig/{plugins → transcoder}/multipart.rbs +3 -10
- data/sig/transcoder/utils/body_reader.rbs +15 -0
- data/sig/transcoder/utils/deflater.rbs +29 -0
- data/sig/transcoder.rbs +18 -2
- metadata +50 -34
- data/lib/httpx/plugins/authentication.rb +0 -24
- data/lib/httpx/plugins/compression/brotli.rb +0 -54
- data/lib/httpx/plugins/compression/deflate.rb +0 -54
- data/lib/httpx/plugins/compression/gzip.rb +0 -90
- data/lib/httpx/plugins/compression.rb +0 -165
- data/lib/httpx/plugins/multipart/decoder.rb +0 -137
- data/lib/httpx/plugins/multipart.rb +0 -96
- data/sig/plugins/authentication.rbs +0 -13
- data/sig/plugins/compression/brotli.rbs +0 -21
- data/sig/plugins/compression/deflate.rbs +0 -17
- data/sig/plugins/compression/gzip.rbs +0 -29
- /data/sig/plugins/{authentication → auth}/digest.rbs +0 -0
- /data/sig/plugins/{authentication → auth}/ntlm.rbs +0 -0
- /data/sig/plugins/{authentication → auth}/socks5.rbs +0 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "stringio"
|
|
6
|
+
require "zlib"
|
|
7
|
+
|
|
8
|
+
module HTTPX
|
|
9
|
+
module Transcoder
|
|
10
|
+
module GZIP
|
|
11
|
+
class Deflater < Transcoder::Deflater
|
|
12
|
+
def initialize(body)
|
|
13
|
+
@compressed_chunk = "".b
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def deflate(chunk)
|
|
18
|
+
@deflater ||= Zlib::GzipWriter.new(self)
|
|
19
|
+
|
|
20
|
+
if chunk.nil?
|
|
21
|
+
unless @deflater.closed?
|
|
22
|
+
@deflater.flush
|
|
23
|
+
@deflater.close
|
|
24
|
+
compressed_chunk
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
@deflater.write(chunk)
|
|
28
|
+
compressed_chunk
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def write(chunk)
|
|
35
|
+
@compressed_chunk << chunk
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def compressed_chunk
|
|
39
|
+
@compressed_chunk.dup
|
|
40
|
+
ensure
|
|
41
|
+
@compressed_chunk.clear
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Inflater
|
|
46
|
+
def initialize(bytesize)
|
|
47
|
+
@inflater = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)
|
|
48
|
+
@bytesize = bytesize
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def call(chunk)
|
|
52
|
+
buffer = @inflater.inflate(chunk)
|
|
53
|
+
@bytesize -= chunk.bytesize
|
|
54
|
+
if @bytesize <= 0
|
|
55
|
+
buffer << @inflater.finish
|
|
56
|
+
@inflater.close
|
|
57
|
+
end
|
|
58
|
+
buffer
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
module_function
|
|
63
|
+
|
|
64
|
+
def encode(body)
|
|
65
|
+
Deflater.new(body)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def decode(response, bytesize: nil)
|
|
69
|
+
bytesize ||= response.headers.key?("content-length") ? response.headers["content-length"].to_i : Float::INFINITY
|
|
70
|
+
Inflater.new(bytesize)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -4,12 +4,10 @@ require "forwardable"
|
|
|
4
4
|
|
|
5
5
|
module HTTPX::Transcoder
|
|
6
6
|
module JSON
|
|
7
|
-
JSON_REGEX = %r{\bapplication/(?:vnd\.api\+)?json\b}i.freeze
|
|
8
|
-
|
|
9
|
-
using HTTPX::RegexpExtensions unless Regexp.method_defined?(:match?)
|
|
10
|
-
|
|
11
7
|
module_function
|
|
12
8
|
|
|
9
|
+
JSON_REGEX = %r{\bapplication/(?:vnd\.api\+)?json\b}i.freeze
|
|
10
|
+
|
|
13
11
|
class Encoder
|
|
14
12
|
extend Forwardable
|
|
15
13
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tempfile"
|
|
4
|
+
require "delegate"
|
|
5
|
+
|
|
6
|
+
module HTTPX
|
|
7
|
+
module Transcoder
|
|
8
|
+
module Multipart
|
|
9
|
+
class FilePart < SimpleDelegator
|
|
10
|
+
attr_reader :original_filename, :content_type
|
|
11
|
+
|
|
12
|
+
def initialize(filename, content_type)
|
|
13
|
+
@original_filename = filename
|
|
14
|
+
@content_type = content_type
|
|
15
|
+
@file = Tempfile.new("httpx", encoding: Encoding::BINARY, mode: File::RDWR)
|
|
16
|
+
super(@file)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Decoder
|
|
21
|
+
include HTTPX::Utils
|
|
22
|
+
|
|
23
|
+
CRLF = "\r\n"
|
|
24
|
+
BOUNDARY_RE = /;\s*boundary=([^;]+)/i.freeze
|
|
25
|
+
MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{CRLF}/ni.freeze
|
|
26
|
+
MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni.freeze
|
|
27
|
+
MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{CRLF}]*)/ni.freeze
|
|
28
|
+
WINDOW_SIZE = 2 << 14
|
|
29
|
+
|
|
30
|
+
def initialize(response)
|
|
31
|
+
@boundary = begin
|
|
32
|
+
m = response.headers["content-type"].to_s[BOUNDARY_RE, 1]
|
|
33
|
+
raise Error, "no boundary declared in content-type header" unless m
|
|
34
|
+
|
|
35
|
+
m.strip
|
|
36
|
+
end
|
|
37
|
+
@buffer = "".b
|
|
38
|
+
@parts = {}
|
|
39
|
+
@intermediate_boundary = "--#{@boundary}"
|
|
40
|
+
@state = :idle
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def call(response, *)
|
|
44
|
+
response.body.each do |chunk|
|
|
45
|
+
@buffer << chunk
|
|
46
|
+
|
|
47
|
+
parse
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
raise Error, "invalid or unsupported multipart format" unless @buffer.empty?
|
|
51
|
+
|
|
52
|
+
@parts
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def parse
|
|
58
|
+
case @state
|
|
59
|
+
when :idle
|
|
60
|
+
raise Error, "payload does not start with boundary" unless @buffer.start_with?("#{@intermediate_boundary}#{CRLF}")
|
|
61
|
+
|
|
62
|
+
@buffer = @buffer.byteslice(@intermediate_boundary.bytesize + 2..-1)
|
|
63
|
+
|
|
64
|
+
@state = :part_header
|
|
65
|
+
when :part_header
|
|
66
|
+
idx = @buffer.index("#{CRLF}#{CRLF}")
|
|
67
|
+
|
|
68
|
+
# raise Error, "couldn't parse part headers" unless idx
|
|
69
|
+
return unless idx
|
|
70
|
+
|
|
71
|
+
head = @buffer.byteslice(0..idx + 4 - 1)
|
|
72
|
+
|
|
73
|
+
@buffer = @buffer.byteslice(head.bytesize..-1)
|
|
74
|
+
|
|
75
|
+
content_type = head[MULTIPART_CONTENT_TYPE, 1]
|
|
76
|
+
if (name = head[MULTIPART_CONTENT_DISPOSITION, 1])
|
|
77
|
+
name = /\A"(.*)"\Z/ =~ name ? Regexp.last_match(1) : name.dup
|
|
78
|
+
name.gsub!(/\\(.)/, "\\1")
|
|
79
|
+
name
|
|
80
|
+
else
|
|
81
|
+
name = head[MULTIPART_CONTENT_ID, 1]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
filename = HTTPX::Utils.get_filename(head)
|
|
85
|
+
|
|
86
|
+
name = filename || +"#{content_type || "text/plain"}[]" if name.nil? || name.empty?
|
|
87
|
+
|
|
88
|
+
@current = name
|
|
89
|
+
|
|
90
|
+
@parts[name] = if filename
|
|
91
|
+
FilePart.new(filename, content_type)
|
|
92
|
+
else
|
|
93
|
+
"".b
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
@state = :part_body
|
|
97
|
+
when :part_body
|
|
98
|
+
part = @parts[@current]
|
|
99
|
+
|
|
100
|
+
body_separator = if part.is_a?(FilePart)
|
|
101
|
+
"#{CRLF}#{CRLF}"
|
|
102
|
+
else
|
|
103
|
+
CRLF
|
|
104
|
+
end
|
|
105
|
+
idx = @buffer.index(body_separator)
|
|
106
|
+
|
|
107
|
+
if idx
|
|
108
|
+
payload = @buffer.byteslice(0..idx - 1)
|
|
109
|
+
@buffer = @buffer.byteslice(idx + body_separator.bytesize..-1)
|
|
110
|
+
part << payload
|
|
111
|
+
part.rewind if part.respond_to?(:rewind)
|
|
112
|
+
@state = :parse_boundary
|
|
113
|
+
else
|
|
114
|
+
part << @buffer
|
|
115
|
+
@buffer.clear
|
|
116
|
+
end
|
|
117
|
+
when :parse_boundary
|
|
118
|
+
raise Error, "payload does not start with boundary" unless @buffer.start_with?(@intermediate_boundary)
|
|
119
|
+
|
|
120
|
+
@buffer = @buffer.byteslice(@intermediate_boundary.bytesize..-1)
|
|
121
|
+
|
|
122
|
+
if @buffer == "--"
|
|
123
|
+
@buffer.clear
|
|
124
|
+
@state = :done
|
|
125
|
+
return
|
|
126
|
+
elsif @buffer.start_with?(CRLF)
|
|
127
|
+
@buffer = @buffer.byteslice(2..-1)
|
|
128
|
+
@state = :part_header
|
|
129
|
+
else
|
|
130
|
+
return
|
|
131
|
+
end
|
|
132
|
+
when :done
|
|
133
|
+
raise Error, "parsing should have been over by now"
|
|
134
|
+
end until @buffer.empty?
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module HTTPX
|
|
4
|
-
module Multipart
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Transcoder::Multipart
|
|
5
5
|
class Encoder
|
|
6
6
|
attr_reader :bytesize
|
|
7
7
|
|
|
@@ -43,7 +43,7 @@ module HTTPX::Plugins
|
|
|
43
43
|
def to_parts(form)
|
|
44
44
|
@bytesize = 0
|
|
45
45
|
params = form.each_with_object([]) do |(key, val), aux|
|
|
46
|
-
|
|
46
|
+
Transcoder.normalize_keys(key, val, MULTIPART_VALUE_COND) do |k, v|
|
|
47
47
|
next if v.nil?
|
|
48
48
|
|
|
49
49
|
value, content_type, filename = Part.call(v)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module HTTPX
|
|
4
|
-
module
|
|
4
|
+
module Transcoder::Multipart
|
|
5
5
|
module Part
|
|
6
6
|
module_function
|
|
7
7
|
|
|
@@ -21,7 +21,8 @@ module HTTPX
|
|
|
21
21
|
|
|
22
22
|
value = value.open(File::RDONLY) if Object.const_defined?(:Pathname) && value.is_a?(Pathname)
|
|
23
23
|
|
|
24
|
-
if value.
|
|
24
|
+
if value.respond_to?(:path) && value.respond_to?(:read)
|
|
25
|
+
# either a File, a Tempfile, or something else which has to quack like a file
|
|
25
26
|
filename ||= File.basename(value.path)
|
|
26
27
|
content_type ||= MimeTypeDetector.call(value, filename) || "application/octet-stream"
|
|
27
28
|
[value, content_type, filename]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "multipart/encoder"
|
|
4
|
+
require_relative "multipart/decoder"
|
|
5
|
+
require_relative "multipart/part"
|
|
6
|
+
require_relative "multipart/mime_type_detector"
|
|
7
|
+
|
|
8
|
+
module HTTPX::Transcoder
|
|
9
|
+
module Multipart
|
|
10
|
+
MULTIPART_VALUE_COND = lambda do |value|
|
|
11
|
+
value.respond_to?(:read) ||
|
|
12
|
+
(value.respond_to?(:to_hash) &&
|
|
13
|
+
value.key?(:body) &&
|
|
14
|
+
(value.key?(:filename) || value.key?(:content_type)))
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "stringio"
|
|
4
|
+
|
|
5
|
+
module HTTPX
|
|
6
|
+
module Transcoder
|
|
7
|
+
class BodyReader
|
|
8
|
+
def initialize(body)
|
|
9
|
+
@body = if body.respond_to?(:read)
|
|
10
|
+
body.rewind if body.respond_to?(:rewind)
|
|
11
|
+
body
|
|
12
|
+
elsif body.respond_to?(:each)
|
|
13
|
+
body.enum_for(:each)
|
|
14
|
+
else
|
|
15
|
+
StringIO.new(body.to_s)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def bytesize
|
|
20
|
+
return @body.bytesize if @body.respond_to?(:bytesize)
|
|
21
|
+
|
|
22
|
+
Float::INFINITY
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def read(length = nil, outbuf = nil)
|
|
26
|
+
return @body.read(length, outbuf) if @body.respond_to?(:read)
|
|
27
|
+
|
|
28
|
+
begin
|
|
29
|
+
chunk = @body.next
|
|
30
|
+
if outbuf
|
|
31
|
+
outbuf.clear.force_encoding(Encoding::BINARY)
|
|
32
|
+
outbuf << chunk
|
|
33
|
+
else
|
|
34
|
+
outbuf = chunk
|
|
35
|
+
end
|
|
36
|
+
outbuf unless length && outbuf.empty?
|
|
37
|
+
rescue StopIteration
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def close
|
|
42
|
+
@body.close if @body.respond_to?(:close)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
require_relative "body_reader"
|
|
5
|
+
|
|
6
|
+
module HTTPX
|
|
7
|
+
module Transcoder
|
|
8
|
+
class Deflater
|
|
9
|
+
extend Forwardable
|
|
10
|
+
|
|
11
|
+
attr_reader :content_type
|
|
12
|
+
|
|
13
|
+
def initialize(body)
|
|
14
|
+
@content_type = body.content_type
|
|
15
|
+
@body = BodyReader.new(body)
|
|
16
|
+
@closed = false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def bytesize
|
|
20
|
+
buffer_deflate!
|
|
21
|
+
|
|
22
|
+
@buffer.size
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def read(length = nil, outbuf = nil)
|
|
26
|
+
return @buffer.read(length, outbuf) if @buffer
|
|
27
|
+
|
|
28
|
+
return if @closed
|
|
29
|
+
|
|
30
|
+
chunk = @body.read(length)
|
|
31
|
+
|
|
32
|
+
compressed_chunk = deflate(chunk)
|
|
33
|
+
|
|
34
|
+
return unless compressed_chunk
|
|
35
|
+
|
|
36
|
+
if outbuf
|
|
37
|
+
outbuf.clear.force_encoding(Encoding::BINARY)
|
|
38
|
+
outbuf << compressed_chunk
|
|
39
|
+
else
|
|
40
|
+
compressed_chunk
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def close
|
|
45
|
+
return if @closed
|
|
46
|
+
|
|
47
|
+
@buffer.close if @buffer
|
|
48
|
+
|
|
49
|
+
@body.close
|
|
50
|
+
|
|
51
|
+
@closed = true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
|
57
|
+
def buffer_deflate!
|
|
58
|
+
return @buffer if defined?(@buffer)
|
|
59
|
+
|
|
60
|
+
buffer = Response::Buffer.new(
|
|
61
|
+
threshold_size: Options::MAX_BODY_THRESHOLD_SIZE
|
|
62
|
+
)
|
|
63
|
+
::IO.copy_stream(self, buffer)
|
|
64
|
+
|
|
65
|
+
buffer.rewind
|
|
66
|
+
|
|
67
|
+
@buffer = buffer
|
|
68
|
+
end
|
|
69
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/httpx/transcoder/xml.rb
CHANGED
data/lib/httpx/transcoder.rb
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module HTTPX
|
|
4
4
|
module Transcoder
|
|
5
|
-
using RegexpExtensions unless Regexp.method_defined?(:match?)
|
|
6
|
-
|
|
7
5
|
module_function
|
|
8
6
|
|
|
9
7
|
def normalize_keys(key, value, cond = nil, &block)
|
|
@@ -90,3 +88,5 @@ require "httpx/transcoder/form"
|
|
|
90
88
|
require "httpx/transcoder/json"
|
|
91
89
|
require "httpx/transcoder/xml"
|
|
92
90
|
require "httpx/transcoder/chunker"
|
|
91
|
+
require "httpx/transcoder/deflate"
|
|
92
|
+
require "httpx/transcoder/gzip"
|
data/lib/httpx/utils.rb
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
module HTTPX
|
|
4
4
|
module Utils
|
|
5
5
|
using URIExtensions
|
|
6
|
-
using HTTPX::RegexpExtensions unless Regexp.method_defined?(:match?)
|
|
7
6
|
|
|
8
7
|
TOKEN = %r{[^\s()<>,;:\\"/\[\]?=]+}.freeze
|
|
9
8
|
VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/.freeze
|
|
@@ -55,31 +54,22 @@ module HTTPX
|
|
|
55
54
|
filename
|
|
56
55
|
end
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
URIParser = URI::RFC2396_Parser.new
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
else
|
|
65
|
-
|
|
66
|
-
URIParser = URI::RFC2396_Parser.new
|
|
59
|
+
def to_uri(uri)
|
|
60
|
+
return URI(uri) unless uri.is_a?(String) && !uri.ascii_only?
|
|
67
61
|
|
|
68
|
-
|
|
69
|
-
return URI(uri) unless uri.is_a?(String) && !uri.ascii_only?
|
|
62
|
+
uri = URI(URIParser.escape(uri))
|
|
70
63
|
|
|
71
|
-
|
|
64
|
+
non_ascii_hostname = URIParser.unescape(uri.host)
|
|
72
65
|
|
|
73
|
-
|
|
66
|
+
non_ascii_hostname.force_encoding(Encoding::UTF_8)
|
|
74
67
|
|
|
75
|
-
|
|
68
|
+
idna_hostname = Punycode.encode_hostname(non_ascii_hostname)
|
|
76
69
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
uri.non_ascii_hostname = non_ascii_hostname
|
|
81
|
-
uri
|
|
82
|
-
end
|
|
70
|
+
uri.host = idna_hostname
|
|
71
|
+
uri.non_ascii_hostname = non_ascii_hostname
|
|
72
|
+
uri
|
|
83
73
|
end
|
|
84
74
|
end
|
|
85
75
|
end
|
data/lib/httpx/version.rb
CHANGED
data/lib/httpx.rb
CHANGED
|
@@ -53,14 +53,6 @@ module HTTPX
|
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
# :nocov:
|
|
57
|
-
def self.const_missing(const_name)
|
|
58
|
-
super unless const_name == :Client
|
|
59
|
-
warn "DEPRECATION WARNING: the class #{self}::Client is deprecated. Use #{self}::Session instead."
|
|
60
|
-
Session
|
|
61
|
-
end
|
|
62
|
-
# :nocov:
|
|
63
|
-
|
|
64
56
|
extend Chainable
|
|
65
57
|
end
|
|
66
58
|
|
data/sig/chainable.rbs
CHANGED
|
@@ -12,18 +12,17 @@ module HTTPX
|
|
|
12
12
|
def with: (options) -> Session
|
|
13
13
|
| (options) { (Session) -> void } -> void
|
|
14
14
|
|
|
15
|
-
def plugin: (:
|
|
16
|
-
| (:
|
|
17
|
-
| (:
|
|
18
|
-
| (:
|
|
15
|
+
def plugin: (:auth, ?options) -> Plugins::sessionAuthorization
|
|
16
|
+
| (:basic_auth, ?options) -> Plugins::sessionBasicAuth
|
|
17
|
+
| (:digest_auth, ?options) -> Plugins::sessionDigestAuth
|
|
18
|
+
| (:ntlm_auth, ?options) -> Plugins::sessionNTLMAuth
|
|
19
19
|
| (:aws_sdk_authentication, ?options) -> Plugins::sessionAwsSdkAuthentication
|
|
20
|
-
| (:
|
|
20
|
+
| (:brotli, ?options) -> Session
|
|
21
21
|
| (:cookies, ?options) -> Plugins::sessionCookies
|
|
22
22
|
| (:expect, ?options) -> Session
|
|
23
23
|
| (:follow_redirects, ?options) -> Plugins::sessionFollowRedirects
|
|
24
24
|
| (:upgrade, ?options) -> Session
|
|
25
25
|
| (:h2c, ?options) -> Session
|
|
26
|
-
| (:multipart, ?options) -> Session
|
|
27
26
|
| (:persistent, ?options) -> Plugins::sessionPersistent
|
|
28
27
|
| (:proxy, ?options) -> (Plugins::sessionProxy & Plugins::httpProxy)
|
|
29
28
|
| (:push_promise, ?options) -> Plugins::sessionPushPromise
|
data/sig/connection.rbs
CHANGED
data/sig/errors.rbs
CHANGED
data/sig/httpx.rbs
CHANGED
|
@@ -5,7 +5,8 @@ module HTTPX
|
|
|
5
5
|
|
|
6
6
|
VERSION: String
|
|
7
7
|
|
|
8
|
-
type
|
|
8
|
+
type http_uri = URI::HTTP | URI::HTTPS
|
|
9
|
+
type uri = http_uri | string
|
|
9
10
|
type generic_uri = String | URI::Generic
|
|
10
11
|
|
|
11
12
|
type verb = "OPTIONS" | "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT" |
|
data/sig/io/unix.rbs
CHANGED
data/sig/options.rbs
CHANGED
|
@@ -11,13 +11,11 @@ module HTTPX
|
|
|
11
11
|
SETTINGS_TIMEOUT: Integer
|
|
12
12
|
DEFAULT_OPTIONS: Hash[Symbol, untyped]
|
|
13
13
|
|
|
14
|
-
type timeout_type = :connect_timeout | :settings_timeout | :operation_timeout | :keep_alive_timeout | :
|
|
14
|
+
type timeout_type = :connect_timeout | :settings_timeout | :operation_timeout | :keep_alive_timeout | :read_timeout | :write_timeout | :request_timeout
|
|
15
15
|
type timeout = Hash[timeout_type, Numeric]
|
|
16
16
|
|
|
17
17
|
def self.new: (?options) -> instance
|
|
18
18
|
|
|
19
|
-
def self.def_option: (Symbol, ?String) -> void
|
|
20
|
-
| (Symbol) { (*nil) -> untyped } -> void
|
|
21
19
|
# headers
|
|
22
20
|
attr_reader uri: URI?
|
|
23
21
|
|
|
@@ -48,12 +46,18 @@ module HTTPX
|
|
|
48
46
|
# transport
|
|
49
47
|
attr_reader transport: "unix" | nil
|
|
50
48
|
|
|
51
|
-
# transport_options
|
|
52
|
-
attr_reader transport_options: Hash[untyped, untyped]?
|
|
53
|
-
|
|
54
49
|
# addresses
|
|
55
50
|
attr_reader addresses: Array[ipaddr]?
|
|
56
51
|
|
|
52
|
+
# supported_compression_formats
|
|
53
|
+
attr_reader supported_compression_formats: Array[String]
|
|
54
|
+
|
|
55
|
+
# compress_request_body
|
|
56
|
+
attr_reader compress_request_body: bool
|
|
57
|
+
|
|
58
|
+
# decompress_response_body
|
|
59
|
+
attr_reader decompress_response_body: bool
|
|
60
|
+
|
|
57
61
|
# params
|
|
58
62
|
attr_reader params: Transcoder::urlencoded_input?
|
|
59
63
|
|
|
@@ -124,9 +128,9 @@ module HTTPX
|
|
|
124
128
|
|
|
125
129
|
REQUEST_IVARS: Array[Symbol]
|
|
126
130
|
|
|
127
|
-
def initialize: (?options options) ->
|
|
131
|
+
def initialize: (?options options) -> void
|
|
128
132
|
|
|
129
|
-
def
|
|
133
|
+
def do_initialize: (?options options) -> void
|
|
130
134
|
end
|
|
131
135
|
|
|
132
136
|
type options = Options | Hash[Symbol, untyped]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module HTTPX
|
|
2
|
+
module Plugins
|
|
3
|
+
module Authorization
|
|
4
|
+
module InstanceMethods
|
|
5
|
+
def authorization: (string token) -> instance
|
|
6
|
+
|
|
7
|
+
def bearer_auth: (string token) -> instance
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
type sessionAuthorization = Session & Authorization::InstanceMethods
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -6,10 +6,10 @@ module HTTPX
|
|
|
6
6
|
def self.configure: (singleton(Session)) -> void
|
|
7
7
|
|
|
8
8
|
module InstanceMethods
|
|
9
|
-
def
|
|
9
|
+
def basic_auth: (string user, string password) -> instance
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
type sessionBasicAuth =
|
|
13
|
+
type sessionBasicAuth = sessionAuthorization & BasicAuth::InstanceMethods
|
|
14
14
|
end
|
|
15
15
|
end
|