mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* lib/cgi/core.rb (CGI::QueryExtension): delete MorphingBody
and replace like as 1.8's in multipart reading. see [ruby-dev:36443], reference from CGIAlt http://cgialt.rubyforge.org/ * test/cgi/test_cgi_multipart.rb : fixed multipart test. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19663 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
bd421aa2d2
commit
10e9b63806
3 changed files with 113 additions and 138 deletions
|
@ -1,3 +1,12 @@
|
|||
Thu Oct 2 21:22:43 2008 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
|
||||
|
||||
* lib/cgi/core.rb (CGI::QueryExtension): delete MorphingBody
|
||||
and replace like as 1.8's in multipart reading.
|
||||
see [ruby-dev:36443],
|
||||
reference from CGIAlt http://cgialt.rubyforge.org/
|
||||
|
||||
* test/cgi/test_cgi_multipart.rb : fixed multipart test.
|
||||
|
||||
Thu Oct 2 20:46:17 2008 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* string.c (rb_str_sub_bang): fix coderange.
|
||||
|
|
234
lib/cgi/core.rb
234
lib/cgi/core.rb
|
@ -345,6 +345,15 @@ class CGI
|
|||
params
|
||||
end
|
||||
|
||||
# Maximum content length of post data
|
||||
##MAX_CONTENT_LENGTH = 2 * 1024 * 1024
|
||||
|
||||
# Maximum content length of multipart data
|
||||
MAX_MULTIPART_LENGTH = 128 * 1024 * 1024
|
||||
|
||||
# Maximum number of request parameters when multipart
|
||||
MAX_MULTIPART_COUNT = 128
|
||||
|
||||
# Mixin module. It provides the follow functionality groups:
|
||||
#
|
||||
# 1. Access to CGI environment variables as methods. See
|
||||
|
@ -404,98 +413,105 @@ class CGI
|
|||
end
|
||||
|
||||
def read_multipart(boundary, content_length)
|
||||
params = Hash.new([])
|
||||
boundary = "--" + boundary
|
||||
quoted_boundary = Regexp.quote(boundary)
|
||||
buf = ""
|
||||
## read first boundary
|
||||
stdin = $stdin
|
||||
first_line = "--#{boundary}#{EOL}"
|
||||
content_length -= first_line.bytesize
|
||||
status = stdin.read(first_line.bytesize)
|
||||
raise EOFError.new("no content body") unless status
|
||||
raise EOFError.new("bad content body") unless first_line == status
|
||||
## parse and set params
|
||||
params = {}
|
||||
boundary_rexp = /--#{Regexp.quote(boundary)}(#{EOL}|--)/
|
||||
boundary_size = "#{EOL}--#{boundary}#{EOL}".bytesize
|
||||
boundary_end = nil
|
||||
buf = ''
|
||||
bufsize = 10 * 1024
|
||||
boundary_end=""
|
||||
|
||||
# start multipart/form-data
|
||||
stdinput.binmode if defined? stdinput.binmode
|
||||
boundary_size = boundary.bytesize + EOL.bytesize
|
||||
content_length -= boundary_size
|
||||
status = stdinput.read(boundary_size)
|
||||
if nil == status
|
||||
raise EOFError, "no content body"
|
||||
elsif boundary + EOL != status
|
||||
raise EOFError, "bad content body"
|
||||
end
|
||||
|
||||
loop do
|
||||
head = nil
|
||||
body = MorphingBody.new
|
||||
|
||||
until head and /#{quoted_boundary}(?:#{EOL}|--)/.match(buf)
|
||||
if (not head) and /#{EOL}#{EOL}/.match(buf)
|
||||
buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/) do
|
||||
head = $1.dup
|
||||
""
|
||||
end
|
||||
next
|
||||
end
|
||||
|
||||
if head and ( (EOL + boundary + EOL).bytesize < buf.bytesize )
|
||||
body.print buf[0 ... (buf.bytesize - (EOL + boundary + EOL).bytesize)]
|
||||
buf[0 ... (buf.bytesize - (EOL + boundary + EOL).bytesize)] = ""
|
||||
end
|
||||
|
||||
c = if bufsize < content_length
|
||||
stdinput.read(bufsize)
|
||||
else
|
||||
stdinput.read(content_length)
|
||||
end
|
||||
if c.nil? || c.empty?
|
||||
raise EOFError, "bad content body"
|
||||
end
|
||||
buf.concat(c)
|
||||
content_length -= c.bytesize
|
||||
end
|
||||
|
||||
buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/) do
|
||||
body.print $1
|
||||
if "--" == $2
|
||||
content_length = -1
|
||||
end
|
||||
boundary_end = $2.dup
|
||||
""
|
||||
end
|
||||
|
||||
body.rewind
|
||||
|
||||
/Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/i.match(head)
|
||||
filename = ($1 or $2 or "")
|
||||
if /Mac/i =~ env_table['HTTP_USER_AGENT'] and
|
||||
/Mozilla/i =~ env_table['HTTP_USER_AGENT'] and
|
||||
/MSIE/i !~ env_table['HTTP_USER_AGENT']
|
||||
filename = CGI::unescape(filename)
|
||||
end
|
||||
|
||||
/Content-Type: ([^\s]*)/i.match(head)
|
||||
content_type = ($1 or "")
|
||||
|
||||
(class << body; self; end).class_eval do
|
||||
max_count = MAX_MULTIPART_COUNT
|
||||
n = 0
|
||||
while true
|
||||
(n += 1) < max_count or raise StandardError.new("too many parameters.")
|
||||
## create body (StringIO or Tempfile)
|
||||
body = create_body(bufsize < content_length)
|
||||
class << body
|
||||
alias local_path path
|
||||
define_method(:original_filename) {filename.dup.taint}
|
||||
define_method(:content_type) {content_type.dup.taint}
|
||||
attr_reader :original_filename, :content_type
|
||||
end
|
||||
|
||||
/Content-Disposition:.* name="?([^\";\s]*)"?/i.match(head)
|
||||
name = ($1 || "").dup
|
||||
|
||||
if params.has_key?(name)
|
||||
params[name].push(body)
|
||||
else
|
||||
params[name] = [body]
|
||||
## find head and boundary
|
||||
head = nil
|
||||
separator = EOL * 2
|
||||
until head && matched = boundary_rexp.match(buf)
|
||||
if !head && pos = buf.index(separator)
|
||||
len = pos + EOL.bytesize
|
||||
head = buf[0, len]
|
||||
buf = buf[(pos+separator.bytesize)..-1]
|
||||
else
|
||||
if head && buf.size > boundary_size
|
||||
len = buf.size - boundary_size
|
||||
body.print(buf[0, len])
|
||||
buf[0, len] = ''
|
||||
end
|
||||
c = stdin.read(bufsize < content_length ? bufsize : content_length)
|
||||
raise EOFError.new("bad content body") if c.nil? || c.empty?
|
||||
buf << c
|
||||
content_length -= c.bytesize
|
||||
end
|
||||
end
|
||||
break if buf.bytesize == 0
|
||||
## read to end of boundary
|
||||
m = matched
|
||||
len = m.begin(0)
|
||||
s = buf[0, len]
|
||||
if s =~ /(\r?\n)\z/
|
||||
s = buf[0, len - $1.bytesize]
|
||||
end
|
||||
body.print(s)
|
||||
buf = buf[m.end(0)..-1]
|
||||
boundary_end = m[1]
|
||||
content_length = -1 if boundary_end == '--'
|
||||
## reset file cursor position
|
||||
body.rewind
|
||||
## original filename
|
||||
/Content-Disposition:.* filename=(?:"(.*?)"|([^;\r\n]*))/i.match(head)
|
||||
filename = $1 || $2 || ''
|
||||
filename = CGI.unescape(filename) if unescape_filename?()
|
||||
body.instance_variable_set('@original_filename', filename.taint)
|
||||
## content type
|
||||
/Content-Type: (.*)/i.match(head)
|
||||
(content_type = $1 || '').chomp!
|
||||
body.instance_variable_set('@content_type', content_type.taint)
|
||||
## query parameter name
|
||||
/Content-Disposition:.* name=(?:"(.*?)"|([^;\r\n]*))/i.match(head)
|
||||
name = $1 || $2 || ''
|
||||
(params[name] ||= []) << body
|
||||
## break loop
|
||||
break if buf.size == 0
|
||||
break if content_length == -1
|
||||
end
|
||||
raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/
|
||||
|
||||
raise EOFError, "bad boundary end of body part" unless boundary_end =~ /--/
|
||||
params.default = []
|
||||
params
|
||||
end # read_multipart
|
||||
private :read_multipart
|
||||
def create_body(is_large) #:nodoc:
|
||||
if is_large
|
||||
require 'tempfile'
|
||||
body = Tempfile.new('CGI')
|
||||
else
|
||||
begin
|
||||
require 'stringio'
|
||||
body = StringIO.new
|
||||
rescue LoadError
|
||||
require 'tempfile'
|
||||
body = Tempfile.new('CGI')
|
||||
end
|
||||
end
|
||||
body.binmode if defined? body.binmode
|
||||
return body
|
||||
end
|
||||
def unescape_filename? #:nodoc:
|
||||
user_agent = $CGI_ENV['HTTP_USER_AGENT']
|
||||
return /Mac/i.match(user_agent) && /Mozilla/i.match(user_agent) && !/MSIE/i.match(user_agent)
|
||||
end
|
||||
|
||||
# offline mode. read name=value pairs on standard input.
|
||||
def read_from_cmdline
|
||||
|
@ -524,57 +540,6 @@ class CGI
|
|||
|
||||
# A wrapper class to use a StringIO object as the body and switch
|
||||
# to a TempFile when the passed threshold is passed.
|
||||
class MorphingBody
|
||||
begin
|
||||
require "stringio"
|
||||
@@small_buffer = lambda{StringIO.new}
|
||||
rescue LoadError
|
||||
require "tempfile"
|
||||
@@small_buffer = lambda{
|
||||
n = Tempfile.new("CGI")
|
||||
n.binmode
|
||||
n
|
||||
}
|
||||
end
|
||||
|
||||
def initialize(morph_threshold = 10240)
|
||||
@threshold = morph_threshold
|
||||
@body = @@small_buffer.call
|
||||
@cur_size = 0
|
||||
@morph_check = true
|
||||
end
|
||||
|
||||
def print(data)
|
||||
if @morph_check && (@cur_size + data.bytesize > @threshold)
|
||||
convert_body
|
||||
end
|
||||
@body.print data
|
||||
end
|
||||
def rewind
|
||||
@body.rewind
|
||||
end
|
||||
def path
|
||||
@body.path
|
||||
end
|
||||
|
||||
# returns the true body object.
|
||||
def extract
|
||||
@body
|
||||
end
|
||||
|
||||
private
|
||||
def convert_body
|
||||
new_body = TempFile.new("CGI")
|
||||
new_body.binmode if defined? @body.binmode
|
||||
new_body.binmode if defined? new_body.binmode
|
||||
|
||||
@body.rewind
|
||||
new_body.print @body.read
|
||||
@body = new_body
|
||||
@morph_check = false
|
||||
end
|
||||
end
|
||||
|
||||
# Initialize the data from the query.
|
||||
#
|
||||
# Handles multipart forms (in particular, forms that involve file uploads).
|
||||
|
@ -582,6 +547,7 @@ class CGI
|
|||
def initialize_query()
|
||||
if ("POST" == env_table['REQUEST_METHOD']) and
|
||||
%r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|.match(env_table['CONTENT_TYPE'])
|
||||
raise StandardError.new("too large multipart data.") if env_table['CONTENT_LENGTH'].to_i > MAX_MULTIPART_LENGTH
|
||||
boundary = $1.dup
|
||||
@multipart = true
|
||||
@params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
|
||||
|
|
|
@ -150,9 +150,9 @@ class CGIMultipartTest < Test::Unit::TestCase
|
|||
name = hash[:name]
|
||||
expected = hash[:value]
|
||||
expected_class = @expected_class || (hash[:value].length < threshold ? StringIO : Tempfile)
|
||||
assert_kind_of(expected_class, cgi[name]) if RUBY_VERSION<"1.9"
|
||||
assert_equal(expected, cgi[name].read()) if RUBY_VERSION<"1.9"
|
||||
assert_equal(hash[:filename] || '', cgi[name].original_filename) #if hash[:filename]
|
||||
assert_kind_of(expected_class, cgi[name])
|
||||
assert_equal(expected, cgi[name].read())
|
||||
assert_equal(hash[:filename] || '', cgi[name].original_filename) #if hash[:filename]
|
||||
assert_equal(hash[:content_type] || '', cgi[name].content_type) #if hash[:content_type]
|
||||
end
|
||||
end
|
||||
|
@ -192,7 +192,7 @@ class CGIMultipartTest < Test::Unit::TestCase
|
|||
]
|
||||
@expected_class = Tempfile
|
||||
_test_multipart()
|
||||
end
|
||||
end if RUBY_VERSION < "1.9"
|
||||
|
||||
|
||||
def _set_const(klass, name, value)
|
||||
|
|
Loading…
Reference in a new issue