class CGI
def self.accept_charset
def self.accept_charset @@accept_charset end
def self.accept_charset=(accept_charset)
def self.accept_charset=(accept_charset) @@accept_charset=accept_charset end
def self.parse(query)
# "name2" => ["value1", "value2", ...], ... }
# {"name1" => ["value1", "value2", ...],
params = CGI.parse("query_string")
Parse an HTTP query string into a hash of key=>value pairs.
def self.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
def _header_for_hash(options) #:nodoc:
def _header_for_hash(options) #:nodoc: buf = ''.dup ## 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 = _no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0' status = options.delete('status') status = HTTP_STATUS[status] || _no_crlf_check(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] || _no_crlf_check(status)}#{EOL}" if status server = options.delete('server') buf << "Server: #{_no_crlf_check(server)}#{EOL}" if server connection = options.delete('connection') buf << "Connection: #{_no_crlf_check(connection)}#{EOL}" if connection type = options.delete('type') buf << "Content-Type: #{_no_crlf_check(type)}#{EOL}" #if type length = options.delete('length') buf << "Content-Length: #{_no_crlf_check(length)}#{EOL}" if length language = options.delete('language') buf << "Content-Language: #{_no_crlf_check(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: #{_no_crlf_check(cookie)}#{EOL}" when Array arr = cookie arr.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" } when Hash hash = cookie hash.each_value {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" } end end if @output_cookies @output_cookies.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" } end ## other headers options.each do |key, value| buf << "#{_no_crlf_check(key)}: #{_no_crlf_check(value)}#{EOL}" end return buf end # _header_for_hash
def _header_for_modruby(buf) #:nodoc:
def _header_for_modruby(buf) #:nodoc: request = Apache::request buf.scan(/([^:]+): (.+)#{EOL}/o) do |name, value| $stderr.printf("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
def _header_for_string(content_type) #:nodoc:
def _header_for_string(content_type) #:nodoc: buf = ''.dup if nph?() buf << "#{_no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0'} 200 OK#{EOL}" buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}" buf << "Server: #{_no_crlf_check($CGI_ENV['SERVER_SOFTWARE'])}#{EOL}" buf << "Connection: close#{EOL}" end buf << "Content-Type: #{_no_crlf_check(content_type)}#{EOL}" if @output_cookies @output_cookies.each {|cookie| buf << "Set-Cookie: #{_no_crlf_check(cookie)}#{EOL}" } end return buf end # _header_for_string
def _no_crlf_check(str)
def _no_crlf_check(str) if str str = str.to_s raise "A HTTP status or header field must not include CR and LF" if str =~ /[\r\n]/ str else nil end end
def env_table
def env_table ENV end
def http_header(options='text/html')
"my_header2" => "my_value")
"my_header1" => "my_value",
"cookie" => [cookie1, cookie2],
"expires" => Time.now + 30,
"language" => "ja",
"length" => 103,
# Content-Type: text/html; charset=iso-2022-jp
"charset" => "iso-2022-jp",
"type" => "text/html",
"connection" => "close",
"server" => ENV['SERVER_SOFTWARE'],
# "status" => "200 GOOD",
"status" => "OK", # == "200 OK"
http_header("nph" => true,
# Content-Type: text/plain
http_header("text/plain")
# Content-Type: text/html
http_header
Examples:
Other headers can also be set; they are appended as key: value.
@output_cookies field.
These cookies are in addition to the cookies held in the
whose values are literal cookie strings or Cookie objects.
an Array of literal cookie strings or Cookie objects; or a hash all of
value can be the literal string of the cookie; a CGI::Cookie object;
A cookie or cookies, returned as one or more Set-Cookie headers. The
cookie::
object, returned as the Expires header.
expires:: The time on which the current content expires, as a +Time+
header.
language:: The language of the content, returned as the Content-Language
Content-Length header.
length:: The length of the content that will be sent, returned as the
instance, "close".
connection:: The connection type, returned as the Connection header (for
server:: The server software, returned as the Server header.
VARIANT_ALSO_VARIES:: 506 Variant Also Negotiates
BAD_GATEWAY:: 502 Bad Gateway
NOT_IMPLEMENTED:: 501 Method Not Implemented
SERVER_ERROR:: 500 Internal Server Error
PRECONDITION_FAILED:: 412 Precondition Failed
LENGTH_REQUIRED:: 411 Length Required
NOT_ACCEPTABLE:: 406 Not Acceptable
METHOD_NOT_ALLOWED:: 405 Method Not Allowed
NOT_FOUND:: 404 Not Found
FORBIDDEN:: 403 Forbidden
AUTH_REQUIRED:: 401 Authorization Required
BAD_REQUEST:: 400 Bad Request
NOT_MODIFIED:: 304 Not Modified
REDIRECT:: 302 Found
MOVED:: 301 Moved Permanently
MULTIPLE_CHOICES:: 300 Multiple Choices
PARTIAL_CONTENT:: 206 Partial Content
OK:: 200 OK
values are:
The HTTP status code as a String, returned as the Status header. The
status::
"connection" if not explicitly set.
code, and date; and sets default values for "server" and
nph:: A boolean value. If true, prepend protocol string and status
charset:: The charset of the body, appended to the Content-Type header.
type:: The Content-Type header. Defaults to "text/html"
A Hash of header values. The following header keys are recognized:
+headers_hash+::
If this form is used, this string is the Content-Type
+content_type_string+::
Includes the empty line that ends the header block.
http_header(headers_hash)
http_header(content_type_string="text/html")
:call-seq:
Create an HTTP header block as a string.
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()
def initialize(options = {}, &block) # :yields: name, value
CGI locations, which varies according to the REQUEST_METHOD.
cookies and other parameters are parsed automatically from the standard
from the command line or (failing that) from standard input. Otherwise,
then it will run in "offline" mode. In this mode, it reads its parameters
environment (that is, it can't locate REQUEST_METHOD in its environment),
Finally, if the CGI object is not created in a standard CGI call
end
encoding_errors[name] = value
cgi=CGI.new(:accept_charset=>"EUC-JP") do |name,value|
encoding_errors={}
encountered. For example:
If provided, the block is called when an invalid encoding is
block::
cgi=CGI.new(:max_multipart_length => -> {check_filesystem}) # lambda
cgi=CGI.new(:max_multipart_length => 268435456) # simple scalar
Default is 128 * 1024 * 1024 bytes
multipart data (e.g. consult a registered users upload allowance)
allows more complex logic to be set when determining whether to accept
a lambda, that will be evaluated when the request is parsed. This
Specifies maximum length of multipart data. Can be an Integer scalar or
:max_multipart_length::
"html5":: HTML 5
"html4Fr":: HTML 4.0 with Framesets
"html4Tr":: HTML 4.0 Transitional
"html4":: HTML 4.0
"html3":: HTML 3.x
The following values are supported:
use. If not specified, no HTML generation methods will be loaded.
String that specifies which version of the HTML generation methods to
:tag_maker::
cgi=CGI.new(:accept_charset => "EUC-JP") # => "EUC-JP"
when specified as "EUC-JP":
cgi=CGI.new # @accept_charset # => "UTF-8"
when not specified:
Example. Suppose @@accept_charset is "UTF-8"
CGI::InvalidEncoding will be raised.
@@accept_charset is used. If the encoding is not valid, a
specifies encoding of received query string. If omitted,
:accept_charset::
A Hash that recognizes three options:
options_hash::
will accept.
+options_hash+ form, since it also allows you specify the charset you
:tag_maker => tag_maker } Note that it is recommended to use the
This is the same as using the +options_hash+ form with the value {
tag_maker::
CGI.new(options_hash = {}) { block }
CGI.new(tag_maker) { block }
:call-seq:
Create a new CGI instance.
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_relative 'html' extend Html3 extend HtmlExtension when "html4" require_relative 'html' extend Html4 extend HtmlExtension when "html4Tr" require_relative 'html' extend Html4Tr extend HtmlExtension when "html4Fr" require_relative 'html' extend Html4Tr extend Html4Fr extend HtmlExtension when "html5" require_relative 'html' extend Html5 extend HtmlExtension end end
def nph? #:nodoc:
def nph? #:nodoc: return /IIS\/(\d+)/ =~ $CGI_ENV['SERVER_SOFTWARE'] && $1.to_i < 5 end
def out(options = "text/html") # :yield:
# string
#
# my_header2: my_value
# my_header1: my_value
# Set-Cookie: bar
# Set-Cookie: foo
# Expires: Tue, 14 Jun 2011 17:35:54 GMT
# Content-Language: ja
# Content-Length: 6
# Content-Type: text/html; charset=iso-2022-jp
# Connection: close
# Server: Apache 2.2.0
# Date: Sun, 15 May 2011 17:35:54 GMT
# HTTP/1.1 200 OK
"my_header2" => "my_value") { "string" }
"my_header1" => "my_value",
"cookie" => [cookie1, cookie2],
"expires" => Time.now + (3600 * 24 * 30),
"language" => "ja",
# Content-Type: text/html; charset=iso-2022-jp
"charset" => "iso-2022-jp",
"type" => "text/html",
"connection" => "close",
"server" => ENV['SERVER_SOFTWARE'],
"status" => "OK", # == "200 OK"
cgi.out("nph" => true,
# string
#
# Content-Length: 6
# Content-Type: text/plain
cgi.out("text/plain") { "string" }
# string
#
# Content-Length: 6
# Content-Type: text/html
cgi.out{ "string" }
cgi = CGI.new
Example:
content is converted to this charset, and the language is set to "ja".
If the charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then the
is output (the content block is still required, but it is ignored).
If ENV['REQUEST_METHOD'] == "HEAD", then only the header
the String returned by the content block.
Content-Length is automatically calculated from the size of
A block is required and should evaluate to the body of the response.
+block+::
This is a Hash of headers, similar to that used by #http_header.
+headers_hash+::
If a string is passed, it is assumed to be the content type.
+content_type_string+::
cgi.out(headers_hash)
cgi.out(content_type_string='text/html')
:call-seq:
Print an HTTP header and body to $DEFAULT_OUTPUT ($>)
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
def print(*options)
cgi = CGI.new
Print an argument or list of arguments to the default output stream
def print(*options) stdoutput.print(*options) end
def stdinput
def stdinput $stdin end
def stdoutput
def stdoutput $stdout end