Class: CGI

Inherits:
Object
  • Object
show all
Defined in:
lib/laser/standard_library/cgi/html.rb,
lib/laser/standard_library/cgi/core.rb,
lib/laser/standard_library/cgi/util.rb,
lib/laser/standard_library/cgi/cookie.rb,
lib/laser/standard_library/cgi/session.rb,
lib/laser/standard_library/cgi/session/pstore.rb

Overview

Class representing an HTTP cookie.

In addition to its specific fields and methods, a Cookie instance is a delegator to the array of its values.

See RFC 2965.

Examples of use

cookie1 = CGI::Cookie::new("name", "value1", "value2", ...)
cookie1 = CGI::Cookie::new("name" => "name", "value" => "value")
cookie1 = CGI::Cookie::new('name'    => 'name',
                           'value'   => ['value1', 'value2', ...],
                           'path'    => 'path',   # optional
                           'domain'  => 'domain', # optional
                           'expires' => Time.now, # optional
                           'secure'  => true      # optional
                          )

cgi.out("cookie" => [cookie1, cookie2]) { "string" }

name    = cookie1.name
values  = cookie1.value
path    = cookie1.path
domain  = cookie1.domain
expires = cookie1.expires
secure  = cookie1.secure

cookie1.name    = 'name'
cookie1.value   = ['value1', 'value2', ...]
cookie1.path    = 'path'
cookie1.domain  = 'domain'
cookie1.expires = Time.now + 30
cookie1.secure  = true

Defined Under Namespace

Modules: Html3, Html4, Html4Fr, Html4Tr, HtmlExtension, QueryExtension, TagMaker Classes: Cookie, InvalidEncoding, Session

Constant Summary

CR =

String for carriage return

"\015"
LF =

String for linefeed

"\012"
EOL =

Standard internet newline sequence

CR + LF
REVISION =

:nodoc:

'$Id: core.rb 27581 2010-05-01 23:54:39Z nobu $'
NEEDS_BINMODE =
File::BINARY != 0
PATH_SEPARATOR =

Path separators in different environments.

{'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
HTTP_STATUS =

HTTP status codes.

{
  "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"
}
MAX_MULTIPART_LENGTH =

Maximum content length of multipart data

128 * 1024 * 1024
MAX_MULTIPART_COUNT =

Maximum number of request parameters when multipart

128
TABLE_FOR_ESCAPE_HTML__ =
{
  '&' => '&',
  '"' => '"',
  '<' => '&lt;',
  '>' => '&gt;',
}
RFC822_DAYS =

Abbreviated day-of-week names specified by RFC 822

%w[ Sun Mon Tue Wed Thu Fri Sat ]
RFC822_MONTHS =

Abbreviated month names specified by RFC 822

%w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
@@accept_charset =

@@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"
"UTF-8"

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (CGI) initialize(options = {}, &block)



742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
# File 'lib/laser/standard_library/cgi/core.rb', line 742

def initialize(options = {},&block)
  @accept_charset_error_block=block if block_given?
  @options={accept_charset:@@accept_charset}
  case options
  when Hash
    @options.merge!(options)
  when String
    @options[:tag_maker]=options
  end
  @accept_charset=@options[:accept_charset]
  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
    element_init()
    extend HtmlExtension
  when "html4"
    require 'cgi/html'
    extend Html4
    element_init()
    extend HtmlExtension
  when "html4Tr"
    require 'cgi/html'
    extend Html4Tr
    element_init()
    extend HtmlExtension
  when "html4Fr"
    require 'cgi/html'
    extend Html4Tr
    element_init()
    extend Html4Fr
    element_init()
    extend HtmlExtension
  end
end

Instance Attribute Details

- (Object) accept_charset (readonly)

Create a new CGI instance.

CGI accept constructor parameters either in a hash, string as a block. But string is as same as using :tag_maker of hash.

CGI.new("html3") #=>  CGI.new(:tag_maker=>"html3")

And, if you specify string, @accept_charset cannot be changed. Instead, please use hash parameter.

accept_charset

:accept_charset specifies encoding of received query string. ( Default value is @@accept_charset. ) If not valid, raise CGI::InvalidEncoding

Example. Suppose @@accept_charset # => “UTF-8”

when not specified:

cgi=CGI.new      # @accept_charset # => "UTF-8"

when specified “EUC-JP”:

cgi=CGI.new(:accept_charset => "EUC-JP") # => "EUC-JP"

block

When you use a block, you can write a process that query encoding is invalid. Example:

encoding_error={}
cgi=CGI.new(:accept_charset=>"EUC-JP") do |name,value|
  encoding_error[key] = value
end

tag_maker

:tag_maker specifies which version of HTML to load the HTML generation methods for. The following versions of HTML are supported:

html3

HTML 3.x

html4

HTML 4.0

html4Tr

HTML 4.0 Transitional

html4Fr

HTML 4.0 with Framesets

If not specified, no HTML generation methods will be loaded.

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. It works this:

CGI.new(:tag_maker=>"html3")

This will be obsolete:

CGI.new("html3")


741
742
743
# File 'lib/laser/standard_library/cgi/core.rb', line 741

def accept_charset
  @accept_charset
end

Class Method Details

+ (Object) accept_charset



672
673
674
# File 'lib/laser/standard_library/cgi/core.rb', line 672

def self.accept_charset
  @@accept_charset
end

+ (Object) accept_charset=(accept_charset)



676
677
678
# File 'lib/laser/standard_library/cgi/core.rb', line 676

def self.accept_charset=(accept_charset)
  @@accept_charset=accept_charset
end

+ (Object) escape(string)

URL-encode a string.

url_encoded_string = CGI::escape("'Stop!' said Fred")
   # => "%27Stop%21%27+said+Fred"


6
7
8
9
10
# File 'lib/laser/standard_library/cgi/util.rb', line 6

def CGI::escape(string)
  string.gsub(/([^ a-zA-Z0-9_.-]+)/) do
    '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
  end.tr(' ', '+')
end

+ (Object) escape_element(str)



137
138
139
# File 'lib/laser/standard_library/cgi/util.rb', line 137

def CGI::escape_element(str)
  escapeElement(str)
end

+ (Object) escape_html(str)



86
87
88
# File 'lib/laser/standard_library/cgi/util.rb', line 86

def CGI::escape_html(str)
  escapeHTML(str)
end

+ (Object) escapeElement(string, *elements)

Escape only the tags of certain HTML elements in string.

Takes an element or elements or array of elements. Each element is specified by the name of the element, without angle brackets. This matches both the start and the end tag of that element. The attribute list of the open tag will also be escaped (for instance, the double-quotes surrounding attribute values).

print CGI::escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
  # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"

print CGI::escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
  # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"


106
107
108
109
110
111
112
113
114
115
# File 'lib/laser/standard_library/cgi/util.rb', line 106

def CGI::escapeElement(string, *elements)
  elements = elements[0] if elements[0].kind_of?(Array)
  unless elements.empty?
    string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) do
      CGI::escapeHTML($&)
    end
  else
    string
  end
