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 91 91: def self.parse_multipart(env) 92: unless env['CONTENT_TYPE'] =~ 93: %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n 94: nil 95: else 96: boundary = "--#{$1}" 97: 98: params = {} 99: buf = "" 100: content_length = env['CONTENT_LENGTH'].to_i 101: input = env['rack.input'] 102: 103: boundary_size = boundary.size + EOL.size 104: bufsize = 16384 105: 106: content_length -= boundary_size 107: 108: status = input.read(boundary_size) 109: raise EOFError, "bad content body" unless status == boundary + EOL 110: 111: rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/ 112: 113: loop { 114: head = nil 115: body = '' 116: filename = content_type = name = nil 117: 118: until head && buf =~ rx 119: if !head && i = buf.index("\r\n\r\n") 120: head = buf.slice!(0, i+2) # First \r\n 121: buf.slice!(0, 2) # Second \r\n 122: 123: filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] 124: content_type = head[/Content-Type: (.*)\r\n/ni, 1] 125: name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1] 126: 127: body = Tempfile.new("RackMultipart") if filename 128: 129: next 130: end 131: 132: # Save the read body part. 133: if head && (boundary_size+4 < buf.size) 134: body << buf.slice!(0, buf.size - (boundary_size+4)) 135: end 136: 137: c = input.read(bufsize < content_length ? bufsize : content_length) 138: raise EOFError, "bad content body" if c.nil? || c.empty? 139: buf << c 140: content_length -= c.size 141: end 142: 143: # Save the rest. 144: if i = buf.index(rx) 145: body << buf.slice!(0, i) 146: buf.slice!(0, boundary_size+2) 147: 148: content_length = -1 if $1 == "--" 149: end 150: 151: if filename 152: body.rewind 153: data = {:filename => filename, :type => content_type, 154: :name => name, :tempfile => body, :head => head} 155: else 156: data = body 157: end 158: 159: if name 160: if name =~ /\[\]\z/ 161: params[name] ||= [] 162: params[name] << data 163: else 164: params[name] = data 165: end 166: end 167: 168: break if buf.empty? || content_length == -1 169: } 170: 171: params 172: end 173: end