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.

Methods

Constants

EOL = "\r\n"

Public Class methods

[Source]

     # 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

[Validate]