end

+ (Object) escapeHTML(string)

Escape special characters in HTML, namely &"<>

CGI::escapeHTML('Usage: foo "bar" <baz>')
   # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"


33
34
35
# File 'lib/laser/standard_library/cgi/util.rb', line 33

def CGI::escapeHTML(string)
  string.gsub(/[&\"<>]/, TABLE_FOR_ESCAPE_HTML__)
end

+ (Object) parse(query)

Parse an HTTP query string into a hash of key=>value pairs.

params = CGI::parse("query_string")
  # {"name1" => ["value1", "value2", ...],
  #  "name2" => ["value1", "value2", ...], ... }


330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/laser/standard_library/cgi/core.rb', line 330

def CGI::parse(query)
  params = {}
  query.split(/[&;]/).each do |pairs|
    key, value = pairs.split('=',2).collect{|v| CGI::unescape(v) }
    if key && value
      params.has_key?(key) ? params[key].push(value) : params[key] = [value]
    elsif key
      params[key]=[]
    end
  end
  params.default=[].freeze
  params
end

+ (Object) pretty(string, shift = " ")

Prettify (indent) an HTML string.

string is the HTML string to indent. shift is the indentation unit to use; it defaults to two spaces.

print CGI::pretty("<HTML><BODY></BODY></HTML>")
  # <HTML>
  #   <BODY>
  #   </BODY>
  # </HTML>

print CGI::pretty("<HTML><BODY></BODY></HTML>", "\t")
  # <HTML>
  #         <BODY>
  #         </BODY>
  # </HTML>


178
179
180
181
182
183
184
185
186
187
# File 'lib/laser/standard_library/cgi/util.rb', line 178

def CGI::pretty(string, shift = "  ")
  lines = string.gsub(/(?!\A)<.*?>/m, "\n\\0").gsub(/<.*?>(?!\n)/m, "\\0\n")
  end_pos = 0
  while end_pos = lines.index(/^<\/(\w+)/, end_pos)
    element = $1.dup
    start_pos = lines.rindex(/^\s*<#{element}/i, end_pos)
    lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/, "\n" + shift) + "__"
  end
  lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/, '\1')
end

+ (Object) rfc1123_date(time)

Format a Time object as a String using the format specified by RFC 1123.

CGI::rfc1123_date(Time.now)
  # Sat, 01 Jan 2000 00:00:00 GMT


154
155
156
157
158
159
# File 'lib/laser/standard_library/cgi/util.rb', line 154

def CGI::rfc1123_date(time)
  t = time.clone.gmtime
  return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
              RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
              t.hour, t.min, t.sec)
end

+ (Object) unescape(string, encoding = @@accept_charset)

URL-decode a string with encoding(optional).

string = CGI::unescape("%27Stop%21%27+said+Fred")
   # => "'Stop!' said Fred"


