rack 2.2.4 → 3.0.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +223 -71
- data/CONTRIBUTING.md +53 -47
- data/MIT-LICENSE +1 -1
- data/README.md +309 -0
- data/SPEC.rdoc +183 -131
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +3 -1
- data/lib/rack/auth/basic.rb +0 -2
- data/lib/rack/auth/digest/md5.rb +1 -131
- data/lib/rack/auth/digest/nonce.rb +1 -54
- data/lib/rack/auth/digest/params.rb +1 -54
- data/lib/rack/auth/digest/request.rb +1 -43
- data/lib/rack/auth/digest.rb +256 -0
- data/lib/rack/body_proxy.rb +3 -1
- data/lib/rack/builder.rb +83 -63
- data/lib/rack/cascade.rb +2 -0
- data/lib/rack/chunked.rb +16 -13
- data/lib/rack/common_logger.rb +23 -18
- data/lib/rack/conditional_get.rb +18 -15
- data/lib/rack/constants.rb +64 -0
- data/lib/rack/content_length.rb +12 -16
- data/lib/rack/content_type.rb +8 -5
- data/lib/rack/deflater.rb +40 -26
- data/lib/rack/directory.rb +9 -3
- data/lib/rack/etag.rb +14 -23
- data/lib/rack/events.rb +4 -0
- data/lib/rack/file.rb +2 -0
- data/lib/rack/files.rb +15 -17
- data/lib/rack/head.rb +9 -8
- data/lib/rack/headers.rb +154 -0
- data/lib/rack/lint.rb +783 -682
- data/lib/rack/lock.rb +2 -5
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +1 -1
- data/lib/rack/method_override.rb +6 -2
- data/lib/rack/mime.rb +8 -0
- data/lib/rack/mock.rb +1 -271
- data/lib/rack/mock_request.rb +166 -0
- data/lib/rack/mock_response.rb +126 -0
- data/lib/rack/multipart/generator.rb +7 -5
- data/lib/rack/multipart/parser.rb +134 -65
- data/lib/rack/multipart/uploaded_file.rb +4 -0
- data/lib/rack/multipart.rb +20 -40
- data/lib/rack/null_logger.rb +9 -0
- data/lib/rack/query_parser.rb +78 -46
- data/lib/rack/recursive.rb +2 -0
- data/lib/rack/reloader.rb +0 -2
- data/lib/rack/request.rb +226 -108
- data/lib/rack/response.rb +136 -61
- data/lib/rack/rewindable_input.rb +24 -5
- data/lib/rack/runtime.rb +7 -6
- data/lib/rack/sendfile.rb +30 -25
- data/lib/rack/show_exceptions.rb +15 -2
- data/lib/rack/show_status.rb +17 -7
- data/lib/rack/static.rb +8 -8
- data/lib/rack/tempfile_reaper.rb +15 -4
- data/lib/rack/urlmap.rb +4 -2
- data/lib/rack/utils.rb +223 -185
- data/lib/rack/version.rb +9 -4
- data/lib/rack.rb +6 -76
- metadata +18 -38
- data/README.rdoc +0 -306
- data/Rakefile +0 -130
- data/bin/rackup +0 -5
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +0 -150
- data/contrib/rack_logo.svg +0 -164
- data/contrib/rdoc.css +0 -412
- data/example/lobster.ru +0 -6
- data/example/protectedlobster.rb +0 -16
- data/example/protectedlobster.ru +0 -10
- data/lib/rack/core_ext/regexp.rb +0 -14
- data/lib/rack/handler/cgi.rb +0 -59
- data/lib/rack/handler/fastcgi.rb +0 -100
- data/lib/rack/handler/lsws.rb +0 -61
- data/lib/rack/handler/scgi.rb +0 -71
- data/lib/rack/handler/thin.rb +0 -36
- data/lib/rack/handler/webrick.rb +0 -129
- data/lib/rack/handler.rb +0 -104
- data/lib/rack/lobster.rb +0 -70
- data/lib/rack/server.rb +0 -466
- data/lib/rack/session/abstract/id.rb +0 -523
- data/lib/rack/session/cookie.rb +0 -203
- data/lib/rack/session/memcache.rb +0 -10
- data/lib/rack/session/pool.rb +0 -85
- data/rack.gemspec +0 -46
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'uploaded_file'
|
4
|
+
|
3
5
|
module Rack
|
4
6
|
module Multipart
|
5
7
|
class Generator
|
@@ -74,12 +76,12 @@ module Rack
|
|
74
76
|
|
75
77
|
def content_for_tempfile(io, file, name)
|
76
78
|
length = ::File.stat(file.path).size if file.path
|
77
|
-
filename = "; filename=\"#{Utils.
|
79
|
+
filename = "; filename=\"#{Utils.escape_path(file.original_filename)}\""
|
78
80
|
<<-EOF
|
79
81
|
--#{MULTIPART_BOUNDARY}\r
|
80
|
-
|
81
|
-
|
82
|
-
#{"
|
82
|
+
content-disposition: form-data; name="#{name}"#{filename}\r
|
83
|
+
content-type: #{file.content_type}\r
|
84
|
+
#{"content-length: #{length}\r\n" if length}\r
|
83
85
|
#{io.read}\r
|
84
86
|
EOF
|
85
87
|
end
|
@@ -87,7 +89,7 @@ EOF
|
|
87
89
|
def content_for_other(file, name)
|
88
90
|
<<-EOF
|
89
91
|
--#{MULTIPART_BOUNDARY}\r
|
90
|
-
|
92
|
+
content-disposition: form-data; name="#{name}"\r
|
91
93
|
\r
|
92
94
|
#{file}\r
|
93
95
|
EOF
|
@@ -2,21 +2,54 @@
|
|
2
2
|
|
3
3
|
require 'strscan'
|
4
4
|
|
5
|
+
require_relative '../utils'
|
6
|
+
|
5
7
|
module Rack
|
6
8
|
module Multipart
|
7
9
|
class MultipartPartLimitError < Errno::EMFILE; end
|
8
10
|
|
9
|
-
class
|
10
|
-
|
11
|
+
class MultipartTotalPartLimitError < StandardError; end
|
12
|
+
|
13
|
+
# Use specific error class when parsing multipart request
|
14
|
+
# that ends early.
|
15
|
+
class EmptyContentError < ::EOFError; end
|
16
|
+
|
17
|
+
# Base class for multipart exceptions that do not subclass from
|
18
|
+
# other exception classes for backwards compatibility.
|
19
|
+
class Error < StandardError; end
|
20
|
+
|
21
|
+
EOL = "\r\n"
|
22
|
+
MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni
|
23
|
+
TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/
|
24
|
+
CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i
|
25
|
+
VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/
|
26
|
+
BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i
|
27
|
+
MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni
|
28
|
+
MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:[^:]*;\s*name=(#{VALUE})/ni
|
29
|
+
MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni
|
30
|
+
# Updated definitions from RFC 2231
|
31
|
+
ATTRIBUTE_CHAR = %r{[^ \x00-\x1f\x7f)(><@,;:\\"/\[\]?='*%]}
|
32
|
+
ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/
|
33
|
+
SECTION = /\*[0-9]+/
|
34
|
+
REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/
|
35
|
+
REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/
|
36
|
+
EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/
|
37
|
+
EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/
|
38
|
+
EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/
|
39
|
+
EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/
|
40
|
+
EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/
|
41
|
+
EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/
|
42
|
+
EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/
|
43
|
+
DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/
|
44
|
+
RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i
|
11
45
|
|
46
|
+
class Parser
|
12
47
|
BUFSIZE = 1_048_576
|
13
48
|
TEXT_PLAIN = "text/plain"
|
14
49
|
TEMPFILE_FACTORY = lambda { |filename, content_type|
|
15
50
|
Tempfile.new(["RackMultipart", ::File.extname(filename.gsub("\0", '%00'))])
|
16
51
|
}
|
17
52
|
|
18
|
-
BOUNDARY_REGEX = /\A([^\n]*(?:\n|\Z))/
|
19
|
-
|
20
53
|
class BoundedIO # :nodoc:
|
21
54
|
def initialize(io, content_length)
|
22
55
|
@io = io
|
@@ -38,16 +71,12 @@ module Rack
|
|
38
71
|
if str
|
39
72
|
@cursor += str.bytesize
|
40
73
|
else
|
41
|
-
# Raise an error for mismatching
|
74
|
+
# Raise an error for mismatching content-length and actual contents
|
42
75
|
raise EOFError, "bad content body"
|
43
76
|
end
|
44
77
|
|
45
78
|
str
|
46
79
|
end
|
47
|
-
|
48
|
-
def rewind
|
49
|
-
@io.rewind
|
50
|
-
end
|
51
80
|
end
|
52
81
|
|
53
82
|
MultipartInfo = Struct.new :params, :tmp_files
|
@@ -66,18 +95,17 @@ module Rack
|
|
66
95
|
boundary = parse_boundary content_type
|
67
96
|
return EMPTY unless boundary
|
68
97
|
|
98
|
+
if boundary.length > 70
|
99
|
+
# RFC 1521 Section 7.2.1 imposes a 70 character maximum for the boundary.
|
100
|
+
# Most clients use no more than 55 characters.
|
101
|
+
raise Error, "multipart boundary size too large (#{boundary.length} characters)"
|
102
|
+
end
|
103
|
+
|
69
104
|
io = BoundedIO.new(io, content_length) if content_length
|
70
|
-
outbuf = String.new
|
71
105
|
|
72
106
|
parser = new(boundary, tmpfile, bufsize, qp)
|
73
|
-
parser.
|
107
|
+
parser.parse(io)
|
74
108
|
|
75
|
-
loop do
|
76
|
-
break if parser.state == :DONE
|
77
|
-
parser.on_read io.read(bufsize, outbuf)
|
78
|
-
end
|
79
|
-
|
80
|
-
io.rewind
|
81
109
|
parser.result
|
82
110
|
end
|
83
111
|
|
@@ -140,7 +168,7 @@ module Rack
|
|
140
168
|
|
141
169
|
@mime_parts[mime_index] = klass.new(body, head, filename, content_type, name)
|
142
170
|
|
143
|
-
|
171
|
+
check_part_limits
|
144
172
|
end
|
145
173
|
|
146
174
|
def on_mime_body(mime_index, content)
|
@@ -152,13 +180,23 @@ module Rack
|
|
152
180
|
|
153
181
|
private
|
154
182
|
|
155
|
-
def
|
156
|
-
|
157
|
-
|
183
|
+
def check_part_limits
|
184
|
+
file_limit = Utils.multipart_file_limit
|
185
|
+
part_limit = Utils.multipart_total_part_limit
|
186
|
+
|
187
|
+
if file_limit && file_limit > 0
|
188
|
+
if @open_files >= file_limit
|
158
189
|
@mime_parts.each(&:close)
|
159
190
|
raise MultipartPartLimitError, 'Maximum file multiparts in content reached'
|
160
191
|
end
|
161
192
|
end
|
193
|
+
|
194
|
+
if part_limit && part_limit > 0
|
195
|
+
if @mime_parts.size >= part_limit
|
196
|
+
@mime_parts.each(&:close)
|
197
|
+
raise MultipartTotalPartLimitError, 'Maximum total multiparts in content reached'
|
198
|
+
end
|
199
|
+
end
|
162
200
|
end
|
163
201
|
end
|
164
202
|
|
@@ -167,32 +205,46 @@ module Rack
|
|
167
205
|
def initialize(boundary, tempfile, bufsize, query_parser)
|
168
206
|
@query_parser = query_parser
|
169
207
|
@params = query_parser.make_params
|
170
|
-
@boundary = "--#{boundary}"
|
171
208
|
@bufsize = bufsize
|
172
209
|
|
173
|
-
@full_boundary = @boundary
|
174
|
-
@end_boundary = @boundary + '--'
|
175
210
|
@state = :FAST_FORWARD
|
176
211
|
@mime_index = 0
|
177
212
|
@collector = Collector.new tempfile
|
178
213
|
|
179
214
|
@sbuf = StringScanner.new("".dup)
|
180
|
-
@body_regex = /(?:#{EOL})
|
181
|
-
@rx_max_size =
|
215
|
+
@body_regex = /(?:#{EOL}|\A)--#{Regexp.quote(boundary)}(?:#{EOL}|--)/m
|
216
|
+
@rx_max_size = boundary.bytesize + 6 # (\r\n-- at start, either \r\n or -- at finish)
|
182
217
|
@head_regex = /(.*?#{EOL})#{EOL}/m
|
183
218
|
end
|
184
219
|
|
185
|
-
def
|
186
|
-
|
187
|
-
|
188
|
-
|
220
|
+
def parse(io)
|
221
|
+
outbuf = String.new
|
222
|
+
read_data(io, outbuf)
|
223
|
+
|
224
|
+
loop do
|
225
|
+
status =
|
226
|
+
case @state
|
227
|
+
when :FAST_FORWARD
|
228
|
+
handle_fast_forward
|
229
|
+
when :CONSUME_TOKEN
|
230
|
+
handle_consume_token
|
231
|
+
when :MIME_HEAD
|
232
|
+
handle_mime_head
|
233
|
+
when :MIME_BODY
|
234
|
+
handle_mime_body
|
235
|
+
else # when :DONE
|
236
|
+
return
|
237
|
+
end
|
238
|
+
|
239
|
+
read_data(io, outbuf) if status == :want_read
|
240
|
+
end
|
189
241
|
end
|
190
242
|
|
191
243
|
def result
|
192
244
|
@collector.each do |part|
|
193
245
|
part.get_data do |data|
|
194
246
|
tag_multipart_encoding(part.filename, part.content_type, part.name, data)
|
195
|
-
@query_parser.normalize_params(@params, part.name, data
|
247
|
+
@query_parser.normalize_params(@params, part.name, data)
|
196
248
|
end
|
197
249
|
end
|
198
250
|
MultipartInfo.new @params.to_params_hash, @collector.find_all(&:file?).map(&:body)
|
@@ -200,29 +252,38 @@ module Rack
|
|
200
252
|
|
201
253
|
private
|
202
254
|
|
203
|
-
def
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
break if handle_mime_body == :want_read
|
214
|
-
when :DONE
|
215
|
-
break
|
216
|
-
end
|
217
|
-
end
|
255
|
+
def dequote(str) # From WEBrick::HTTPUtils
|
256
|
+
ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
|
257
|
+
ret.gsub!(/\\(.)/, "\\1")
|
258
|
+
ret
|
259
|
+
end
|
260
|
+
|
261
|
+
def read_data(io, outbuf)
|
262
|
+
content = io.read(@bufsize, outbuf)
|
263
|
+
handle_empty_content!(content)
|
264
|
+
@sbuf.concat(content)
|
218
265
|
end
|
219
266
|
|
267
|
+
# This handles the initial parser state. We read until we find the starting
|
268
|
+
# boundary, then we can transition to the next state. If we find the ending
|
269
|
+
# boundary, this is an invalid multipart upload, but keep scanning for opening
|
270
|
+
# boundary in that case. If no boundary found, we need to keep reading data
|
271
|
+
# and retry. It's highly unlikely the initial read will not consume the
|
272
|
+
# boundary. The client would have to deliberately craft a response
|
273
|
+
# with the opening boundary beyond the buffer size for that to happen.
|
220
274
|
def handle_fast_forward
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
275
|
+
while true
|
276
|
+
case consume_boundary
|
277
|
+
when :BOUNDARY
|
278
|
+
# found opening boundary, transition to next state
|
279
|
+
@state = :MIME_HEAD
|
280
|
+
return
|
281
|
+
when :END_BOUNDARY
|
282
|
+
# invalid multipart upload, but retry for opening boundary
|
283
|
+
else
|
284
|
+
# no boundary found, keep reading data
|
285
|
+
return :want_read
|
286
|
+
end
|
226
287
|
end
|
227
288
|
end
|
228
289
|
|
@@ -241,7 +302,7 @@ module Rack
|
|
241
302
|
head = @sbuf[1]
|
242
303
|
content_type = head[MULTIPART_CONTENT_TYPE, 1]
|
243
304
|
if name = head[MULTIPART_CONTENT_DISPOSITION, 1]
|
244
|
-
name =
|
305
|
+
name = dequote(name)
|
245
306
|
else
|
246
307
|
name = head[MULTIPART_CONTENT_ID, 1]
|
247
308
|
end
|
@@ -278,15 +339,16 @@ module Rack
|
|
278
339
|
end
|
279
340
|
end
|
280
341
|
|
281
|
-
|
282
|
-
|
342
|
+
# Scan until the we find the start or end of the boundary.
|
343
|
+
# If we find it, return the appropriate symbol for the start or
|
344
|
+
# end of the boundary. If we don't find the start or end of the
|
345
|
+
# boundary, clear the buffer and return nil.
|
283
346
|
def consume_boundary
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
return if @sbuf.eos?
|
347
|
+
if read_buffer = @sbuf.scan_until(@body_regex)
|
348
|
+
read_buffer.end_with?(EOL) ? :BOUNDARY : :END_BOUNDARY
|
349
|
+
else
|
350
|
+
@sbuf.terminate
|
351
|
+
nil
|
290
352
|
end
|
291
353
|
end
|
292
354
|
|
@@ -296,10 +358,10 @@ module Rack
|
|
296
358
|
when RFC2183
|
297
359
|
params = Hash[*head.scan(DISPPARM).flat_map(&:compact)]
|
298
360
|
|
299
|
-
if filename = params['filename']
|
300
|
-
filename = $1 if filename =~ /^"(.*)"$/
|
301
|
-
elsif filename = params['filename*']
|
361
|
+
if filename = params['filename*']
|
302
362
|
encoding, _, filename = filename.split("'", 3)
|
363
|
+
elsif filename = params['filename']
|
364
|
+
filename = $1 if filename =~ /^"(.*)"$/
|
303
365
|
end
|
304
366
|
when BROKEN
|
305
367
|
filename = $1
|
@@ -326,6 +388,7 @@ module Rack
|
|
326
388
|
end
|
327
389
|
|
328
390
|
CHARSET = "charset"
|
391
|
+
deprecate_constant :CHARSET
|
329
392
|
|
330
393
|
def tag_multipart_encoding(filename, content_type, name, body)
|
331
394
|
name = name.to_s
|
@@ -346,7 +409,13 @@ module Rack
|
|
346
409
|
k.strip!
|
347
410
|
v.strip!
|
348
411
|
v = v[1..-2] if v.start_with?('"') && v.end_with?('"')
|
349
|
-
|
412
|
+
if k == "charset"
|
413
|
+
encoding = begin
|
414
|
+
Encoding.find v
|
415
|
+
rescue ArgumentError
|
416
|
+
Encoding::BINARY
|
417
|
+
end
|
418
|
+
end
|
350
419
|
end
|
351
420
|
end
|
352
421
|
end
|
@@ -357,7 +426,7 @@ module Rack
|
|
357
426
|
|
358
427
|
def handle_empty_content!(content)
|
359
428
|
if content.nil? || content.empty?
|
360
|
-
raise
|
429
|
+
raise EmptyContentError
|
361
430
|
end
|
362
431
|
end
|
363
432
|
end
|
data/lib/rack/multipart.rb
CHANGED
@@ -1,64 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'constants'
|
4
|
+
require_relative 'utils'
|
5
|
+
|
3
6
|
require_relative 'multipart/parser'
|
7
|
+
require_relative 'multipart/generator'
|
4
8
|
|
5
9
|
module Rack
|
6
10
|
# A multipart form data parser, adapted from IOWA.
|
7
11
|
#
|
8
12
|
# Usually, Rack::Request#POST takes care of calling this.
|
9
13
|
module Multipart
|
10
|
-
autoload :UploadedFile, 'rack/multipart/uploaded_file'
|
11
|
-
autoload :Generator, 'rack/multipart/generator'
|
12
|
-
|
13
|
-
EOL = "\r\n"
|
14
14
|
MULTIPART_BOUNDARY = "AaB03x"
|
15
|
-
MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni
|
16
|
-
TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/
|
17
|
-
CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i
|
18
|
-
VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/
|
19
|
-
BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i
|
20
|
-
MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni
|
21
|
-
MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni
|
22
|
-
MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni
|
23
|
-
# Updated definitions from RFC 2231
|
24
|
-
ATTRIBUTE_CHAR = %r{[^ \t\v\n\r)(><@,;:\\"/\[\]?='*%]}
|
25
|
-
ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/
|
26
|
-
SECTION = /\*[0-9]+/
|
27
|
-
REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/
|
28
|
-
REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/
|
29
|
-
EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/
|
30
|
-
EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/
|
31
|
-
EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/
|
32
|
-
EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/
|
33
|
-
EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/
|
34
|
-
EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/
|
35
|
-
EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/
|
36
|
-
DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/
|
37
|
-
RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i
|
38
15
|
|
39
16
|
class << self
|
40
17
|
def parse_multipart(env, params = Rack::Utils.default_query_parser)
|
41
|
-
|
42
|
-
|
18
|
+
io = env[RACK_INPUT]
|
19
|
+
|
20
|
+
if content_length = env['CONTENT_LENGTH']
|
21
|
+
content_length = content_length.to_i
|
22
|
+
end
|
43
23
|
|
44
|
-
|
45
|
-
io = req.get_header(RACK_INPUT)
|
46
|
-
io.rewind
|
47
|
-
content_length = req.content_length
|
48
|
-
content_length = content_length.to_i if content_length
|
24
|
+
content_type = env['CONTENT_TYPE']
|
49
25
|
|
50
|
-
tempfile =
|
51
|
-
bufsize =
|
26
|
+
tempfile = env[RACK_MULTIPART_TEMPFILE_FACTORY] || Parser::TEMPFILE_FACTORY
|
27
|
+
bufsize = env[RACK_MULTIPART_BUFFER_SIZE] || Parser::BUFSIZE
|
52
28
|
|
53
|
-
info = Parser.parse
|
54
|
-
|
55
|
-
|
29
|
+
info = Parser.parse(io, content_length, content_type, tempfile, bufsize, params)
|
30
|
+
env[RACK_TEMPFILES] = info.tmp_files
|
31
|
+
|
32
|
+
return info.params
|
33
|
+
end
|
34
|
+
|
35
|
+
def extract_multipart(request, params = Rack::Utils.default_query_parser)
|
36
|
+
parse_multipart(request.env)
|
56
37
|
end
|
57
38
|
|
58
39
|
def build_multipart(params, first = true)
|
59
40
|
Generator.new(params, first).dump
|
60
41
|
end
|
61
42
|
end
|
62
|
-
|
63
43
|
end
|
64
44
|
end
|
data/lib/rack/null_logger.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'constants'
|
4
|
+
|
3
5
|
module Rack
|
4
6
|
class NullLogger
|
5
7
|
def initialize(app)
|
@@ -22,6 +24,11 @@ module Rack
|
|
22
24
|
def warn? ; end
|
23
25
|
def error? ; end
|
24
26
|
def fatal? ; end
|
27
|
+
def debug! ; end
|
28
|
+
def error! ; end
|
29
|
+
def fatal! ; end
|
30
|
+
def info! ; end
|
31
|
+
def warn! ; end
|
25
32
|
def level ; end
|
26
33
|
def progname ; end
|
27
34
|
def datetime_format ; end
|
@@ -34,6 +41,8 @@ module Rack
|
|
34
41
|
def sev_threshold=(sev_threshold); end
|
35
42
|
def close ; end
|
36
43
|
def add(severity, message = nil, progname = nil, &block); end
|
44
|
+
def log(severity, message = nil, progname = nil, &block); end
|
37
45
|
def <<(msg); end
|
46
|
+
def reopen(logdev = nil); end
|
38
47
|
end
|
39
48
|
end
|