lib/tap/http/utils.rb in tap-http-0.3.1 vs lib/tap/http/utils.rb in tap-http-0.3.2

- old
+ new

@@ -1,8 +1,9 @@ autoload(:WEBrick, 'webrick') autoload(:Zlib, 'zlib') autoload(:StringIO, 'stringio') +require 'rack' module Tap module Http module Utils module_function @@ -135,14 +136,15 @@ params = {} request.params.each_pair do |key, value| params[key] = each_member(value) do |obj| if obj.kind_of?(Hash) - file = {'Content-Type' => value[:type], 'Filename' => value[:filename]} - file['Content'] = value[:tempfile].read if keep_content + file = {'Content-Type' => obj[:type], 'Filename' => obj[:filename]} + file['Content'] = obj[:tempfile].read if keep_content file - else value + else + obj end end end { @@ -204,9 +206,102 @@ #-- # Utils.inflate(res.body) if res['content-encoding'] == 'gzip' # def inflate(str) Zlib::GzipReader.new( StringIO.new( str ) ).read + end + + EOL = Rack::Utils::Multipart::EOL + # Lifted from Rack::Utils::Multipart, and modified to collect + # overloaded params and params with names suffixed by '[]' as + # arrays. + def parse_multipart(env) + unless env['CONTENT_TYPE'] =~ + %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n + nil + else + boundary = "--#{$1}" + + params = {} + buf = "" + content_length = env['CONTENT_LENGTH'].to_i + input = env['rack.input'] + + boundary_size = boundary.size + EOL.size + bufsize = 16384 + + content_length -= boundary_size + + status = input.read(boundary_size) + raise EOFError, "bad content body" unless status == boundary + EOL + + rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/ + + loop { + head = nil + body = '' + filename = content_type = name = nil + + until head && buf =~ rx + if !head && i = buf.index("\r\n\r\n") + head = buf.slice!(0, i+2) # First \r\n + buf.slice!(0, 2) # Second \r\n + + filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] + content_type = head[/Content-Type: (.*)\r\n/ni, 1] + name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1] + + if filename + body = Tempfile.new("RackMultipart") + body.binmode if body.respond_to?(:binmode) + end + + next + end + + # Save the read body part. + if head && (boundary_size+4 < buf.size) + body << buf.slice!(0, buf.size - (boundary_size+4)) + end + + c = input.read(bufsize < content_length ? bufsize : content_length) + raise EOFError, "bad content body" if c.nil? || c.empty? + buf << c + content_length -= c.size + end + + # Save the rest. + if i = buf.index(rx) + body << buf.slice!(0, i) + buf.slice!(0, boundary_size+2) + + content_length = -1 if $1 == "--" + end + + if filename + body.rewind + data = {:filename => filename, :type => content_type, + :name => name, :tempfile => body, :head => head} + else + data = body + end + + if name + case current = params[name] + when nil + params[name] = (name =~ /\[\]\z/ ? [data] : data) + when Array + params[name] << data + else + params[name] = [current, data] + end + end + + break if buf.empty? || content_length == -1 + } + + params + end end end end end \ No newline at end of file