Multipart

A multipart form data parser, adapted from IOWA.

Usually, Rack::Request#POST takes care of calling this.

Constants

EOL
(Not documented)

Public Class Methods

parse_multipart(env) click to toggle source

(Not documented)

     # File lib/rack/utils.rb, line 298
298:       def self.parse_multipart(env)
299:         unless env['CONTENT_TYPE'] =~
300:             %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
301:           nil
302:         else
303:           boundary = "--#{$1}"
304: 
305:           params = {}
306:           buf = ""
307:           content_length = env['CONTENT_LENGTH'].to_i
308:           input = env['rack.input']
309:           input.rewind
310: 
311:           boundary_size = Utils.bytesize(boundary) + EOL.size
312:           bufsize = 16384
313: 
314:           content_length -= boundary_size
315: 
316:           read_buffer = ''
317: 
318:           status = input.read(boundary_size, read_buffer)
319:           raise EOFError, "bad content body"  unless status == boundary + EOL
320: 
321:           rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n
322: 
323:           loop {
324:             head = nil
325:             body = ''
326:             filename = content_type = name = nil
327: 
328:             until head && buf =~ rx
329:               if !head && i = buf.index(EOL+EOL)
330:                 head = buf.slice!(0, i+2) # First \r\n
331:                 buf.slice!(0, 2)          # Second \r\n
332: 
333:                 filename = head[/Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/ni, 1]
334:                 content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
335:                 name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
336: 
337:                 if content_type || filename
338:                   body = Tempfile.new("RackMultipart")
339:                   body.binmode  if body.respond_to?(:binmode)
340:                 end
341: 
342:                 next
343:               end
344: 
345:               # Save the read body part.
346:               if head && (boundary_size+4 < buf.size)
347:                 body << buf.slice!(0, buf.size - (boundary_size+4))
348:               end
349: 
350:               c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer)
351:               raise EOFError, "bad content body"  if c.nil? || c.empty?
352:               buf << c
353:               content_length -= c.size
354:             end
355: 
356:             # Save the rest.
357:             if i = buf.index(rx)
358:               body << buf.slice!(0, i)
359:               buf.slice!(0, boundary_size+2)
360: 
361:               content_length = -1  if $1 == "--"
362:             end
363: 
364:             if filename == ""
365:               # filename is blank which means no file has been selected
366:               data = nil
367:             elsif filename
368:               body.rewind
369: 
370:               # Take the basename of the upload's original filename.
371:               # This handles the full Windows paths given by Internet Explorer
372:               # (and perhaps other broken user agents) without affecting
373:               # those which give the lone filename.
374:               filename =~ /^(?:.*[:\\\/])?(.*)/m
375:               filename = $1
376: 
377:               data = {:filename => filename, :type => content_type,
378:                       :name => name, :tempfile => body, :head => head}
379:             elsif !filename && content_type
380:               body.rewind
381:               
382:               # Generic multipart cases, not coming from a form
383:               data = {:type => content_type,
384:                       :name => name, :tempfile => body, :head => head}
385:             else
386:               data = body
387:             end
388: 
389:             Utils.normalize_params(params, name, data) unless data.nil?
390: 
391:             break  if buf.empty? || content_length == -1
392:           }
393: 
394:           input.rewind
395: 
396:           params
397:         end
398:       end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.