Index: lib/cgi.rb =================================================================== --- lib/cgi.rb (リビジョン 18794) +++ lib/cgi.rb (作業コピー) @@ -339,7 +339,7 @@ # url_encoded_string = CGI::escape("'Stop!' said Fred") # # => "%27Stop%21%27+said+Fred" def CGI::escape(string) - string.gsub(/([^ a-zA-Z0-9_.-]+)/) do + string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase end.tr(' ', '+') end @@ -350,23 +350,17 @@ # # => "'Stop!' said Fred" def CGI::unescape(string) enc = string.encoding - string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do + string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do [$1.delete('%')].pack('H*').force_encoding(enc) end end - TABLE_FOR_ESCAPE_HTML__ = { - '&' => '&', - '"' => '"', - '<' => '<', - '>' => '>', - } # Escape special characters in HTML, namely &\"<> # CGI::escapeHTML('Usage: foo "bar" ') # # => "Usage: foo "bar" <baz>" def CGI::escapeHTML(string) - string.gsub(/[&\"<>]/, TABLE_FOR_ESCAPE_HTML__) + string.gsub(/&/n, '&').gsub(/\"/n, '"').gsub(/>/n, '>').gsub(/ "Usage: foo \"bar\" " def CGI::unescapeHTML(string) enc = string.encoding - string.gsub(/&(amp|quot|gt|lt|\#[0-9]+|\#x[0-9A-Fa-f]+);/) do + string.gsub(/&(amp|quot|gt|lt|\#[0-9]+|\#x[0-9A-Fa-f]+);/n) do match = $1.dup case match when 'amp' then '&' when 'quot' then '"' when 'gt' then '>' when 'lt' then '<' - when /\A#0*(\d+)\z/ then + when /\A#0*(\d+)\z/n then if Integer($1) < 256 Integer($1).chr.force_encoding(enc) else - "&##{$1};" + if Integer($1) < 65536 and enc==Encoding::UTF_8 + [Integer($1)].pack("U") + else + "&##{$1};" + end end - when /\A#x([0-9a-f]+)\z/i then + when /\A#x([0-9a-f]+)\z/ni then if $1.hex < 256 $1.hex.chr.force_encoding(enc) else - "&#x#{$1};" + if $1.hex < 65536 and enc==Encoding::UTF_8 + [$1.hex].pack("U") + else + "&#x#{$1};" + end + end else "&#{match};" end end end - def CGI::escape_html(str) - escapeHTML(str) - end - def CGI::unescape_html(str) - unescapeHTML(str) - end # Escape only the tags of certain HTML elements in +string+. # @@ -967,7 +964,7 @@ def read_multipart(boundary, content_length) params = Hash.new([]) boundary = "--" + boundary - quoted_boundary = Regexp.quote(boundary) + quoted_boundary = Regexp.quote(boundary,"n") buf = "" bufsize = 10 * 1024 boundary_end="" @@ -985,7 +982,19 @@ loop do head = nil - body = MorphingBody.new + if 10240 < content_length + 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 until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf) if (not head) and /#{EOL}#{EOL}/n.match(buf) @@ -1083,59 +1092,6 @@ end private :read_from_cmdline - # 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). @@ -1172,7 +1128,28 @@ def multipart? @multipart end - + module Value # :nodoc: + def set_params(params) + @params = params + end + def [](idx, *args) + if args.bytesize == 0 + warn "#{caller(1)[0]}:CAUTION! cgi['key'] == cgi.params['key'][0]; if want Array, use cgi.params['key']" + @params[idx] + else + super[idx,*args] + end + end + def first + warn "#{caller(1)[0]}:CAUTION! cgi['key'] == cgi.params['key'][0]; if want Array, use cgi.params['key']" + self + end + alias last first + def to_a + @params || [self] + end + alias to_ary to_a # to be rhs of multiple assignment + end # Get the value for the parameter with a given key. # # If the parameter has multiple values, only the first will be @@ -1191,6 +1168,9 @@ end else str = if value then value.dup else "" end + str.extend(Value) + str.set_params(params) + str end end @@ -2280,15 +2260,17 @@ Apache.request.setup_cgi_env end - (class << self; self; end).class_eval do - const_set(:CGI_PARAMS, [1]) - const_set(:CGI_COOKIES, [2]) - end - extend QueryExtension @multipart = false - initialize_query() # set @params, @cookies + if defined?(CGI_PARAMS) + warn "do not use CGI_PARAMS and CGI_COOKIES" + @params = CGI_PARAMS.dup + @cookies = CGI_COOKIES.dup + else + initialize_query() # set @params, @cookies + end + @output_cookies = nil @output_hidden = nil