rack 2.2.8 → 3.0.0.beta1

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.

Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +138 -89
  3. data/CONTRIBUTING.md +53 -47
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +287 -0
  6. data/Rakefile +40 -7
  7. data/SPEC.rdoc +166 -125
  8. data/contrib/LICENSE.md +7 -0
  9. data/contrib/logo.webp +0 -0
  10. data/lib/rack/auth/abstract/handler.rb +3 -1
  11. data/lib/rack/auth/abstract/request.rb +3 -1
  12. data/lib/rack/auth/digest/md5.rb +1 -131
  13. data/lib/rack/auth/digest/nonce.rb +1 -54
  14. data/lib/rack/auth/digest/params.rb +1 -54
  15. data/lib/rack/auth/digest/request.rb +1 -43
  16. data/lib/rack/auth/digest.rb +256 -0
  17. data/lib/rack/body_proxy.rb +3 -1
  18. data/lib/rack/builder.rb +60 -42
  19. data/lib/rack/cascade.rb +2 -0
  20. data/lib/rack/chunked.rb +16 -13
  21. data/lib/rack/common_logger.rb +23 -18
  22. data/lib/rack/conditional_get.rb +18 -15
  23. data/lib/rack/constants.rb +62 -0
  24. data/lib/rack/content_length.rb +12 -16
  25. data/lib/rack/content_type.rb +8 -5
  26. data/lib/rack/deflater.rb +40 -26
  27. data/lib/rack/directory.rb +9 -3
  28. data/lib/rack/etag.rb +14 -23
  29. data/lib/rack/events.rb +4 -0
  30. data/lib/rack/file.rb +2 -0
  31. data/lib/rack/files.rb +15 -17
  32. data/lib/rack/head.rb +9 -8
  33. data/lib/rack/headers.rb +154 -0
  34. data/lib/rack/lint.rb +740 -649
  35. data/lib/rack/lock.rb +2 -5
  36. data/lib/rack/logger.rb +2 -0
  37. data/lib/rack/media_type.rb +1 -1
  38. data/lib/rack/method_override.rb +5 -1
  39. data/lib/rack/mime.rb +8 -0
  40. data/lib/rack/mock.rb +1 -271
  41. data/lib/rack/mock_request.rb +166 -0
  42. data/lib/rack/mock_response.rb +124 -0
  43. data/lib/rack/multipart/generator.rb +7 -5
  44. data/lib/rack/multipart/parser.rb +123 -79
  45. data/lib/rack/multipart/uploaded_file.rb +4 -0
  46. data/lib/rack/multipart.rb +20 -40
  47. data/lib/rack/null_logger.rb +9 -0
  48. data/lib/rack/query_parser.rb +76 -44
  49. data/lib/rack/recursive.rb +2 -0
  50. data/lib/rack/reloader.rb +0 -2
  51. data/lib/rack/request.rb +189 -91
  52. data/lib/rack/response.rb +131 -61
  53. data/lib/rack/rewindable_input.rb +24 -5
  54. data/lib/rack/runtime.rb +7 -6
  55. data/lib/rack/sendfile.rb +30 -25
  56. data/lib/rack/show_exceptions.rb +15 -2
  57. data/lib/rack/show_status.rb +17 -7
  58. data/lib/rack/static.rb +8 -8
  59. data/lib/rack/tempfile_reaper.rb +15 -4
  60. data/lib/rack/urlmap.rb +4 -2
  61. data/lib/rack/utils.rb +208 -194
  62. data/lib/rack/version.rb +9 -4
  63. data/lib/rack.rb +5 -76
  64. data/rack.gemspec +6 -6
  65. metadata +19 -31
  66. data/README.rdoc +0 -320
  67. data/bin/rackup +0 -5
  68. data/contrib/rack.png +0 -0
  69. data/contrib/rack.svg +0 -150
  70. data/contrib/rack_logo.svg +0 -164
  71. data/lib/rack/core_ext/regexp.rb +0 -14
  72. data/lib/rack/handler/cgi.rb +0 -59
  73. data/lib/rack/handler/fastcgi.rb +0 -100
  74. data/lib/rack/handler/lsws.rb +0 -61
  75. data/lib/rack/handler/scgi.rb +0 -71
  76. data/lib/rack/handler/thin.rb +0 -36
  77. data/lib/rack/handler/webrick.rb +0 -129
  78. data/lib/rack/handler.rb +0 -104
  79. data/lib/rack/lobster.rb +0 -70
  80. data/lib/rack/server.rb +0 -466
  81. data/lib/rack/session/abstract/id.rb +0 -523
  82. data/lib/rack/session/cookie.rb +0 -204
  83. data/lib/rack/session/memcache.rb +0 -10
  84. data/lib/rack/session/pool.rb +0 -85
