модуль CGI::QueryExtension
Mixin-модуль, который предоставляет следующее:
-
Доступ к переменным среды CGI в качестве методов. См. документацию к классу CGI для списка этих переменных. Методы экспонируются путем удаления префикса
HTTP_(если он существует) и приведения имени к нижнему регистру. Например,auth_typeвернёт переменную средыAUTH_TYPE, аacceptвернёт значение дляHTTP_ACCEPT. -
Доступ к кукам, включая атрибут cookies.
-
Доступ к параметрам, включая атрибут params, и перегрузку [] для поиска значения параметра по ключу.
-
Метод #initialize_query для инициализации вышеперечисленных механизмов, обработки многочастных форм и позволяющий классу использоваться в «оффлайн» режиме.
Атрибуты
Получить куки в виде хеша пар «имя куки»=>«Cookie».
Получить загруженные файлы в виде хеша пар «имя»=>«значения»
Получить параметры в виде хеша пар «имя»=>«значения», где значения являются массивом.
Общедоступные методы экземпляров
# File lib/cgi/core.rb, line 701
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 Получить значение для параметра с заданным ключом.
Если параметр имеет несколько значений, будет возвращено только первое; используйте params для получения массива значений.
# File lib/cgi/core.rb, line 725 def has_key?(*args) @params.has_key?(*args) end
Возвращает true, если параметр запроса с данным ключом существует.
# File lib/cgi/core.rb, line 720 def keys(*args) @params.keys(*args) end
Возвращает все имена параметров запроса в виде массива строк.
# File lib/cgi/core.rb, line 693 def multipart? @multipart end
Возвращает, содержала ли форма multipart/form-data
# File lib/cgi/core.rb, line 462 def params=(hash) @params.clear @params.update(hash) end
Установить все параметры.
# File lib/cgi/core.rb, line 442 def raw_cookie env_table["HTTP_COOKIE"] end
Получить исходные куки в виде строки.
# File lib/cgi/core.rb, line 447 def raw_cookie2 env_table["HTTP_COOKIE2"] end
Получить исходные куки RFC2965 в виде строки.
Приватные методы экземпляров
# File lib/cgi/core.rb, line 648
def initialize_query()
if ("POST" == env_table['REQUEST_METHOD']) and
%r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|.match(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 Обёртка для использования объекта StringIO в качестве тела и переключения на TempFile, когда пройден порог. Инициализировать данные из запроса.
Обрабатывает многочастные формы (в частности, формы с загрузкой файлов). Считывает параметры запроса в поле @params и куки в @cookies.
# File lib/cgi/core.rb, line 613
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 Режим офлайн. Считывает пары «имя=значение» со стандартного ввода.
# File lib/cgi/core.rb, line 476
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.taint)
## content type
/Content-Type: (.*)/i.match(head)
(content_type = $1 || ''.dup).chomp!
body.instance_variable_set(:@content_type, content_type.taint)
## 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 Парсит элементы многочастной формы в соответствии с
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2
Возвращает хеш параметров многочастной формы с телами типа StringIO или Tempfile в зависимости от того, превышает ли элемент многочастной формы 10 КБ
params[name => body]
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.