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.
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