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 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

[Validate]