httpx 0.20.0 → 1.3.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 +0 -48
- data/README.md +54 -45
- data/doc/release_notes/0_10_0.md +2 -2
- data/doc/release_notes/0_11_0.md +3 -5
- data/doc/release_notes/0_12_0.md +5 -5
- data/doc/release_notes/0_13_0.md +5 -5
- data/doc/release_notes/0_14_0.md +2 -2
- data/doc/release_notes/0_16_0.md +3 -3
- data/doc/release_notes/0_17_0.md +1 -1
- data/doc/release_notes/0_18_0.md +4 -4
- data/doc/release_notes/0_18_2.md +1 -1
- data/doc/release_notes/0_19_0.md +1 -1
- data/doc/release_notes/0_19_8.md +1 -1
- data/doc/release_notes/0_20_0.md +2 -2
- 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/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/lib/httpx/adapters/datadog.rb +215 -122
- data/lib/httpx/adapters/faraday.rb +145 -107
- data/lib/httpx/adapters/sentry.rb +26 -7
- data/lib/httpx/adapters/webmock.rb +34 -18
- data/lib/httpx/altsvc.rb +63 -26
- data/lib/httpx/base64.rb +27 -0
- data/lib/httpx/buffer.rb +12 -0
- data/lib/httpx/callbacks.rb +5 -3
- data/lib/httpx/chainable.rb +54 -39
- data/lib/httpx/connection/http1.rb +75 -44
- data/lib/httpx/connection/http2.rb +31 -38
- data/lib/httpx/connection.rb +287 -117
- data/lib/httpx/domain_name.rb +10 -13
- data/lib/httpx/errors.rb +52 -2
- data/lib/httpx/extensions.rb +24 -131
- data/lib/httpx/io/ssl.rb +83 -77
- data/lib/httpx/io/tcp.rb +48 -71
- data/lib/httpx/io/udp.rb +18 -52
- data/lib/httpx/io/unix.rb +10 -15
- data/lib/httpx/io.rb +3 -9
- data/lib/httpx/loggable.rb +4 -19
- data/lib/httpx/options.rb +176 -118
- data/lib/httpx/parser/http1.rb +4 -0
- data/lib/httpx/plugins/{authentication → auth}/basic.rb +1 -5
- data/lib/httpx/plugins/{authentication → auth}/digest.rb +14 -14
- 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_sdk_authentication.rb +4 -3
- data/lib/httpx/plugins/aws_sigv4.rb +12 -9
- data/lib/httpx/plugins/basic_auth.rb +29 -0
- data/lib/httpx/plugins/brotli.rb +50 -0
- data/lib/httpx/plugins/callbacks.rb +91 -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 +148 -0
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +0 -2
- data/lib/httpx/plugins/cookies.rb +30 -17
- data/lib/httpx/plugins/{digest_authentication.rb → digest_auth.rb} +14 -12
- data/lib/httpx/plugins/expect.rb +21 -14
- data/lib/httpx/plugins/follow_redirects.rb +140 -41
- data/lib/httpx/plugins/grpc/call.rb +2 -3
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +88 -0
- data/lib/httpx/plugins/grpc/message.rb +7 -37
- data/lib/httpx/plugins/grpc.rb +36 -29
- data/lib/httpx/plugins/h2c.rb +26 -19
- data/lib/httpx/plugins/internal_telemetry.rb +16 -0
- data/lib/httpx/plugins/{ntlm_authentication.rb → ntlm_auth.rb} +7 -5
- data/lib/httpx/plugins/oauth.rb +175 -0
- data/lib/httpx/plugins/persistent.rb +1 -1
- data/lib/httpx/plugins/proxy/http.rb +23 -13
- data/lib/httpx/plugins/proxy/socks4.rb +9 -7
- data/lib/httpx/plugins/proxy/socks5.rb +11 -9
- data/lib/httpx/plugins/proxy.rb +80 -61
- data/lib/httpx/plugins/push_promise.rb +1 -1
- data/lib/httpx/plugins/rate_limiter.rb +5 -1
- data/lib/httpx/plugins/response_cache/file_store.rb +40 -0
- data/lib/httpx/plugins/response_cache/store.rb +62 -25
- data/lib/httpx/plugins/response_cache.rb +105 -12
- data/lib/httpx/plugins/retries.rb +87 -17
- data/lib/httpx/plugins/ssrf_filter.rb +145 -0
- data/lib/httpx/plugins/stream.rb +27 -23
- data/lib/httpx/plugins/upgrade/h2.rb +4 -4
- data/lib/httpx/plugins/upgrade.rb +8 -10
- data/lib/httpx/plugins/webdav.rb +80 -0
- data/lib/httpx/pool/synch_pool.rb +93 -0
- data/lib/httpx/pool.rb +102 -27
- data/lib/httpx/punycode.rb +9 -291
- data/lib/httpx/request/body.rb +154 -0
- data/lib/httpx/request.rb +130 -146
- data/lib/httpx/resolver/https.rb +62 -27
- data/lib/httpx/resolver/multi.rb +9 -13
- data/lib/httpx/resolver/native.rb +192 -76
- data/lib/httpx/resolver/resolver.rb +34 -9
- data/lib/httpx/resolver/system.rb +16 -11
- data/lib/httpx/resolver.rb +38 -16
- data/lib/httpx/response/body.rb +242 -0
- data/lib/httpx/response/buffer.rb +96 -0
- data/lib/httpx/response.rb +159 -217
- data/lib/httpx/selector.rb +9 -4
- data/lib/httpx/session.rb +137 -89
- data/lib/httpx/session_extensions.rb +4 -1
- data/lib/httpx/timers.rb +34 -8
- data/lib/httpx/transcoder/body.rb +0 -2
- data/lib/httpx/transcoder/chunker.rb +0 -1
- data/lib/httpx/transcoder/deflate.rb +37 -0
- data/lib/httpx/transcoder/form.rb +52 -33
- data/lib/httpx/transcoder/gzip.rb +74 -0
- data/lib/httpx/transcoder/json.rb +21 -8
- data/lib/httpx/transcoder/multipart/decoder.rb +139 -0
- data/lib/httpx/{plugins → transcoder}/multipart/encoder.rb +4 -4
- 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/utils/inflater.rb +19 -0
- data/lib/httpx/transcoder/xml.rb +52 -0
- data/lib/httpx/transcoder.rb +5 -6
- data/lib/httpx/utils.rb +36 -16
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +12 -14
- data/sig/altsvc.rbs +33 -0
- data/sig/buffer.rbs +2 -1
- data/sig/callbacks.rbs +3 -3
- data/sig/chainable.rbs +11 -9
- data/sig/connection/http1.rbs +8 -7
- data/sig/connection/http2.rbs +19 -19
- data/sig/connection.rbs +64 -24
- data/sig/errors.rbs +22 -3
- data/sig/httpx.rbs +5 -4
- data/sig/io/ssl.rbs +27 -0
- data/sig/io/tcp.rbs +60 -0
- data/sig/io/udp.rbs +20 -0
- data/sig/io/unix.rbs +27 -0
- data/sig/io.rbs +6 -0
- data/sig/options.rbs +32 -22
- data/sig/parser/http1.rbs +1 -1
- data/sig/plugins/{authentication → auth}/basic.rbs +0 -2
- data/sig/plugins/{authentication → auth}/digest.rbs +2 -1
- 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/callbacks.rbs +38 -0
- data/sig/plugins/circuit_breaker.rbs +71 -0
- data/sig/plugins/compression.rbs +7 -5
- data/sig/plugins/cookies/jar.rbs +2 -2
- data/sig/plugins/cookies.rbs +2 -0
- data/sig/plugins/{digest_authentication.rbs → digest_auth.rbs} +2 -2
- data/sig/plugins/follow_redirects.rbs +18 -4
- data/sig/plugins/grpc/call.rbs +19 -0
- data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
- data/sig/plugins/grpc/message.rbs +17 -0
- data/sig/plugins/grpc.rbs +7 -32
- data/sig/plugins/h2c.rbs +1 -1
- data/sig/plugins/{ntlm_authentication.rbs → ntlm_auth.rbs} +2 -2
- data/sig/plugins/oauth.rbs +54 -0
- data/sig/plugins/proxy/http.rbs +3 -0
- data/sig/plugins/proxy/socks4.rbs +9 -6
- data/sig/plugins/proxy/socks5.rbs +10 -6
- data/sig/plugins/proxy/ssh.rbs +1 -1
- data/sig/plugins/proxy.rbs +13 -5
- data/sig/plugins/push_promise.rbs +3 -3
- data/sig/plugins/rate_limiter.rbs +1 -1
- data/sig/plugins/response_cache.rbs +36 -7
- data/sig/plugins/retries.rbs +30 -8
- data/sig/plugins/stream.rbs +24 -17
- data/sig/plugins/upgrade.rbs +5 -3
- data/sig/pool.rbs +10 -7
- data/sig/request/body.rbs +38 -0
- data/sig/request.rbs +15 -24
- data/sig/resolver/https.rbs +8 -3
- data/sig/resolver/native.rbs +17 -4
- data/sig/resolver/resolver.rbs +8 -6
- data/sig/resolver/system.rbs +2 -0
- data/sig/resolver.rbs +9 -5
- data/sig/response/body.rbs +53 -0
- data/sig/response/buffer.rbs +24 -0
- data/sig/response.rbs +24 -39
- data/sig/selector.rbs +1 -1
- data/sig/session.rbs +29 -18
- data/sig/timers.rbs +18 -8
- 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 +8 -3
- data/sig/{plugins → transcoder}/multipart.rbs +15 -19
- data/sig/transcoder/utils/body_reader.rbs +15 -0
- data/sig/transcoder/utils/deflater.rbs +29 -0
- data/sig/transcoder/utils/inflater.rbs +12 -0
- data/sig/transcoder/xml.rbs +22 -0
- data/sig/transcoder.rbs +24 -9
- data/sig/utils.rbs +8 -2
- metadata +163 -41
- data/lib/httpx/plugins/authentication.rb +0 -20
- data/lib/httpx/plugins/basic_authentication.rb +0 -30
- data/lib/httpx/plugins/compression/brotli.rb +0 -54
- data/lib/httpx/plugins/compression/deflate.rb +0 -49
- data/lib/httpx/plugins/compression/gzip.rb +0 -88
- data/lib/httpx/plugins/compression.rb +0 -164
- data/lib/httpx/plugins/multipart/decoder.rb +0 -187
- data/lib/httpx/plugins/multipart.rb +0 -84
- data/lib/httpx/registry.rb +0 -85
- data/sig/plugins/authentication.rbs +0 -11
- 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/registry.rbs +0 -12
- /data/sig/plugins/{authentication → auth}/ntlm.rbs +0 -0
- /data/sig/plugins/{authentication → auth}/socks5.rbs +0 -0
@@ -1,164 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module HTTPX
|
4
|
-
module Plugins
|
5
|
-
#
|
6
|
-
# This plugin adds compression support. Namely it:
|
7
|
-
#
|
8
|
-
# * Compresses the request body when passed a supported "Content-Encoding" mime-type;
|
9
|
-
# * Decompresses the response body from a supported "Content-Encoding" mime-type;
|
10
|
-
#
|
11
|
-
# It supports both *gzip* and *deflate*.
|
12
|
-
#
|
13
|
-
# https://gitlab.com/honeyryderchuck/httpx/wikis/Compression
|
14
|
-
#
|
15
|
-
module Compression
|
16
|
-
class << self
|
17
|
-
def configure(klass)
|
18
|
-
klass.plugin(:"compression/gzip")
|
19
|
-
klass.plugin(:"compression/deflate")
|
20
|
-
end
|
21
|
-
|
22
|
-
def extra_options(options)
|
23
|
-
encodings = Module.new do
|
24
|
-
extend Registry
|
25
|
-
end
|
26
|
-
options.merge(encodings: encodings)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
module OptionsMethods
|
31
|
-
def option_compression_threshold_size(value)
|
32
|
-
bytes = Integer(value)
|
33
|
-
raise TypeError, ":expect_threshold_size must be positive" unless bytes.positive?
|
34
|
-
|
35
|
-
bytes
|
36
|
-
end
|
37
|
-
|
38
|
-
def option_encodings(value)
|
39
|
-
raise TypeError, ":encodings must be a registry" unless value.respond_to?(:registry)
|
40
|
-
|
41
|
-
value
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
module RequestMethods
|
46
|
-
def initialize(*)
|
47
|
-
super
|
48
|
-
# forego compression in the Range cases
|
49
|
-
if @headers.key?("range")
|
50
|
-
@headers.delete("accept-encoding")
|
51
|
-
else
|
52
|
-
@headers["accept-encoding"] ||= @options.encodings.registry.keys
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
module RequestBodyMethods
|
58
|
-
def initialize(*, options)
|
59
|
-
super
|
60
|
-
return if @body.nil?
|
61
|
-
|
62
|
-
threshold = options.compression_threshold_size
|
63
|
-
return if threshold && !unbounded_body? && @body.bytesize < threshold
|
64
|
-
|
65
|
-
@headers.get("content-encoding").each do |encoding|
|
66
|
-
next if encoding == "identity"
|
67
|
-
|
68
|
-
@body = Encoder.new(@body, options.encodings.registry(encoding).deflater)
|
69
|
-
end
|
70
|
-
@headers["content-length"] = @body.bytesize unless unbounded_body?
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
module ResponseBodyMethods
|
75
|
-
using ArrayExtensions
|
76
|
-
|
77
|
-
attr_reader :encodings
|
78
|
-
|
79
|
-
def initialize(*)
|
80
|
-
@encodings = []
|
81
|
-
|
82
|
-
super
|
83
|
-
|
84
|
-
return unless @headers.key?("content-encoding")
|
85
|
-
|
86
|
-
# remove encodings that we are able to decode
|
87
|
-
@headers["content-encoding"] = @headers.get("content-encoding") - @encodings
|
88
|
-
|
89
|
-
compressed_length = if @headers.key?("content-length")
|
90
|
-
@headers["content-length"].to_i
|
91
|
-
else
|
92
|
-
Float::INFINITY
|
93
|
-
end
|
94
|
-
|
95
|
-
@_inflaters = @headers.get("content-encoding").filter_map do |encoding|
|
96
|
-
next if encoding == "identity"
|
97
|
-
|
98
|
-
inflater = @options.encodings.registry(encoding).inflater(compressed_length)
|
99
|
-
# do not uncompress if there is no decoder available. In fact, we can't reliably
|
100
|
-
# continue decompressing beyond that, so ignore.
|
101
|
-
break unless inflater
|
102
|
-
|
103
|
-
@encodings << encoding
|
104
|
-
inflater
|
105
|
-
end
|
106
|
-
|
107
|
-
# this can happen if the only declared encoding is "identity"
|
108
|
-
remove_instance_variable(:@_inflaters) if @_inflaters.empty?
|
109
|
-
end
|
110
|
-
|
111
|
-
def write(chunk)
|
112
|
-
return super unless defined?(@_inflaters) && !chunk.empty?
|
113
|
-
|
114
|
-
chunk = decompress(chunk)
|
115
|
-
super(chunk)
|
116
|
-
end
|
117
|
-
|
118
|
-
private
|
119
|
-
|
120
|
-
def decompress(buffer)
|
121
|
-
@_inflaters.reverse_each do |inflater|
|
122
|
-
buffer = inflater.inflate(buffer)
|
123
|
-
end
|
124
|
-
buffer
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
class Encoder
|
129
|
-
attr_reader :content_type
|
130
|
-
|
131
|
-
def initialize(body, deflater)
|
132
|
-
@content_type = body.content_type
|
133
|
-
@body = body.respond_to?(:read) ? body : StringIO.new(body.to_s)
|
134
|
-
@buffer = StringIO.new("".b, File::RDWR)
|
135
|
-
@deflater = deflater
|
136
|
-
end
|
137
|
-
|
138
|
-
def each(&blk)
|
139
|
-
return enum_for(__method__) unless blk
|
140
|
-
|
141
|
-
return deflate(&blk) if @buffer.size.zero?
|
142
|
-
|
143
|
-
@buffer.rewind
|
144
|
-
@buffer.each(&blk)
|
145
|
-
end
|
146
|
-
|
147
|
-
def bytesize
|
148
|
-
deflate
|
149
|
-
@buffer.size
|
150
|
-
end
|
151
|
-
|
152
|
-
private
|
153
|
-
|
154
|
-
def deflate(&blk)
|
155
|
-
return unless @buffer.size.zero?
|
156
|
-
|
157
|
-
@body.rewind
|
158
|
-
@deflater.deflate(@body, @buffer, chunk_size: 16_384, &blk)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
register_plugin :compression, Compression
|
163
|
-
end
|
164
|
-
end
|
@@ -1,187 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "tempfile"
|
4
|
-
require "delegate"
|
5
|
-
|
6
|
-
module HTTPX::Plugins
|
7
|
-
module Multipart
|
8
|
-
using HTTPX::RegexpExtensions unless Regexp.method_defined?(:match?)
|
9
|
-
|
10
|
-
CRLF = "\r\n"
|
11
|
-
|
12
|
-
class FilePart < SimpleDelegator
|
13
|
-
attr_reader :original_filename, :content_type
|
14
|
-
|
15
|
-
def initialize(filename, content_type)
|
16
|
-
@original_filename = filename
|
17
|
-
@content_type = content_type
|
18
|
-
@file = Tempfile.new("httpx", encoding: Encoding::BINARY, mode: File::RDWR)
|
19
|
-
super(@file)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
TOKEN = %r{[^\s()<>,;:\\"/\[\]?=]+}.freeze
|
24
|
-
VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/.freeze
|
25
|
-
CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i.freeze
|
26
|
-
BROKEN_QUOTED = /^#{CONDISP}.*;\s*filename="(.*?)"(?:\s*$|\s*;\s*#{TOKEN}=)/i.freeze
|
27
|
-
BROKEN_UNQUOTED = /^#{CONDISP}.*;\s*filename=(#{TOKEN})/i.freeze
|
28
|
-
MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{CRLF}/ni.freeze
|
29
|
-
MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni.freeze
|
30
|
-
MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{CRLF}]*)/ni.freeze
|
31
|
-
# Updated definitions from RFC 2231
|
32
|
-
ATTRIBUTE_CHAR = %r{[^ \t\v\n\r)(><@,;:\\"/\[\]?='*%]}.freeze
|
33
|
-
ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/.freeze
|
34
|
-
SECTION = /\*[0-9]+/.freeze
|
35
|
-
REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/.freeze
|
36
|
-
REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/.freeze
|
37
|
-
EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/.freeze
|
38
|
-
EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/.freeze
|
39
|
-
EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/.freeze
|
40
|
-
EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/.freeze
|
41
|
-
EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/.freeze
|
42
|
-
EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/.freeze
|
43
|
-
EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/.freeze
|
44
|
-
DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/.freeze
|
45
|
-
RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i.freeze
|
46
|
-
|
47
|
-
class Decoder
|
48
|
-
BOUNDARY_RE = /;\s*boundary=([^;]+)/i.freeze
|
49
|
-
WINDOW_SIZE = 2 << 14
|
50
|
-
|
51
|
-
def initialize(response)
|
52
|
-
@boundary = begin
|
53
|
-
m = response.headers["content-type"].to_s[BOUNDARY_RE, 1]
|
54
|
-
raise Error, "no boundary declared in content-type header" unless m
|
55
|
-
|
56
|
-
m.strip
|
57
|
-
end
|
58
|
-
@buffer = "".b
|
59
|
-
@parts = {}
|
60
|
-
@intermediate_boundary = "--#{@boundary}"
|
61
|
-
@state = :idle
|
62
|
-
end
|
63
|
-
|
64
|
-
def call(response, _)
|
65
|
-
response.body.each do |chunk|
|
66
|
-
@buffer << chunk
|
67
|
-
|
68
|
-
parse
|
69
|
-
end
|
70
|
-
|
71
|
-
raise Error, "invalid or unsupported multipart format" unless @buffer.empty?
|
72
|
-
|
73
|
-
@parts
|
74
|
-
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
def parse
|
79
|
-
case @state
|
80
|
-
when :idle
|
81
|
-
raise Error, "payload does not start with boundary" unless @buffer.start_with?("#{@intermediate_boundary}#{CRLF}")
|
82
|
-
|
83
|
-
@buffer = @buffer.byteslice(@intermediate_boundary.bytesize + 2..-1)
|
84
|
-
|
85
|
-
@state = :part_header
|
86
|
-
when :part_header
|
87
|
-
idx = @buffer.index("#{CRLF}#{CRLF}")
|
88
|
-
|
89
|
-
# raise Error, "couldn't parse part headers" unless idx
|
90
|
-
return unless idx
|
91
|
-
|
92
|
-
head = @buffer.byteslice(0..idx + 4 - 1)
|
93
|
-
|
94
|
-
@buffer = @buffer.byteslice(head.bytesize..-1)
|
95
|
-
|
96
|
-
content_type = head[MULTIPART_CONTENT_TYPE, 1]
|
97
|
-
if (name = head[MULTIPART_CONTENT_DISPOSITION, 1])
|
98
|
-
name = /\A"(.*)"\Z/ =~ name ? Regexp.last_match(1) : name.dup
|
99
|
-
name.gsub!(/\\(.)/, "\\1")
|
100
|
-
name
|
101
|
-
else
|
102
|
-
name = head[MULTIPART_CONTENT_ID, 1]
|
103
|
-
end
|
104
|
-
|
105
|
-
filename = get_filename(head)
|
106
|
-
|
107
|
-
name = filename || +"#{content_type || "text/plain"}[]" if name.nil? || name.empty?
|
108
|
-
|
109
|
-
@current = name
|
110
|
-
|
111
|
-
@parts[name] = if filename
|
112
|
-
FilePart.new(filename, content_type)
|
113
|
-
else
|
114
|
-
"".b
|
115
|
-
end
|
116
|
-
|
117
|
-
@state = :part_body
|
118
|
-
when :part_body
|
119
|
-
part = @parts[@current]
|
120
|
-
|
121
|
-
body_separator = if part.is_a?(FilePart)
|
122
|
-
"#{CRLF}#{CRLF}"
|
123
|
-
else
|
124
|
-
CRLF
|
125
|
-
end
|
126
|
-
idx = @buffer.index(body_separator)
|
127
|
-
|
128
|
-
if idx
|
129
|
-
payload = @buffer.byteslice(0..idx - 1)
|
130
|
-
@buffer = @buffer.byteslice(idx + body_separator.bytesize..-1)
|
131
|
-
part << payload
|
132
|
-
part.rewind if part.respond_to?(:rewind)
|
133
|
-
@state = :parse_boundary
|
134
|
-
else
|
135
|
-
part << @buffer
|
136
|
-
@buffer.clear
|
137
|
-
end
|
138
|
-
when :parse_boundary
|
139
|
-
raise Error, "payload does not start with boundary" unless @buffer.start_with?(@intermediate_boundary)
|
140
|
-
|
141
|
-
@buffer = @buffer.byteslice(@intermediate_boundary.bytesize..-1)
|
142
|
-
|
143
|
-
if @buffer == "--"
|
144
|
-
@buffer.clear
|
145
|
-
@state = :done
|
146
|
-
return
|
147
|
-
elsif @buffer.start_with?(CRLF)
|
148
|
-
@buffer = @buffer.byteslice(2..-1)
|
149
|
-
@state = :part_header
|
150
|
-
else
|
151
|
-
return
|
152
|
-
end
|
153
|
-
when :done
|
154
|
-
raise Error, "parsing should have been over by now"
|
155
|
-
end until @buffer.empty?
|
156
|
-
end
|
157
|
-
|
158
|
-
def get_filename(head)
|
159
|
-
filename = nil
|
160
|
-
case head
|
161
|
-
when RFC2183
|
162
|
-
params = Hash[*head.scan(DISPPARM).flat_map(&:compact)]
|
163
|
-
|
164
|
-
if (filename = params["filename"])
|
165
|
-
filename = Regexp.last_match(1) if filename =~ /^"(.*)"$/
|
166
|
-
elsif (filename = params["filename*"])
|
167
|
-
encoding, _, filename = filename.split("'", 3)
|
168
|
-
end
|
169
|
-
when BROKEN_QUOTED, BROKEN_UNQUOTED
|
170
|
-
filename = Regexp.last_match(1)
|
171
|
-
end
|
172
|
-
|
173
|
-
return unless filename
|
174
|
-
|
175
|
-
filename = URI::DEFAULT_PARSER.unescape(filename) if filename.scan(/%.?.?/).all? { |s| /%[0-9a-fA-F]{2}/.match?(s) }
|
176
|
-
|
177
|
-
filename.scrub!
|
178
|
-
|
179
|
-
filename = filename.gsub(/\\(.)/, '\1') unless /\\[^\\"]/.match?(filename)
|
180
|
-
|
181
|
-
filename.force_encoding ::Encoding.find(encoding) if encoding
|
182
|
-
|
183
|
-
filename
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module HTTPX
|
4
|
-
module Plugins
|
5
|
-
#
|
6
|
-
# This plugin adds support for passing `http-form_data` objects (like file objects) as "multipart/form-data";
|
7
|
-
#
|
8
|
-
# HTTPX.post(URL, form: form: { image: HTTP::FormData::File.new("path/to/file")})
|
9
|
-
#
|
10
|
-
# https://gitlab.com/honeyryderchuck/httpx/wikis/Multipart-Uploads
|
11
|
-
#
|
12
|
-
module Multipart
|
13
|
-
MULTIPART_VALUE_COND = lambda do |value|
|
14
|
-
value.respond_to?(:read) ||
|
15
|
-
(value.respond_to?(:to_hash) &&
|
16
|
-
value.key?(:body) &&
|
17
|
-
(value.key?(:filename) || value.key?(:content_type)))
|
18
|
-
end
|
19
|
-
|
20
|
-
class << self
|
21
|
-
def normalize_keys(key, value, &block)
|
22
|
-
Transcoder.normalize_keys(key, value, MULTIPART_VALUE_COND, &block)
|
23
|
-
end
|
24
|
-
|
25
|
-
def load_dependencies(*)
|
26
|
-
# :nocov:
|
27
|
-
begin
|
28
|
-
unless defined?(HTTP::FormData)
|
29
|
-
# in order not to break legacy code, we'll keep loading http/form_data for them.
|
30
|
-
require "http/form_data"
|
31
|
-
warn "httpx: http/form_data is no longer a requirement to use HTTPX :multipart plugin. See migration instructions under" \
|
32
|
-
"https://honeyryderchuck.gitlab.io/httpx/wiki/Multipart-Uploads.html#notes. \n\n" \
|
33
|
-
"If you'd like to stop seeing this message, require 'http/form_data' yourself."
|
34
|
-
end
|
35
|
-
rescue LoadError
|
36
|
-
end
|
37
|
-
# :nocov:
|
38
|
-
require "httpx/plugins/multipart/encoder"
|
39
|
-
require "httpx/plugins/multipart/decoder"
|
40
|
-
require "httpx/plugins/multipart/part"
|
41
|
-
require "httpx/plugins/multipart/mime_type_detector"
|
42
|
-
end
|
43
|
-
|
44
|
-
def configure(*)
|
45
|
-
Transcoder.register("form", FormTranscoder)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
module FormTranscoder
|
50
|
-
module_function
|
51
|
-
|
52
|
-
def encode(form)
|
53
|
-
if multipart?(form)
|
54
|
-
Encoder.new(form)
|
55
|
-
else
|
56
|
-
Transcoder::Form::Encoder.new(form)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def decode(response)
|
61
|
-
content_type = response.content_type.mime_type
|
62
|
-
|
63
|
-
case content_type
|
64
|
-
when "application/x-www-form-urlencoded"
|
65
|
-
Transcoder::Form.decode(response)
|
66
|
-
when "multipart/form-data"
|
67
|
-
Decoder.new(response)
|
68
|
-
else
|
69
|
-
raise Error, "invalid form mime type (#{content_type})"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def multipart?(data)
|
74
|
-
data.any? do |_, v|
|
75
|
-
MULTIPART_VALUE_COND.call(v) ||
|
76
|
-
(v.respond_to?(:to_ary) && v.to_ary.any?(&MULTIPART_VALUE_COND)) ||
|
77
|
-
(v.respond_to?(:to_hash) && v.to_hash.any? { |_, e| MULTIPART_VALUE_COND.call(e) })
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
register_plugin :multipart, Multipart
|
83
|
-
end
|
84
|
-
end
|
data/lib/httpx/registry.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module HTTPX
|
4
|
-
# Adds a general-purpose registry API to a class. It is designed to be a
|
5
|
-
# configuration-level API, i.e. the registry is global to the class and
|
6
|
-
# should be set on **boot time**.
|
7
|
-
#
|
8
|
-
# It is used internally to associate tags with handlers.
|
9
|
-
#
|
10
|
-
# ## Register/Fetch
|
11
|
-
#
|
12
|
-
# One is strongly advised to register handlers when creating the class.
|
13
|
-
#
|
14
|
-
# There is an instance-level method to retrieve from the registry based
|
15
|
-
# on the tag:
|
16
|
-
#
|
17
|
-
# class Server
|
18
|
-
# include HTTPX::Registry
|
19
|
-
#
|
20
|
-
# register "tcp", TCPHandler
|
21
|
-
# register "ssl", SSLHandlers
|
22
|
-
# ...
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# def handle(uri)
|
26
|
-
# scheme = uri.scheme
|
27
|
-
# handler = registry(scheme) #=> TCPHandler
|
28
|
-
# handler.handle
|
29
|
-
# end
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
module Registry
|
33
|
-
# Base Registry Error
|
34
|
-
class Error < Error; end
|
35
|
-
|
36
|
-
def self.extended(klass)
|
37
|
-
super
|
38
|
-
klass.extend(ClassMethods)
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.included(klass)
|
42
|
-
super
|
43
|
-
klass.extend(ClassMethods)
|
44
|
-
klass.__send__(:include, InstanceMethods)
|
45
|
-
end
|
46
|
-
|
47
|
-
# Class Methods
|
48
|
-
module ClassMethods
|
49
|
-
def inherited(klass)
|
50
|
-
super
|
51
|
-
klass.instance_variable_set(:@registry, @registry.dup)
|
52
|
-
end
|
53
|
-
|
54
|
-
# @param [Object] tag the handler identifier in the registry
|
55
|
-
# @return [Symbol, String, Object] the corresponding handler (if Symbol or String,
|
56
|
-
# will assume it referes to an autoloaded module, and will load-and-return it).
|
57
|
-
#
|
58
|
-
def registry(tag = nil)
|
59
|
-
@registry ||= {}
|
60
|
-
return @registry if tag.nil?
|
61
|
-
|
62
|
-
handler = @registry[tag]
|
63
|
-
raise(Error, "#{tag} is not registered in #{self}") unless handler
|
64
|
-
|
65
|
-
handler
|
66
|
-
end
|
67
|
-
|
68
|
-
# @param [Object] tag the identifier for the handler in the registry
|
69
|
-
# @return [Symbol, String, Object] the handler (if Symbol or String, it is
|
70
|
-
# assumed to be an autoloaded module, to be loaded later)
|
71
|
-
#
|
72
|
-
def register(tag, handler)
|
73
|
-
registry[tag] = handler
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Instance Methods
|
78
|
-
module InstanceMethods
|
79
|
-
# delegates to HTTPX::Registry#registry
|
80
|
-
def registry(tag)
|
81
|
-
self.class.registry(tag)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module HTTPX
|
2
|
-
module Plugins
|
3
|
-
module Compression
|
4
|
-
module Brotli
|
5
|
-
def self.load_dependencies: (singleton(Session)) -> void
|
6
|
-
def self.configure: (singleton(Session)) -> void
|
7
|
-
|
8
|
-
def self?.deflater: () -> _Deflater
|
9
|
-
def self?.decoder: (Numeric bytesize) -> Inflater
|
10
|
-
|
11
|
-
module Deflater
|
12
|
-
extend _Deflater
|
13
|
-
end
|
14
|
-
|
15
|
-
class Inflater
|
16
|
-
include _Inflater
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module HTTPX
|
2
|
-
module Plugins
|
3
|
-
module Compression
|
4
|
-
module Deflate
|
5
|
-
def self.load_dependencies: (singleton(Session)) -> void
|
6
|
-
def self.configure: (singleton(Session)) -> void
|
7
|
-
|
8
|
-
def self?.deflater: () -> _Deflater
|
9
|
-
def self?.inflater: (Numeric bytesize) -> GZIP::Inflater
|
10
|
-
|
11
|
-
module Deflater
|
12
|
-
extend _Deflater
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module HTTPX
|
2
|
-
module Plugins
|
3
|
-
module Compression
|
4
|
-
module GZIP
|
5
|
-
def self.load_dependencies: (singleton(Session)) -> void
|
6
|
-
def self.configure: (singleton(Session)) -> void
|
7
|
-
|
8
|
-
def self?.deflater: () -> _Deflater
|
9
|
-
def self?.inflater: (Numeric bytesize) -> Inflater
|
10
|
-
|
11
|
-
class Deflater
|
12
|
-
include _Deflater
|
13
|
-
|
14
|
-
@compressed_chunk: String
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def initialize: () -> untyped
|
19
|
-
def write: (string) -> void
|
20
|
-
def compressed_chunk: () -> String
|
21
|
-
end
|
22
|
-
|
23
|
-
class Inflater
|
24
|
-
include _Inflater
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/sig/registry.rbs
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
module HTTPX::Registry[T, V]
|
2
|
-
class Error < HTTPX::Error
|
3
|
-
end
|
4
|
-
|
5
|
-
# type registrable = Symbol | String | Class
|
6
|
-
|
7
|
-
def self.registry: (T tag) -> Class
|
8
|
-
| () -> Hash[T, V]
|
9
|
-
def self.register: (T tag, V handler) -> void
|
10
|
-
|
11
|
-
def registry: (?T tag) -> V
|
12
|
-
end
|
File without changes
|
File without changes
|