CGI::QueryExtension 模块
提供以下内容的 Mixin 模块
-
访问
CGI
环境变量作为方法。请参阅CGI
类的文档以获取这些变量的列表。通过移除前导HTTP_
(如果存在)并使用小写名称来公开这些方法。例如,auth_type
将返回环境变量AUTH_TYPE
,而accept
将返回HTTP_ACCEPT
的值。 -
访问 cookie,包括 cookies 属性。
-
访问参数,包括 params 属性,并重载
[]
以按键执行参数值查找。 -
initialize_query
方法,用于初始化上述机制、处理多部分表单,并允许该类在“脱机”模式下使用。
属性
files[R]
获取上传的文件,作为名称 => 值对的哈希
params[R]
获取参数,作为名称 => 值对的哈希,其中值是一个 Array
。
公共实例方法
[](key) 点击切换源代码
获取具有给定键的参数值。
如果参数有多个值,则仅检索第一个值;使用 params
获取值数组。
# File lib/cgi/core.rb, line 714 def [](key) params = @params[key] return '' unless params value = params[0] if @multipart if value return value elsif defined? StringIO StringIO.new("".b) else Tempfile.new("CGI",encoding: Encoding::ASCII_8BIT) end else str = if value then value.dup else "" end str end end
has_key?(*args) 点击切换源代码
如果给定的查询字符串参数存在,则返回 true。
# File lib/cgi/core.rb, line 738 def has_key?(*args) @params.has_key?(*args) end
keys(*args) 点击切换源代码
以 String
数组的形式返回所有查询参数名称。
# File lib/cgi/core.rb, line 733 def keys(*args) @params.keys(*args) end
multipart?() 点击切换源代码
返回表单是否包含 multipart/form-data
# File lib/cgi/core.rb, line 706 def multipart? @multipart end
params=(hash) 点击切换源代码
Set
所有参数。
# File lib/cgi/core.rb, line 474 def params=(hash) @params.clear @params.update(hash) end
私有实例方法
initialize_query() 点击切换源代码
使用 StringIO
对象作为主体并当超出传递的阈值时切换到 TempFile 的包装类。从查询中初始化数据。
处理多部分表单(尤其是涉及文件上传的表单)。读取 @params 字段中的查询参数,并将 cookie 读取到 @cookies 中。
# File lib/cgi/core.rb, line 661 def initialize_query() if ("POST" == env_table['REQUEST_METHOD']) and %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?| =~ env_table['CONTENT_TYPE'] current_max_multipart_length = @max_multipart_length.respond_to?(:call) ? @max_multipart_length.call : @max_multipart_length raise StandardError.new("too large multipart data.") if env_table['CONTENT_LENGTH'].to_i > current_max_multipart_length boundary = $1.dup @multipart = true @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH'])) else @multipart = false @params = CGI.parse( case env_table['REQUEST_METHOD'] when "GET", "HEAD" if defined?(MOD_RUBY) Apache::request.args or "" else env_table['QUERY_STRING'] or "" end when "POST" stdinput.binmode if defined? stdinput.binmode stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or '' else read_from_cmdline end.dup.force_encoding(@accept_charset) ) unless Encoding.find(@accept_charset) == Encoding::ASCII_8BIT @params.each do |key,values| values.each do |value| unless value.valid_encoding? if @accept_charset_error_block @accept_charset_error_block.call(key,value) else raise InvalidEncoding,"Accept-Charset encoding error" end end end end end end @cookies = CGI::Cookie.parse((env_table['HTTP_COOKIE'] or env_table['COOKIE'])) end
read_from_cmdline() 点击切换源代码
离线模式。在标准输入上读取 name=value 对。
# File lib/cgi/core.rb, line 626 def read_from_cmdline require "shellwords" string = unless ARGV.empty? ARGV.join(' ') else if STDIN.tty? STDERR.print( %|(offline mode: enter name=value pairs on standard input)\n| ) end array = readlines rescue nil if not array.nil? array.join(' ').gsub(/\n/n, '') else "" end end.gsub(/\\=/n, '%3D').gsub(/\\&/n, '%26') words = Shellwords.shellwords(string) if words.find{|x| /=/n.match(x) } words.join('&') else words.join('+') end end
read_multipart(boundary, content_length) 点击切换源代码
根据以下内容解析多部分表单元素
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2
返回一个多部分表单参数哈希,其中主体类型为 StringIO
或 Tempfile
,具体取决于多部分表单元素是否超过 10 KB
params[name => body]
# File lib/cgi/core.rb, line 488 def read_multipart(boundary, content_length) ## read first boundary stdin = stdinput 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 = {} @files = {} boundary_rexp = /--#{Regexp.quote(boundary)}(#{EOL}|--)/ boundary_size = "#{EOL}--#{boundary}#{EOL}".bytesize buf = ''.dup bufsize = 10 * 1024 max_count = MAX_MULTIPART_COUNT n = 0 tempfiles = [] while true (n += 1) < max_count or raise StandardError.new("too many parameters.") ## create body (StringIO or Tempfile) body = create_body(bufsize < content_length) tempfiles << body if defined?(Tempfile) && body.kind_of?(Tempfile) class << body if method_defined?(:path) alias local_path path else def local_path nil end end attr_reader :original_filename, :content_type end ## 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 ## 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 || ''.dup filename = CGI.unescape(filename) if unescape_filename?() body.instance_variable_set(:@original_filename, filename) ## content type /Content-Type: (.*)/i.match(head) (content_type = $1 || ''.dup).chomp! body.instance_variable_set(:@content_type, content_type) ## query parameter name /Content-Disposition:.* name=(?:"(.*?)"|([^;\r\n]*))/i.match(head) name = $1 || $2 || '' if body.original_filename.empty? value=body.read.dup.force_encoding(@accept_charset) body.close! if defined?(Tempfile) && body.kind_of?(Tempfile) (params[name] ||= []) << value unless value.valid_encoding? if @accept_charset_error_block @accept_charset_error_block.call(name,value) else raise InvalidEncoding,"Accept-Charset encoding error" end end class << params[name].last;self;end.class_eval do define_method(:read){self} define_method(:original_filename){""} define_method(:content_type){""} end else (params[name] ||= []) << body @files[name]=body end ## break loop break if content_length == -1 end raise EOFError, "bad boundary end of body part" unless boundary_end =~ /--/ params.default = [] params rescue Exception if tempfiles tempfiles.each {|t| if t.path t.close! end } end raise end