16
17
18
19
20
21
# File 'lib/laser/standard_library/cgi/util.rb', line 16

def CGI::unescape(string,encoding=@@accept_charset)
  str=string.tr('+', ' ').force_encoding(Encoding::ASCII_8BIT).gsub(/((?:%[0-9a-fA-F]{2})+)/) do
    [$1.delete('%')].pack('H*')
  end.force_encoding(encoding)
  str.valid_encoding? ? str : str.force_encoding(string.encoding)
end

+ (Object) unescape_element(str)



140
141
142
# File 'lib/laser/standard_library/cgi/util.rb', line 140

def CGI::unescape_element(str)
  unescapeElement(str)
end

+ (Object) unescape_html(str)



89
90
91
# File 'lib/laser/standard_library/cgi/util.rb', line 89

def CGI::unescape_html(str)
  unescapeHTML(str)
end

+ (Object) unescapeElement(string, *elements)

Undo escaping such as that done by CGI::escapeElement()

print CGI::unescapeElement(
        CGI::escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
  # "&lt;BR&gt;<A HREF="url"></A>"

print CGI::unescapeElement(
        CGI::escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
  # "&lt;BR&gt;<A HREF="url"></A>"


127
128
129
130
131
132
133
134
135
136
# File 'lib/laser/standard_library/cgi/util.rb', line 127

def CGI::unescapeElement(string, *elements)
  elements = elements[0] if elements[0].kind_of?(Array)
  unless elements.empty?
    string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/i) do
      CGI::unescapeHTML($&)
    end
  else
    string
  end
end

+ (Object) unescapeHTML(string)

Unescape a string that has been HTML-escaped

CGI::unescapeHTML("Usage: foo &quot;bar&quot; &lt;baz&gt;")
   # => "Usage: foo \"bar\" <baz>"


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/laser/standard_library/cgi/util.rb', line 41

def CGI::unescapeHTML(string)
  enc = string.encoding
  if [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE].include?(enc)
    return string.gsub(Regexp.new('&(amp|quot|gt|lt|#[0-9]+|#x[0-9A-Fa-f]+);'.encode(enc))) do
      case $1.encode("US-ASCII")
      when 'amp'                 then '&'.encode(enc)
      when 'quot'                then '"'.encode(enc)
      when 'gt'                  then '>'.encode(enc)
      when 'lt'                  then '<'.encode(enc)
      when /\A#0*(\d+)\z/        then $1.to_i.chr(enc)
      when /\A#x([0-9a-f]+)\z/i  then $1.hex.chr(enc)
      end
    end
  end
  asciicompat = Encoding.compatible?(string, "a")
  string.gsub(/&(amp|quot|gt|lt|\#[0-9]+|\#x[0-9A-Fa-f]+);/) do
    match = $1.dup
    case match
    when 'amp'                 then '&'
    when 'quot'                then '"'
    when 'gt'                  then '>'
    when 'lt'                  then '<'
    when /\A#0*(\d+)\z/
      n = $1.to_i
      if enc == Encoding::UTF_8 or
        enc == Encoding::ISO_8859_1 && n < 256 or
        asciicompat && n < 128
        n.chr(enc)
      else
        "&##{$1};"
      end
    when /\A#x([0-9a-f]+)\z/i
      n = $1.hex
      if enc == Encoding::UTF_8 or
        enc == Encoding::ISO_8859_1 && n < 256 or
        asciicompat && n < 128
        n.chr(enc)
      else
        "&#x#{$1};"
      end
    else
      "&#{match};"
    end
  end
end

Instance Method Details

- (Object) header(options = 'text/html')

Create an HTTP header block as a string.

Includes the empty line that ends the header block.

options can be a string specifying the Content-Type (defaults to text/html), or a hash of header key/value pairs. 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, returned as the Status header. See the list of available status codes below.

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 header lines can also be set; they are appended as key: value.

header
  # Content-Type: text/html

header("text/plain")
  # Content-Type: text/plain

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")

The status codes 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"

This method does not perform charset conversion.



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/laser/standard_library/cgi/core.rb', line 136

def 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

- (Boolean) nph?

:nodoc:



231
232
233
# File 'lib/laser/standard_library/cgi/core.rb', line 231

def nph?  #:nodoc:
  return /IIS\/(\d+)/.match($CGI_ENV['SERVER_SOFTWARE']) && $1.to_i < 5
end

- (Object) out(options = "text/html")

Print an HTTP header and body to $DEFAULT_OUTPUT ($>)

The header is provided by options, as for #header(). The body of the document is that returned by the passed- in block. This block takes no arguments. It is required.

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" }

Content-Length is automatically calculated from the size of the String returned by the content block.

If ENV == “HEAD”, then only the header is outputted (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”.



304
305
306
307
308
309
310
311
312
313
# File 'lib/laser/standard_library/cgi/core.rb', line 304

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 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


320
321
322
# File 'lib/laser/standard_library/cgi/core.rb', line 320

def print(*options)
  stdoutput.print(*options)
end