@@ -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.escape(file.original_filename)}\"" if file.original_filename
79
+ filename = "; filename=\"#{Utils.escape_path(file.original_filename)}\""
78
80
  <<-EOF
79
81
  --#{MULTIPART_BOUNDARY}\r
80
- Content-Disposition: form-data; name="#{name}"#{filename}\r
81
- Content-Type: #{file.content_type}\r
82
- #{"Content-Length: #{length}\r\n" if length}\r
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
- Content-Disposition: form-data; name="#{name}"\r
92
+ content-disposition: form-data; name="#{name}"\r
91
93
  \r
92
94
  #{file}\r
93
95
  EOF
@@ -2,24 +2,52 @@
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
- class MultipartTotalPartLimitError < StandardError; end
9
10
 
10
- class Parser
11
- (require_relative '../core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
11
+ # Use specific error class when parsing multipart request
12
+ # that ends early.
13
+ class EmptyContentError < ::EOFError; end
14
+
15
+ # Base class for multipart exceptions that do not subclass from
16
+ # other exception classes for backwards compatibility.
17
+ class Error < StandardError; end
18
+
19
+ EOL = "\r\n"
20
+ MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni
21
+ TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/
22
+ CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i
23
+ VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/
24
+ BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i
25
+ MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni
26
+ MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni
27
+ MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni
28
+ # Updated definitions from RFC 2231
29
+ ATTRIBUTE_CHAR = %r{[^ \t\v\n\r)(><@,;:\\"/\[\]?='*%]}
30
+ ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/
31
+ SECTION = /\*[0-9]+/
32
+ REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/
33
+ REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/
34
+ EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/
35
+ EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/
36
+ EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/
37
+ EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/
38
+ EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/
39
+ EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/
40
+ EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/
41
+ DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/
42
+ RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i
12
43
 
44
+ class Parser
13
45
  BUFSIZE = 1_048_576
14
46
  TEXT_PLAIN = "text/plain"
15
47
  TEMPFILE_FACTORY = lambda { |filename, content_type|
16
- extension = ::File.extname(filename.gsub("\0", '%00'))[0, 129]
17
-
18
- Tempfile.new(["RackMultipart", extension])
48
+ Tempfile.new(["RackMultipart", ::File.extname(filename.gsub("\0", '%00'))])
19
49
  }
20
50
 
21
- BOUNDARY_REGEX = /\A([^\n]*(?:\n|\Z))/
22
-
23
51
  class BoundedIO # :nodoc:
24
52
  def initialize(io, content_length)
25
53
  @io = io
@@ -41,16 +69,12 @@ module Rack
41
69
  if str
42
70
  @cursor += str.bytesize
43
71
  else
44
- # Raise an error for mismatching Content-Length and actual contents
72
+ # Raise an error for mismatching content-length and actual contents
45
73
  raise EOFError, "bad content body"
46
74
  end
47
75
 
48
76
  str
49
77
  end
50
-
51
- def rewind
52
- @io.rewind
53
- end
54
78
  end
55
79
 
56
80
  MultipartInfo = Struct.new :params, :tmp_files
@@ -69,18 +93,17 @@ module Rack
69
93
  boundary = parse_boundary content_type
70
94
  return EMPTY unless boundary
71
95
 
96
+ if boundary.length > 70
97
+ # RFC 1521 Section 7.2.1 imposes a 70 character maximum for the boundary.
98
+ # Most clients use no more than 55 characters.
99
+ raise Error, "multipart boundary size too large (#{boundary.length} characters)"
100
+ end
101
+
72
102
  io = BoundedIO.new(io, content_length) if content_length
73
- outbuf = String.new
74
103
 
75
104
  parser = new(boundary, tmpfile, bufsize, qp)
76
- parser.on_read io.read(bufsize, outbuf)
105
+ parser.parse(io)
77
106
 
78
- loop do
79
- break if parser.state == :DONE
80
- parser.on_read io.read(bufsize, outbuf)
81
- end
82
-
83
- io.rewind
84
107
  parser.result
85
108
  end
86
109
 
@@ -143,7 +166,7 @@ module Rack
143
166
 
144
167
  @mime_parts[mime_index] = klass.new(body, head, filename, content_type, name)
145
168
 
146
- check_part_limits
169
+ check_open_files
147
170
  end
148
171
 
149
172
  def on_mime_body(mime_index, content)
@@ -155,23 +178,13 @@ module Rack
155
178
 
156
179
  private
157
180
 
158
- def check_part_limits
159
- file_limit = Utils.multipart_file_limit
160
- part_limit = Utils.multipart_total_part_limit
161
-
162
- if file_limit && file_limit > 0
163
- if @open_files >= file_limit
181
+ def check_open_files
182
+ if Utils.multipart_part_limit > 0
183
+ if @open_files >= Utils.multipart_part_limit
164
184
  @mime_parts.each(&:close)
165
185
  raise MultipartPartLimitError, 'Maximum file multiparts in content reached'
166
186
  end
167
187
  end
168
-
169
- if part_limit && part_limit > 0
170
- if @mime_parts.size >= part_limit
171
- @mime_parts.each(&:close)
172
- raise MultipartTotalPartLimitError, 'Maximum total multiparts in content reached'
173
- end
174
- end
175
188
  end
176
189
  end
177
190
 
@@ -180,32 +193,46 @@ module Rack
180
193
  def initialize(boundary, tempfile, bufsize, query_parser)
181
194
  @query_parser = query_parser
182
195
  @params = query_parser.make_params
183
- @boundary = "--#{boundary}"
184
196
  @bufsize = bufsize
185
197
 
186
- @full_boundary = @boundary
187
- @end_boundary = @boundary + '--'
188
198
  @state = :FAST_FORWARD
189
199
  @mime_index = 0
190
200
  @collector = Collector.new tempfile
191
201
 
192
202
  @sbuf = StringScanner.new("".dup)
193
- @body_regex = /(?:#{EOL})?#{Regexp.quote(@boundary)}(?:#{EOL}|--)/m
194
- @rx_max_size = EOL.size + @boundary.bytesize + [EOL.size, '--'.size].max
203
+ @body_regex = /(?:#{EOL}|\A)--#{Regexp.quote(boundary)}(?:#{EOL}|--)/m
204
+ @rx_max_size = boundary.bytesize + 6 # (\r\n-- at start, either \r\n or -- at finish)
195
205
  @head_regex = /(.*?#{EOL})#{EOL}/m
196
206
  end
197
207
 
198
- def on_read(content)
199
- handle_empty_content!(content)
200
- @sbuf.concat content
201
- run_parser
208
+ def parse(io)
209
+ outbuf = String.new
210
+ read_data(io, outbuf)
211
+
212
+ loop do
213
+ status =
214
+ case @state
215
+ when :FAST_FORWARD
216
+ handle_fast_forward
217
+ when :CONSUME_TOKEN
218
+ handle_consume_token
219
+ when :MIME_HEAD
220
+ handle_mime_head
221
+ when :MIME_BODY
222
+ handle_mime_body
223
+ else # when :DONE
224
+ return
225
+ end
226
+
227
+ read_data(io, outbuf) if status == :want_read
228
+ end
202
229
  end
203
230
 
204
231
  def result
205
232
  @collector.each do |part|
206
233
  part.get_data do |data|
207
234
  tag_multipart_encoding(part.filename, part.content_type, part.name, data)
208
- @query_parser.normalize_params(@params, part.name, data, @query_parser.param_depth_limit)
235
+ @query_parser.normalize_params(@params, part.name, data)
209
236
  end
210
237
  end
211
238
  MultipartInfo.new @params.to_params_hash, @collector.find_all(&:file?).map(&:body)
@@ -213,29 +240,38 @@ module Rack
213
240
 
214
241
  private
215
242
 
216
- def run_parser
217
- loop do
218
- case @state
219
- when :FAST_FORWARD
220
- break if handle_fast_forward == :want_read
221
- when :CONSUME_TOKEN
222
- break if handle_consume_token == :want_read
223
- when :MIME_HEAD
224
- break if handle_mime_head == :want_read
225
- when :MIME_BODY
226
- break if handle_mime_body == :want_read
227
- when :DONE
228
- break
229
- end
230
- end
243
+ def dequote(str) # From WEBrick::HTTPUtils
244
+ ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
245
+ ret.gsub!(/\\(.)/, "\\1")
246
+ ret
247
+ end
248
+
249
+ def read_data(io, outbuf)
250
+ content = io.read(@bufsize, outbuf)
251
+ handle_empty_content!(content)
252
+ @sbuf.concat(content)
231
253
  end
232
254
 
255
+ # This handles the initial parser state. We read until we find the starting
256
+ # boundary, then we can transition to the next state. If we find the ending
257
+ # boundary, this is an invalid multipart upload, but keep scanning for opening
258
+ # boundary in that case. If no boundary found, we need to keep reading data
259
+ # and retry. It's highly unlikely the initial read will not consume the
260
+ # boundary. The client would have to deliberately craft a response
261
+ # with the opening boundary beyond the buffer size for that to happen.
233
262
  def handle_fast_forward
234
- if consume_boundary
235
- @state = :MIME_HEAD
236
- else
237
- raise EOFError, "bad content body" if @sbuf.rest_size >= @bufsize
238
- :want_read
263
+ while true
264
+ case consume_boundary
265
+ when :BOUNDARY
266
+ # found opening boundary, transition to next state
267
+ @state = :MIME_HEAD
268
+ return
269
+ when :END_BOUNDARY
270
+ # invalid multipart upload, but retry for opening boundary
271
+ else
272
+ # no boundary found, keep reading data
273
+ return :want_read
274
+ end
239
275
  end
240
276
  end
241
277
 
@@ -254,7 +290,7 @@ module Rack
254
290
  head = @sbuf[1]
255
291
  content_type = head[MULTIPART_CONTENT_TYPE, 1]
256
292
  if name = head[MULTIPART_CONTENT_DISPOSITION, 1]
257
- name = Rack::Auth::Digest::Params::dequote(name)
293
+ name = dequote(name)
258
294
  else
259
295
  name = head[MULTIPART_CONTENT_ID, 1]
260
296
  end
@@ -291,15 +327,16 @@ module Rack
291
327
  end
292
328
  end
293
329
 
294
- def full_boundary; @full_boundary; end
295
-
330
+ # Scan until the we find the start or end of the boundary.
331
+ # If we find it, return the appropriate symbol for the start or
332
+ # end of the boundary. If we don't find the start or end of the
333
+ # boundary, clear the buffer and return nil.
296
334
  def consume_boundary
297
- while read_buffer = @sbuf.scan_until(BOUNDARY_REGEX)
298
- case read_buffer.strip
299
- when full_boundary then return :BOUNDARY
300
- when @end_boundary then return :END_BOUNDARY
301
- end
302
- return if @sbuf.eos?
335
+ if read_buffer = @sbuf.scan_until(@body_regex)
336
+ read_buffer.end_with?(EOL) ? :BOUNDARY : :END_BOUNDARY
337
+ else
338
+ @sbuf.terminate
339
+ nil
303
340
  end
304
341
  end
305
342
 
@@ -309,10 +346,10 @@ module Rack
309
346
  when RFC2183
310
347
  params = Hash[*head.scan(DISPPARM).flat_map(&:compact)]
311
348
 
312
- if filename = params['filename']
313
- filename = $1 if filename =~ /^"(.*)"$/
314
- elsif filename = params['filename*']
349
+ if filename = params['filename*']
315
350
  encoding, _, filename = filename.split("'", 3)
351
+ elsif filename = params['filename']
352
+ filename = $1 if filename =~ /^"(.*)"$/
316
353
  end
317
354
  when BROKEN
318
355
  filename = $1
@@ -339,6 +376,7 @@ module Rack
339
376
  end
340
377
 
341
378
  CHARSET = "charset"
379
+ deprecate_constant :CHARSET
342
380
 
343
381
  def tag_multipart_encoding(filename, content_type, name, body)
344
382
  name = name.to_s
@@ -359,7 +397,13 @@ module Rack
359
397
  k.strip!
360
398
  v.strip!
361
399
  v = v[1..-2] if v.start_with?('"') && v.end_with?('"')
362
- encoding = Encoding.find v if k == CHARSET
400
+ if k == "charset"
401
+ encoding = begin
402
+ Encoding.find v
403
+ rescue ArgumentError
404
+ Encoding::BINARY
405
+ end
406
+ end
363
407
  end
364
408
  end
365
409
  end
@@ -370,7 +414,7 @@ module Rack
370
414
 
371
415
  def handle_empty_content!(content)
372
416
  if content.nil? || content.empty?
373
- raise EOFError
417
+ raise EmptyContentError
374
418
  end
375
419
  end
376
420
  end
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tempfile'
4
+ require 'fileutils'
5
+
3
6
  module Rack
4
7
  module Multipart
5
8
  class UploadedFile
9
+
6
10
  # The filename, *not* including the path, of the "uploaded" file
7
11
  attr_reader :original_filename
8
12
 
@@ -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{[^ \x00-\x1f\x7f)(><@,;:\\"/\[\]?='*%]}
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
- extract_multipart Rack::Request.new(env), params
42
- end
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
- def extract_multipart(req, params = Rack::Utils.default_query_parser)
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 = req.get_header(RACK_MULTIPART_TEMPFILE_FACTORY) || Parser::TEMPFILE_FACTORY
51
- bufsize = req.get_header(RACK_MULTIPART_BUFFER_SIZE) || Parser::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 io, content_length, req.get_header('CONTENT_TYPE'), tempfile, bufsize, params
54
- req.set_header(RACK_TEMPFILES, info.tmp_files)
55
- info.params
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
@@ -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