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 154 154: def self.parse_multipart(env) 155: unless env['CONTENT_TYPE'] =~ 156: %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n 157: nil 158: else 159: boundary = "--#{$1}" 160: 161: params = {} 162: buf = "" 163: content_length = env['CONTENT_LENGTH'].to_i 164: input = env['rack.input'] 165: 166: boundary_size = boundary.size + EOL.size 167: bufsize = 16384 168: 169: content_length -= boundary_size 170: 171: status = input.read(boundary_size) 172: raise EOFError, "bad content body" unless status == boundary + EOL 173: 174: rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/ 175: 176: loop { 177: head = nil 178: body = '' 179: filename = content_type = name = nil 180: 181: until head && buf =~ rx 182: if !head && i = buf.index("\r\n\r\n") 183: head = buf.slice!(0, i+2) # First \r\n 184: buf.slice!(0, 2) # Second \r\n 185: 186: filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] 187: content_type = head[/Content-Type: (.*)\r\n/ni, 1] 188: name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1] 189: 190: body = Tempfile.new("RackMultipart") if filename 191: 192: next 193: end 194: 195: # Save the read body part. 196: if head && (boundary_size+4 < buf.size) 197: body << buf.slice!(0, buf.size - (boundary_size+4)) 198: end 199: 200: c = input.read(bufsize < content_length ? bufsize : content_length) 201: raise EOFError, "bad content body" if c.nil? || c.empty? 202: buf << c 203: content_length -= c.size 204: end 205: 206: # Save the rest. 207: if i = buf.index(rx) 208: body << buf.slice!(0, i) 209: buf.slice!(0, boundary_size+2) 210: 211: content_length = -1 if $1 == "--" 212: end 213: 214: if filename 215: body.rewind 216: data = {:filename => filename, :type => content_type, 217: :name => name, :tempfile => body, :head => head} 218: else 219: data = body 220: end 221: 222: if name 223: if name =~ /\[\]\z/ 224: params[name] ||= [] 225: params[name] << data 226: else 227: params[name] = data 228: end 229: end 230: 231: break if buf.empty? || content_length == -1 232: } 233: 234: params 235: end 236: end