httpx 0.20.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (250) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +0 -48
  3. data/README.md +54 -45
  4. data/doc/release_notes/0_10_0.md +2 -2
  5. data/doc/release_notes/0_11_0.md +3 -5
  6. data/doc/release_notes/0_12_0.md +5 -5
  7. data/doc/release_notes/0_13_0.md +5 -5
  8. data/doc/release_notes/0_14_0.md +2 -2
  9. data/doc/release_notes/0_16_0.md +3 -3
  10. data/doc/release_notes/0_17_0.md +1 -1
  11. data/doc/release_notes/0_18_0.md +4 -4
  12. data/doc/release_notes/0_18_2.md +1 -1
  13. data/doc/release_notes/0_19_0.md +1 -1
  14. data/doc/release_notes/0_19_8.md +1 -1
  15. data/doc/release_notes/0_20_0.md +2 -2
  16. data/doc/release_notes/0_20_1.md +5 -0
  17. data/doc/release_notes/0_20_2.md +7 -0
  18. data/doc/release_notes/0_20_3.md +6 -0
  19. data/doc/release_notes/0_20_4.md +17 -0
  20. data/doc/release_notes/0_20_5.md +3 -0
  21. data/doc/release_notes/0_21_0.md +96 -0
  22. data/doc/release_notes/0_21_1.md +12 -0
  23. data/doc/release_notes/0_22_0.md +13 -0
  24. data/doc/release_notes/0_22_1.md +11 -0
  25. data/doc/release_notes/0_22_2.md +5 -0
  26. data/doc/release_notes/0_22_3.md +55 -0
  27. data/doc/release_notes/0_22_4.md +6 -0
  28. data/doc/release_notes/0_22_5.md +6 -0
  29. data/doc/release_notes/0_23_0.md +42 -0
  30. data/doc/release_notes/0_23_1.md +5 -0
  31. data/doc/release_notes/0_23_2.md +5 -0
  32. data/doc/release_notes/0_23_3.md +6 -0
  33. data/doc/release_notes/0_23_4.md +5 -0
  34. data/doc/release_notes/0_24_0.md +48 -0
  35. data/doc/release_notes/0_24_1.md +12 -0
  36. data/doc/release_notes/0_24_2.md +12 -0
  37. data/doc/release_notes/0_24_3.md +12 -0
  38. data/doc/release_notes/0_24_4.md +18 -0
  39. data/doc/release_notes/0_24_5.md +6 -0
  40. data/doc/release_notes/0_24_6.md +5 -0
  41. data/doc/release_notes/0_24_7.md +10 -0
  42. data/doc/release_notes/1_0_0.md +60 -0
  43. data/doc/release_notes/1_0_1.md +5 -0
  44. data/doc/release_notes/1_0_2.md +7 -0
  45. data/doc/release_notes/1_1_0.md +32 -0
  46. data/doc/release_notes/1_1_1.md +17 -0
  47. data/doc/release_notes/1_1_2.md +12 -0
  48. data/doc/release_notes/1_1_3.md +18 -0
  49. data/doc/release_notes/1_1_4.md +6 -0
  50. data/doc/release_notes/1_1_5.md +12 -0
  51. data/doc/release_notes/1_2_0.md +49 -0
  52. data/doc/release_notes/1_2_1.md +6 -0
  53. data/doc/release_notes/1_2_2.md +10 -0
  54. data/doc/release_notes/1_2_3.md +16 -0
  55. data/doc/release_notes/1_2_4.md +8 -0
  56. data/doc/release_notes/1_2_5.md +7 -0
  57. data/doc/release_notes/1_2_6.md +13 -0
  58. data/doc/release_notes/1_3_0.md +18 -0
  59. data/doc/release_notes/1_3_1.md +17 -0
  60. data/lib/httpx/adapters/datadog.rb +215 -122
  61. data/lib/httpx/adapters/faraday.rb +145 -107
  62. data/lib/httpx/adapters/sentry.rb +26 -7
  63. data/lib/httpx/adapters/webmock.rb +34 -18
  64. data/lib/httpx/altsvc.rb +63 -26
  65. data/lib/httpx/base64.rb +27 -0
  66. data/lib/httpx/buffer.rb +12 -0
  67. data/lib/httpx/callbacks.rb +5 -3
  68. data/lib/httpx/chainable.rb +54 -39
  69. data/lib/httpx/connection/http1.rb +75 -44
  70. data/lib/httpx/connection/http2.rb +31 -38
  71. data/lib/httpx/connection.rb +287 -117
  72. data/lib/httpx/domain_name.rb +10 -13
  73. data/lib/httpx/errors.rb +52 -2
  74. data/lib/httpx/extensions.rb +24 -131
  75. data/lib/httpx/io/ssl.rb +83 -77
  76. data/lib/httpx/io/tcp.rb +48 -71
  77. data/lib/httpx/io/udp.rb +18 -52
  78. data/lib/httpx/io/unix.rb +10 -15
  79. data/lib/httpx/io.rb +3 -9
  80. data/lib/httpx/loggable.rb +4 -19
  81. data/lib/httpx/options.rb +176 -118
  82. data/lib/httpx/parser/http1.rb +4 -0
  83. data/lib/httpx/plugins/{authentication → auth}/basic.rb +1 -5
  84. data/lib/httpx/plugins/{authentication → auth}/digest.rb +14 -14
  85. data/lib/httpx/plugins/{authentication → auth}/ntlm.rb +1 -3
  86. data/lib/httpx/plugins/{authentication → auth}/socks5.rb +0 -2
  87. data/lib/httpx/plugins/auth.rb +25 -0
  88. data/lib/httpx/plugins/aws_sdk_authentication.rb +4 -3
  89. data/lib/httpx/plugins/aws_sigv4.rb +12 -9
  90. data/lib/httpx/plugins/basic_auth.rb +29 -0
  91. data/lib/httpx/plugins/brotli.rb +50 -0
  92. data/lib/httpx/plugins/callbacks.rb +91 -0
  93. data/lib/httpx/plugins/circuit_breaker/circuit.rb +100 -0
  94. data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +53 -0
  95. data/lib/httpx/plugins/circuit_breaker.rb +148 -0
  96. data/lib/httpx/plugins/cookies/set_cookie_parser.rb +0 -2
  97. data/lib/httpx/plugins/cookies.rb +30 -17
  98. data/lib/httpx/plugins/{digest_authentication.rb → digest_auth.rb} +14 -12
  99. data/lib/httpx/plugins/expect.rb +21 -14
  100. data/lib/httpx/plugins/follow_redirects.rb +140 -41
  101. data/lib/httpx/plugins/grpc/call.rb +2 -3
  102. data/lib/httpx/plugins/grpc/grpc_encoding.rb +88 -0
  103. data/lib/httpx/plugins/grpc/message.rb +7 -37
  104. data/lib/httpx/plugins/grpc.rb +36 -29
  105. data/lib/httpx/plugins/h2c.rb +26 -19
  106. data/lib/httpx/plugins/internal_telemetry.rb +16 -0
  107. data/lib/httpx/plugins/{ntlm_authentication.rb → ntlm_auth.rb} +7 -5
  108. data/lib/httpx/plugins/oauth.rb +175 -0
  109. data/lib/httpx/plugins/persistent.rb +1 -1
  110. data/lib/httpx/plugins/proxy/http.rb +23 -13
  111. data/lib/httpx/plugins/proxy/socks4.rb +9 -7
  112. data/lib/httpx/plugins/proxy/socks5.rb +11 -9
  113. data/lib/httpx/plugins/proxy.rb +80 -61
  114. data/lib/httpx/plugins/push_promise.rb +1 -1
  115. data/lib/httpx/plugins/rate_limiter.rb +5 -1
  116. data/lib/httpx/plugins/response_cache/file_store.rb +40 -0
  117. data/lib/httpx/plugins/response_cache/store.rb +62 -25
  118. data/lib/httpx/plugins/response_cache.rb +105 -12
  119. data/lib/httpx/plugins/retries.rb +87 -17
  120. data/lib/httpx/plugins/ssrf_filter.rb +145 -0
  121. data/lib/httpx/plugins/stream.rb +27 -23
  122. data/lib/httpx/plugins/upgrade/h2.rb +4 -4
  123. data/lib/httpx/plugins/upgrade.rb +8 -10
  124. data/lib/httpx/plugins/webdav.rb +80 -0
  125. data/lib/httpx/pool/synch_pool.rb +93 -0
  126. data/lib/httpx/pool.rb +102 -27
  127. data/lib/httpx/punycode.rb +9 -291
  128. data/lib/httpx/request/body.rb +154 -0
  129. data/lib/httpx/request.rb +130 -146
  130. data/lib/httpx/resolver/https.rb +62 -27
  131. data/lib/httpx/resolver/multi.rb +9 -13
  132. data/lib/httpx/resolver/native.rb +192 -76
  133. data/lib/httpx/resolver/resolver.rb +34 -9
  134. data/lib/httpx/resolver/system.rb +16 -11
  135. data/lib/httpx/resolver.rb +38 -16
  136. data/lib/httpx/response/body.rb +242 -0
  137. data/lib/httpx/response/buffer.rb +96 -0
  138. data/lib/httpx/response.rb +159 -217
  139. data/lib/httpx/selector.rb +9 -4
  140. data/lib/httpx/session.rb +137 -89
  141. data/lib/httpx/session_extensions.rb +4 -1
  142. data/lib/httpx/timers.rb +34 -8
  143. data/lib/httpx/transcoder/body.rb +0 -2
  144. data/lib/httpx/transcoder/chunker.rb +0 -1
  145. data/lib/httpx/transcoder/deflate.rb +37 -0
  146. data/lib/httpx/transcoder/form.rb +52 -33
  147. data/lib/httpx/transcoder/gzip.rb +74 -0
  148. data/lib/httpx/transcoder/json.rb +21 -8
  149. data/lib/httpx/transcoder/multipart/decoder.rb +139 -0
  150. data/lib/httpx/{plugins → transcoder}/multipart/encoder.rb +4 -4
  151. data/lib/httpx/{plugins → transcoder}/multipart/mime_type_detector.rb +1 -1
  152. data/lib/httpx/{plugins → transcoder}/multipart/part.rb +3 -2
  153. data/lib/httpx/transcoder/multipart.rb +17 -0
  154. data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
  155. data/lib/httpx/transcoder/utils/deflater.rb +72 -0
  156. data/lib/httpx/transcoder/utils/inflater.rb +19 -0
  157. data/lib/httpx/transcoder/xml.rb +52 -0
  158. data/lib/httpx/transcoder.rb +5 -6
  159. data/lib/httpx/utils.rb +36 -16
  160. data/lib/httpx/version.rb +1 -1
  161. data/lib/httpx.rb +12 -14
  162. data/sig/altsvc.rbs +33 -0
  163. data/sig/buffer.rbs +2 -1
  164. data/sig/callbacks.rbs +3 -3
  165. data/sig/chainable.rbs +11 -9
  166. data/sig/connection/http1.rbs +8 -7
  167. data/sig/connection/http2.rbs +19 -19
  168. data/sig/connection.rbs +64 -24
  169. data/sig/errors.rbs +22 -3
  170. data/sig/httpx.rbs +5 -4
  171. data/sig/io/ssl.rbs +27 -0
  172. data/sig/io/tcp.rbs +60 -0
  173. data/sig/io/udp.rbs +20 -0
  174. data/sig/io/unix.rbs +27 -0
  175. data/sig/io.rbs +6 -0
  176. data/sig/options.rbs +32 -22
  177. data/sig/parser/http1.rbs +1 -1
  178. data/sig/plugins/{authentication → auth}/basic.rbs +0 -2
  179. data/sig/plugins/{authentication → auth}/digest.rbs +2 -1
  180. data/sig/plugins/auth.rbs +13 -0
  181. data/sig/plugins/{basic_authentication.rbs → basic_auth.rbs} +2 -2
  182. data/sig/plugins/brotli.rbs +22 -0
  183. data/sig/plugins/callbacks.rbs +38 -0
  184. data/sig/plugins/circuit_breaker.rbs +71 -0
  185. data/sig/plugins/compression.rbs +7 -5
  186. data/sig/plugins/cookies/jar.rbs +2 -2
  187. data/sig/plugins/cookies.rbs +2 -0
  188. data/sig/plugins/{digest_authentication.rbs → digest_auth.rbs} +2 -2
  189. data/sig/plugins/follow_redirects.rbs +18 -4
  190. data/sig/plugins/grpc/call.rbs +19 -0
  191. data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
  192. data/sig/plugins/grpc/message.rbs +17 -0
  193. data/sig/plugins/grpc.rbs +7 -32
  194. data/sig/plugins/h2c.rbs +1 -1
  195. data/sig/plugins/{ntlm_authentication.rbs → ntlm_auth.rbs} +2 -2
  196. data/sig/plugins/oauth.rbs +54 -0
  197. data/sig/plugins/proxy/http.rbs +3 -0
  198. data/sig/plugins/proxy/socks4.rbs +9 -6
  199. data/sig/plugins/proxy/socks5.rbs +10 -6
  200. data/sig/plugins/proxy/ssh.rbs +1 -1
  201. data/sig/plugins/proxy.rbs +13 -5
  202. data/sig/plugins/push_promise.rbs +3 -3
  203. data/sig/plugins/rate_limiter.rbs +1 -1
  204. data/sig/plugins/response_cache.rbs +36 -7
  205. data/sig/plugins/retries.rbs +30 -8
  206. data/sig/plugins/stream.rbs +24 -17
  207. data/sig/plugins/upgrade.rbs +5 -3
  208. data/sig/pool.rbs +10 -7
  209. data/sig/request/body.rbs +38 -0
  210. data/sig/request.rbs +15 -24
  211. data/sig/resolver/https.rbs +8 -3
  212. data/sig/resolver/native.rbs +17 -4
  213. data/sig/resolver/resolver.rbs +8 -6
  214. data/sig/resolver/system.rbs +2 -0
  215. data/sig/resolver.rbs +9 -5
  216. data/sig/response/body.rbs +53 -0
  217. data/sig/response/buffer.rbs +24 -0
  218. data/sig/response.rbs +24 -39
  219. data/sig/selector.rbs +1 -1
  220. data/sig/session.rbs +29 -18
  221. data/sig/timers.rbs +18 -8
  222. data/sig/transcoder/body.rbs +4 -3
  223. data/sig/transcoder/deflate.rbs +11 -0
  224. data/sig/transcoder/form.rbs +5 -3
  225. data/sig/transcoder/gzip.rbs +24 -0
  226. data/sig/transcoder/json.rbs +8 -3
  227. data/sig/{plugins → transcoder}/multipart.rbs +15 -19
  228. data/sig/transcoder/utils/body_reader.rbs +15 -0
  229. data/sig/transcoder/utils/deflater.rbs +29 -0
  230. data/sig/transcoder/utils/inflater.rbs +12 -0
  231. data/sig/transcoder/xml.rbs +22 -0
  232. data/sig/transcoder.rbs +24 -9
  233. data/sig/utils.rbs +8 -2
  234. metadata +163 -41
  235. data/lib/httpx/plugins/authentication.rb +0 -20
  236. data/lib/httpx/plugins/basic_authentication.rb +0 -30
  237. data/lib/httpx/plugins/compression/brotli.rb +0 -54
  238. data/lib/httpx/plugins/compression/deflate.rb +0 -49
  239. data/lib/httpx/plugins/compression/gzip.rb +0 -88
  240. data/lib/httpx/plugins/compression.rb +0 -164
  241. data/lib/httpx/plugins/multipart/decoder.rb +0 -187
  242. data/lib/httpx/plugins/multipart.rb +0 -84
  243. data/lib/httpx/registry.rb +0 -85
  244. data/sig/plugins/authentication.rbs +0 -11
  245. data/sig/plugins/compression/brotli.rbs +0 -21
  246. data/sig/plugins/compression/deflate.rbs +0 -17
  247. data/sig/plugins/compression/gzip.rbs +0 -29
  248. data/sig/registry.rbs +0 -12
  249. /data/sig/plugins/{authentication → auth}/ntlm.rbs +0 -0
  250. /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
@@ -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,11 +0,0 @@
1
- module HTTPX
2
- module Plugins
3
- module Authentication
4
- module InstanceMethods
5
- def authentication: (string token) -> instance
6
- end
7
- end
8
-
9
- type sessionAuthentication = Session & Authentication::InstanceMethods
10
- end
11
- 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