diff options
author | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-16 18:49:26 +0900 |
---|---|---|
committer | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-30 00:39:06 +0900 |
commit | fcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch) | |
tree | 64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/lib/cgi/core.rb |
Fresh start
Diffstat (limited to 'jni/ruby/lib/cgi/core.rb')
-rw-r--r-- | jni/ruby/lib/cgi/core.rb | 880 |
1 files changed, 880 insertions, 0 deletions
diff --git a/jni/ruby/lib/cgi/core.rb b/jni/ruby/lib/cgi/core.rb new file mode 100644 index 0000000..cadd01f --- /dev/null +++ b/jni/ruby/lib/cgi/core.rb @@ -0,0 +1,880 @@ +#-- +# Methods for generating HTML, parsing CGI-related parameters, and +# generating HTTP responses. +#++ +class CGI + + $CGI_ENV = ENV # for FCGI support + + # String for carriage return + CR = "\015" + + # String for linefeed + LF = "\012" + + # Standard internet newline sequence + EOL = CR + LF + + REVISION = '$Id: core.rb 46973 2014-07-27 11:04:28Z hsbt $' #:nodoc: + + # Whether processing will be required in binary vs text + NEEDS_BINMODE = File::BINARY != 0 + + # Path separators in different environments. + PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'} + + # HTTP status codes. + HTTP_STATUS = { + "OK" => "200 OK", + "PARTIAL_CONTENT" => "206 Partial Content", + "MULTIPLE_CHOICES" => "300 Multiple Choices", + "MOVED" => "301 Moved Permanently", + "REDIRECT" => "302 Found", + "NOT_MODIFIED" => "304 Not Modified", + "BAD_REQUEST" => "400 Bad Request", + "AUTH_REQUIRED" => "401 Authorization Required", + "FORBIDDEN" => "403 Forbidden", + "NOT_FOUND" => "404 Not Found", + "METHOD_NOT_ALLOWED" => "405 Method Not Allowed", + "NOT_ACCEPTABLE" => "406 Not Acceptable", + "LENGTH_REQUIRED" => "411 Length Required", + "PRECONDITION_FAILED" => "412 Precondition Failed", + "SERVER_ERROR" => "500 Internal Server Error", + "NOT_IMPLEMENTED" => "501 Method Not Implemented", + "BAD_GATEWAY" => "502 Bad Gateway", + "VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates" + } + + # :startdoc: + + # Synonym for ENV. + def env_table + ENV + end + + # Synonym for $stdin. + def stdinput + $stdin + end + + # Synonym for $stdout. + def stdoutput + $stdout + end + + private :env_table, :stdinput, :stdoutput + + # Create an HTTP header block as a string. + # + # :call-seq: + # http_header(content_type_string="text/html") + # http_header(headers_hash) + # + # Includes the empty line that ends the header block. + # + # +content_type_string+:: + # If this form is used, this string is the <tt>Content-Type</tt> + # +headers_hash+:: + # A Hash of header values. The following header keys are recognized: + # + # type:: The Content-Type header. Defaults to "text/html" + # charset:: The charset of the body, appended to the Content-Type header. + # nph:: A boolean value. If true, prepend protocol string and status + # code, and date; and sets default values for "server" and + # "connection" if not explicitly set. + # status:: + # The HTTP status code as a String, returned as the Status header. The + # values are: + # + # OK:: 200 OK + # PARTIAL_CONTENT:: 206 Partial Content + # MULTIPLE_CHOICES:: 300 Multiple Choices + # MOVED:: 301 Moved Permanently + # REDIRECT:: 302 Found + # NOT_MODIFIED:: 304 Not Modified + # BAD_REQUEST:: 400 Bad Request + # AUTH_REQUIRED:: 401 Authorization Required + # FORBIDDEN:: 403 Forbidden + # NOT_FOUND:: 404 Not Found + # METHOD_NOT_ALLOWED:: 405 Method Not Allowed + # NOT_ACCEPTABLE:: 406 Not Acceptable + # LENGTH_REQUIRED:: 411 Length Required + # PRECONDITION_FAILED:: 412 Precondition Failed + # SERVER_ERROR:: 500 Internal Server Error + # NOT_IMPLEMENTED:: 501 Method Not Implemented + # BAD_GATEWAY:: 502 Bad Gateway + # VARIANT_ALSO_VARIES:: 506 Variant Also Negotiates + # + # server:: The server software, returned as the Server header. + # connection:: The connection type, returned as the Connection header (for + # instance, "close". + # length:: The length of the content that will be sent, returned as the + # Content-Length header. + # language:: The language of the content, returned as the Content-Language + # header. + # expires:: The time on which the current content expires, as a +Time+ + # object, returned as the Expires header. + # cookie:: + # A cookie or cookies, returned as one or more Set-Cookie headers. The + # value can be the literal string of the cookie; a CGI::Cookie object; + # an Array of literal cookie strings or Cookie objects; or a hash all of + # whose values are literal cookie strings or Cookie objects. + # + # These cookies are in addition to the cookies held in the + # @output_cookies field. + # + # Other headers can also be set; they are appended as key: value. + # + # Examples: + # + # http_header + # # Content-Type: text/html + # + # http_header("text/plain") + # # Content-Type: text/plain + # + # http_header("nph" => true, + # "status" => "OK", # == "200 OK" + # # "status" => "200 GOOD", + # "server" => ENV['SERVER_SOFTWARE'], + # "connection" => "close", + # "type" => "text/html", + # "charset" => "iso-2022-jp", + # # Content-Type: text/html; charset=iso-2022-jp + # "length" => 103, + # "language" => "ja", + # "expires" => Time.now + 30, + # "cookie" => [cookie1, cookie2], + # "my_header1" => "my_value" + # "my_header2" => "my_value") + # + # This method does not perform charset conversion. + def http_header(options='text/html') + if options.is_a?(String) + content_type = options + buf = _header_for_string(content_type) + elsif options.is_a?(Hash) + if options.size == 1 && options.has_key?('type') + content_type = options['type'] + buf = _header_for_string(content_type) + else + buf = _header_for_hash(options.dup) + end + else + raise ArgumentError.new("expected String or Hash but got #{options.class}") + end + if defined?(MOD_RUBY) + _header_for_modruby(buf) + return '' + else + buf << EOL # empty line of separator + return buf + end + end # http_header() + + # This method is an alias for #http_header, when HTML5 tag maker is inactive. + # + # NOTE: use #http_header to create HTTP header blocks, this alias is only + # provided for backwards compatibility. + # + # Using #header with the HTML5 tag maker will create a <header> element. + alias :header :http_header + + def _header_for_string(content_type) #:nodoc: + buf = '' + if nph?() + buf << "#{$CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0'} 200 OK#{EOL}" + buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}" + buf << "Server: #{$CGI_ENV['SERVER_SOFTWARE']}#{EOL}" + buf << "Connection: close#{EOL}" + end + buf << "Content-Type: #{content_type}#{EOL}" + if @output_cookies + @output_cookies.each {|cookie| buf << "Set-Cookie: #{cookie}#{EOL}" } + end + return buf + end # _header_for_string + private :_header_for_string + + def _header_for_hash(options) #:nodoc: + buf = '' + ## add charset to option['type'] + options['type'] ||= 'text/html' + charset = options.delete('charset') + options['type'] += "; charset=#{charset}" if charset + ## NPH + options.delete('nph') if defined?(MOD_RUBY) + if options.delete('nph') || nph?() + protocol = $CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0' + status = options.delete('status') + status = HTTP_STATUS[status] || status || '200 OK' + buf << "#{protocol} #{status}#{EOL}" + buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}" + options['server'] ||= $CGI_ENV['SERVER_SOFTWARE'] || '' + options['connection'] ||= 'close' + end + ## common headers + status = options.delete('status') + buf << "Status: #{HTTP_STATUS[status] || status}#{EOL}" if status + server = options.delete('server') + buf << "Server: #{server}#{EOL}" if server + connection = options.delete('connection') + buf << "Connection: #{connection}#{EOL}" if connection + type = options.delete('type') + buf << "Content-Type: #{type}#{EOL}" #if type + length = options.delete('length') + buf << "Content-Length: #{length}#{EOL}" if length + language = options.delete('language') + buf << "Content-Language: #{language}#{EOL}" if language + expires = options.delete('expires') + buf << "Expires: #{CGI.rfc1123_date(expires)}#{EOL}" if expires + ## cookie + if cookie = options.delete('cookie') + case cookie + when String, Cookie + buf << "Set-Cookie: #{cookie}#{EOL}" + when Array + arr = cookie + arr.each {|c| buf << "Set-Cookie: #{c}#{EOL}" } + when Hash + hash = cookie + hash.each_value {|c| buf << "Set-Cookie: #{c}#{EOL}" } + end + end + if @output_cookies + @output_cookies.each {|c| buf << "Set-Cookie: #{c}#{EOL}" } + end + ## other headers + options.each do |key, value| + buf << "#{key}: #{value}#{EOL}" + end + return buf + end # _header_for_hash + private :_header_for_hash + + def nph? #:nodoc: + return /IIS\/(\d+)/.match($CGI_ENV['SERVER_SOFTWARE']) && $1.to_i < 5 + end + + def _header_for_modruby(buf) #:nodoc: + request = Apache::request + buf.scan(/([^:]+): (.+)#{EOL}/o) do |name, value| + warn sprintf("name:%s value:%s\n", name, value) if $DEBUG + case name + when 'Set-Cookie' + request.headers_out.add(name, value) + when /^status$/i + request.status_line = value + request.status = value.to_i + when /^content-type$/i + request.content_type = value + when /^content-encoding$/i + request.content_encoding = value + when /^location$/i + request.status = 302 if request.status == 200 + request.headers_out[name] = value + else + request.headers_out[name] = value + end + end + request.send_http_header + return '' + end + private :_header_for_modruby + + # Print an HTTP header and body to $DEFAULT_OUTPUT ($>) + # + # :call-seq: + # cgi.out(content_type_string='text/html') + # cgi.out(headers_hash) + # + # +content_type_string+:: + # If a string is passed, it is assumed to be the content type. + # +headers_hash+:: + # This is a Hash of headers, similar to that used by #http_header. + # +block+:: + # A block is required and should evaluate to the body of the response. + # + # <tt>Content-Length</tt> is automatically calculated from the size of + # the String returned by the content block. + # + # If <tt>ENV['REQUEST_METHOD'] == "HEAD"</tt>, then only the header + # is output (the content block is still required, but it is ignored). + # + # If the charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then the + # content is converted to this charset, and the language is set to "ja". + # + # Example: + # + # cgi = CGI.new + # cgi.out{ "string" } + # # Content-Type: text/html + # # Content-Length: 6 + # # + # # string + # + # cgi.out("text/plain") { "string" } + # # Content-Type: text/plain + # # Content-Length: 6 + # # + # # string + # + # cgi.out("nph" => true, + # "status" => "OK", # == "200 OK" + # "server" => ENV['SERVER_SOFTWARE'], + # "connection" => "close", + # "type" => "text/html", + # "charset" => "iso-2022-jp", + # # Content-Type: text/html; charset=iso-2022-jp + # "language" => "ja", + # "expires" => Time.now + (3600 * 24 * 30), + # "cookie" => [cookie1, cookie2], + # "my_header1" => "my_value", + # "my_header2" => "my_value") { "string" } + # # HTTP/1.1 200 OK + # # Date: Sun, 15 May 2011 17:35:54 GMT + # # Server: Apache 2.2.0 + # # Connection: close + # # Content-Type: text/html; charset=iso-2022-jp + # # Content-Length: 6 + # # Content-Language: ja + # # Expires: Tue, 14 Jun 2011 17:35:54 GMT + # # Set-Cookie: foo + # # Set-Cookie: bar + # # my_header1: my_value + # # my_header2: my_value + # # + # # string + def out(options = "text/html") # :yield: + + options = { "type" => options } if options.kind_of?(String) + content = yield + options["length"] = content.bytesize.to_s + output = stdoutput + output.binmode if defined? output.binmode + output.print http_header(options) + output.print content unless "HEAD" == env_table['REQUEST_METHOD'] + end + + + # Print an argument or list of arguments to the default output stream + # + # cgi = CGI.new + # cgi.print # default: cgi.print == $DEFAULT_OUTPUT.print + def print(*options) + stdoutput.print(*options) + end + + # Parse an HTTP query string into a hash of key=>value pairs. + # + # params = CGI::parse("query_string") + # # {"name1" => ["value1", "value2", ...], + # # "name2" => ["value1", "value2", ...], ... } + # + def CGI::parse(query) + params = {} + query.split(/[&;]/).each do |pairs| + key, value = pairs.split('=',2).collect{|v| CGI::unescape(v) } + + next unless key + + params[key] ||= [] + params[key].push(value) if value + end + + params.default=[].freeze + params + end + + # Maximum content length of post data + ##MAX_CONTENT_LENGTH = 2 * 1024 * 1024 + + # Maximum number of request parameters when multipart + MAX_MULTIPART_COUNT = 128 + + # Mixin module that provides the following: + # + # 1. Access to the CGI environment variables as methods. See + # documentation to the CGI class for a list of these variables. The + # methods are exposed by removing the leading +HTTP_+ (if it exists) and + # downcasing the name. For example, +auth_type+ will return the + # environment variable +AUTH_TYPE+, and +accept+ will return the value + # for +HTTP_ACCEPT+. + # + # 2. Access to cookies, including the cookies attribute. + # + # 3. Access to parameters, including the params attribute, and overloading + # #[] to perform parameter value lookup by key. + # + # 4. The initialize_query method, for initializing the above + # mechanisms, handling multipart forms, and allowing the + # class to be used in "offline" mode. + # + module QueryExtension + + %w[ CONTENT_LENGTH SERVER_PORT ].each do |env| + define_method(env.sub(/^HTTP_/, '').downcase) do + (val = env_table[env]) && Integer(val) + end + end + + %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO + PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST + REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME + SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE + + HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING + HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST + HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env| + define_method(env.sub(/^HTTP_/, '').downcase) do + env_table[env] + end + end + + # Get the raw cookies as a string. + def raw_cookie + env_table["HTTP_COOKIE"] + end + + # Get the raw RFC2965 cookies as a string. + def raw_cookie2 + env_table["HTTP_COOKIE2"] + end + + # Get the cookies as a hash of cookie-name=>Cookie pairs. + attr_accessor :cookies + + # Get the parameters as a hash of name=>values pairs, where + # values is an Array. + attr_reader :params + + # Get the uploaded files as a hash of name=>values pairs + attr_reader :files + + # Set all the parameters. + def params=(hash) + @params.clear + @params.update(hash) + end + + ## + # Parses multipart form elements according to + # http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 + # + # Returns a hash of multipart form parameters with bodies of type StringIO or + # Tempfile depending on whether the multipart form element exceeds 10 KB + # + # params[name => body] + # + 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 = '' + 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 || '' + 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 || '' + 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 # read_multipart + private :read_multipart + def create_body(is_large) #:nodoc: + if is_large + require 'tempfile' + body = Tempfile.new('CGI', encoding: Encoding::ASCII_8BIT) + else + begin + require 'stringio' + body = StringIO.new("".force_encoding(Encoding::ASCII_8BIT)) + rescue LoadError + require 'tempfile' + body = Tempfile.new('CGI', encoding: Encoding::ASCII_8BIT) + 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 + 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 + 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. + # Initialize the data from the query. + # + # Handles multipart forms (in particular, forms that involve file uploads). + # Reads query parameters in the @params field, and cookies into @cookies. + 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 + private :initialize_query + + # Returns whether the form contained multipart/form-data + def multipart? + @multipart + end + + # Get the value for the parameter with a given key. + # + # If the parameter has multiple values, only the first will be + # retrieved; use #params to get the array of values. + def [](key) + params = @params[key] + return '' unless params + value = params[0] + if @multipart + if value + return value + elsif defined? StringIO + StringIO.new("".force_encoding(Encoding::ASCII_8BIT)) + else + Tempfile.new("CGI",encoding: Encoding::ASCII_8BIT) + end + else + str = if value then value.dup else "" end + str + end + end + + # Return all query parameter names as an array of String. + def keys(*args) + @params.keys(*args) + end + + # Returns true if a given query string parameter exists. + def has_key?(*args) + @params.has_key?(*args) + end + alias key? has_key? + alias include? has_key? + + end # QueryExtension + + # Exception raised when there is an invalid encoding detected + class InvalidEncoding < Exception; end + + # @@accept_charset is default accept character set. + # This default value default is "UTF-8" + # If you want to change the default accept character set + # when create a new CGI instance, set this: + # + # CGI.accept_charset = "EUC-JP" + # + @@accept_charset="UTF-8" + + # Return the accept character set for all new CGI instances. + def self.accept_charset + @@accept_charset + end + + # Set the accept character set for all new CGI instances. + def self.accept_charset=(accept_charset) + @@accept_charset=accept_charset + end + + # Return the accept character set for this CGI instance. + attr_reader :accept_charset + + # @@max_multipart_length is the maximum length of multipart data. + # The default value is 128 * 1024 * 1024 bytes + # + # The default can be set to something else in the CGI constructor, + # via the :max_multipart_length key in the option hash. + # + # See CGI.new documentation. + # + @@max_multipart_length= 128 * 1024 * 1024 + + # Create a new CGI instance. + # + # :call-seq: + # CGI.new(tag_maker) { block } + # CGI.new(options_hash = {}) { block } + # + # + # <tt>tag_maker</tt>:: + # This is the same as using the +options_hash+ form with the value <tt>{ + # :tag_maker => tag_maker }</tt> Note that it is recommended to use the + # +options_hash+ form, since it also allows you specify the charset you + # will accept. + # <tt>options_hash</tt>:: + # A Hash that recognizes three options: + # + # <tt>:accept_charset</tt>:: + # specifies encoding of received query string. If omitted, + # <tt>@@accept_charset</tt> is used. If the encoding is not valid, a + # CGI::InvalidEncoding will be raised. + # + # Example. Suppose <tt>@@accept_charset</tt> is "UTF-8" + # + # when not specified: + # + # cgi=CGI.new # @accept_charset # => "UTF-8" + # + # when specified as "EUC-JP": + # + # cgi=CGI.new(:accept_charset => "EUC-JP") # => "EUC-JP" + # + # <tt>:tag_maker</tt>:: + # String that specifies which version of the HTML generation methods to + # use. If not specified, no HTML generation methods will be loaded. + # + # The following values are supported: + # + # "html3":: HTML 3.x + # "html4":: HTML 4.0 + # "html4Tr":: HTML 4.0 Transitional + # "html4Fr":: HTML 4.0 with Framesets + # "html5":: HTML 5 + # + # <tt>:max_multipart_length</tt>:: + # Specifies maximum length of multipart data. Can be an Integer scalar or + # a lambda, that will be evaluated when the request is parsed. This + # allows more complex logic to be set when determining whether to accept + # multipart data (e.g. consult a registered users upload allowance) + # + # Default is 128 * 1024 * 1024 bytes + # + # cgi=CGI.new(:max_multipart_length => 268435456) # simple scalar + # + # cgi=CGI.new(:max_multipart_length => -> {check_filesystem}) # lambda + # + # <tt>block</tt>:: + # If provided, the block is called when an invalid encoding is + # encountered. For example: + # + # encoding_errors={} + # cgi=CGI.new(:accept_charset=>"EUC-JP") do |name,value| + # encoding_errors[name] = value + # end + # + # Finally, if the CGI object is not created in a standard CGI call + # environment (that is, it can't locate REQUEST_METHOD in its environment), + # then it will run in "offline" mode. In this mode, it reads its parameters + # from the command line or (failing that) from standard input. Otherwise, + # cookies and other parameters are parsed automatically from the standard + # CGI locations, which varies according to the REQUEST_METHOD. + def initialize(options = {}, &block) # :yields: name, value + @accept_charset_error_block = block_given? ? block : nil + @options={ + :accept_charset=>@@accept_charset, + :max_multipart_length=>@@max_multipart_length + } + case options + when Hash + @options.merge!(options) + when String + @options[:tag_maker]=options + end + @accept_charset=@options[:accept_charset] + @max_multipart_length=@options[:max_multipart_length] + if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE") + Apache.request.setup_cgi_env + end + + extend QueryExtension + @multipart = false + + initialize_query() # set @params, @cookies + @output_cookies = nil + @output_hidden = nil + + case @options[:tag_maker] + when "html3" + require 'cgi/html' + extend Html3 + extend HtmlExtension + when "html4" + require 'cgi/html' + extend Html4 + extend HtmlExtension + when "html4Tr" + require 'cgi/html' + extend Html4Tr + extend HtmlExtension + when "html4Fr" + require 'cgi/html' + extend Html4Tr + extend Html4Fr + extend HtmlExtension + when "html5" + require 'cgi/html' + extend Html5 + extend HtmlExtension + end + end + +end # class CGI |