# File lib/cgikit/utilities.rb, line 59
    def query_from_multipart( headers, input, boundary, content_length )
      params   = Hash.new([])
      boundary = "--" + boundary
      buf      = ""
      bufsize  = 10 * 1024

      # start multipart/form-data
      input.binmode
      boundary_size   = boundary.size + EOL.size
      content_length -= boundary_size
      status          = input.read boundary_size
      if status == nil then
        raise EOFError, "no content body"
      elsif boundary + EOL != status
        raise EOFError, "bad content body"
      end

      until content_length == -1
        head = nil
        tmp = nil
        if content_length > MEM_CONTENT_LENGTH
          require "tempfile"
          tmp = Tempfile.new("CGIKit")
          tmp.binmode
          data = TempfileByteData.new(tmp)
        else
          data = ByteData.new
        end

        until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
            if (not head) and /#{EOL}#{EOL}/n.match(buf)
                buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
              head = $1.dup
              ""
            end
              next
            end

          if head and ( (EOL + boundary + EOL).size < buf.size )
            data << buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
            buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
          end

          if bufsize < content_length then
            c = input.read(bufsize) or ''
          else
            c = input.read(content_length) or ''
          end
          buf += c
          content_length -= c.size
        end

        buf = buf.sub(/\A((?:.|\n)*?)(?:#{EOL})?#{boundary}(#{EOL}|--)/n) do
          data << $1
          if "--" == $2
            content_length = -1
          end
          ""
        end

        /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
        filename = ($1 || "").dup
        if /Mac/ni.match(headers['HTTP_USER_AGENT']) and
            /Mozilla/ni.match(headers['HTTP_USER_AGENT']) and
            (not /MSIE/ni.match(headers['HTTP_USER_AGENT']))
          filename = Utilities.unescape_url filename
        end
        data.path = filename

        /Content-Type: ([^\r\n]*)/ni.match(head)
        if $1 then
          data.content_type = $1.dup
        else
          data = data.to_s
        end

        /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
        name = $1.dup

        if params.has_key? name then
          params[name].push data
        else
          params[name] = [data]
        end
      end

      params
    end