Module | Rack::Utils::Multipart |
In: |
lib/rack/utils.rb
|
A multipart form data parser, adapted from IOWA.
Usually, Rack::Request#POST takes care of calling this.
EOL | = | "\r\n" |
# File lib/rack/utils.rb, line 259 259: def self.parse_multipart(env) 260: unless env['CONTENT_TYPE'] =~ 261: %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n 262: nil 263: else 264: boundary = "--#{$1}" 265: 266: params = {} 267: buf = "" 268: content_length = env['CONTENT_LENGTH'].to_i 269: input = env['rack.input'] 270: 271: boundary_size = boundary.size + EOL.size 272: bufsize = 16384 273: 274: content_length -= boundary_size 275: 276: status = input.read(boundary_size) 277: raise EOFError, "bad content body" unless status == boundary + EOL 278: 279: rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/ 280: 281: loop { 282: head = nil 283: body = '' 284: filename = content_type = name = nil 285: 286: until head && buf =~ rx 287: if !head && i = buf.index("\r\n\r\n") 288: head = buf.slice!(0, i+2) # First \r\n 289: buf.slice!(0, 2) # Second \r\n 290: 291: filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] 292: content_type = head[/Content-Type: (.*)\r\n/ni, 1] 293: name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1] 294: 295: if filename 296: body = Tempfile.new("RackMultipart") 297: body.binmode if body.respond_to?(:binmode) 298: end 299: 300: next 301: end 302: 303: # Save the read body part. 304: if head && (boundary_size+4 < buf.size) 305: body << buf.slice!(0, buf.size - (boundary_size+4)) 306: end 307: 308: c = input.read(bufsize < content_length ? bufsize : content_length) 309: raise EOFError, "bad content body" if c.nil? || c.empty? 310: buf << c 311: content_length -= c.size 312: end 313: 314: # Save the rest. 315: if i = buf.index(rx) 316: body << buf.slice!(0, i) 317: buf.slice!(0, boundary_size+2) 318: 319: content_length = -1 if $1 == "--" 320: end 321: 322: if filename 323: body.rewind 324: data = {:filename => filename, :type => content_type, 325: :name => name, :tempfile => body, :head => head} 326: else 327: data = body 328: end 329: 330: if name 331: if name =~ /\[\]\z/ 332: params[name] ||= [] 333: params[name] << data 334: else 335: params[name] = data 336: end 337: end 338: 339: break if buf.empty? || content_length == -1 340: } 341: 342: params 343: end 344: end