Removed CGI library without CGI::Escape features

This commit is contained in:
Hiroshi SHIBATA 2025-05-08 19:21:47 +09:00
parent a61f51f66d
commit 600c616507
Notes: git 2025-05-09 05:27:42 +00:00
19 changed files with 0 additions and 4973 deletions

View File

@ -1,298 +0,0 @@
# frozen_string_literal: true
#
# cgi.rb - cgi support library
#
# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
#
# Copyright (C) 2000 Information-technology Promotion Agency, Japan
#
# Author: Wakou Aoyama <wakou@ruby-lang.org>
#
# Documentation: Wakou Aoyama (RDoc'd and embellished by William Webber)
#
# == Overview
#
# The Common Gateway Interface (CGI) is a simple protocol for passing an HTTP
# request from a web server to a standalone program, and returning the output
# to the web browser. Basically, a CGI program is called with the parameters
# of the request passed in either in the environment (GET) or via $stdin
# (POST), and everything it prints to $stdout is returned to the client.
#
# This file holds the CGI class. This class provides functionality for
# retrieving HTTP request parameters, managing cookies, and generating HTML
# output.
#
# The file CGI::Session provides session management functionality; see that
# class for more details.
#
# See http://www.w3.org/CGI/ for more information on the CGI protocol.
#
# == Introduction
#
# CGI is a large class, providing several categories of methods, many of which
# are mixed in from other modules. Some of the documentation is in this class,
# some in the modules CGI::QueryExtension and CGI::HtmlExtension. See
# CGI::Cookie for specific information on handling cookies, and cgi/session.rb
# (CGI::Session) for information on sessions.
#
# For queries, CGI provides methods to get at environmental variables,
# parameters, cookies, and multipart request data. For responses, CGI provides
# methods for writing output and generating HTML.
#
# Read on for more details. Examples are provided at the bottom.
#
# == Queries
#
# The CGI class dynamically mixes in parameter and cookie-parsing
# functionality, environmental variable access, and support for
# parsing multipart requests (including uploaded files) from the
# CGI::QueryExtension module.
#
# === Environmental Variables
#
# The standard CGI environmental variables are available as read-only
# attributes of a CGI object. The following is a list of these variables:
#
#
# AUTH_TYPE HTTP_HOST REMOTE_IDENT
# CONTENT_LENGTH HTTP_NEGOTIATE REMOTE_USER
# CONTENT_TYPE HTTP_PRAGMA REQUEST_METHOD
# GATEWAY_INTERFACE HTTP_REFERER SCRIPT_NAME
# HTTP_ACCEPT HTTP_USER_AGENT SERVER_NAME
# HTTP_ACCEPT_CHARSET PATH_INFO SERVER_PORT
# HTTP_ACCEPT_ENCODING PATH_TRANSLATED SERVER_PROTOCOL
# HTTP_ACCEPT_LANGUAGE QUERY_STRING SERVER_SOFTWARE
# HTTP_CACHE_CONTROL REMOTE_ADDR
# HTTP_FROM REMOTE_HOST
#
#
# For each of these variables, there is a corresponding attribute with the
# same name, except all lower case and without a preceding HTTP_.
# +content_length+ and +server_port+ are integers; the rest are strings.
#
# === Parameters
#
# The method #params() returns a hash of all parameters in the request as
# name/value-list pairs, where the value-list is an Array of one or more
# values. The CGI object itself also behaves as a hash of parameter names
# to values, but only returns a single value (as a String) for each
# parameter name.
#
# For instance, suppose the request contains the parameter
# "favourite_colours" with the multiple values "blue" and "green". The
# following behavior would occur:
#
# cgi.params["favourite_colours"] # => ["blue", "green"]
# cgi["favourite_colours"] # => "blue"
#
# If a parameter does not exist, the former method will return an empty
# array, the latter an empty string. The simplest way to test for existence
# of a parameter is by the #has_key? method.
#
# === Cookies
#
# HTTP Cookies are automatically parsed from the request. They are available
# from the #cookies() accessor, which returns a hash from cookie name to
# CGI::Cookie object.
#
# === Multipart requests
#
# If a request's method is POST and its content type is multipart/form-data,
# then it may contain uploaded files. These are stored by the QueryExtension
# module in the parameters of the request. The parameter name is the name
# attribute of the file input field, as usual. However, the value is not
# a string, but an IO object, either an IOString for small files, or a
# Tempfile for larger ones. This object also has the additional singleton
# methods:
#
# #local_path():: the path of the uploaded file on the local filesystem
# #original_filename():: the name of the file on the client computer
# #content_type():: the content type of the file
#
# == Responses
#
# The CGI class provides methods for sending header and content output to
# the HTTP client, and mixes in methods for programmatic HTML generation
# from CGI::HtmlExtension and CGI::TagMaker modules. The precise version of HTML
# to use for HTML generation is specified at object creation time.
#
# === Writing output
#
# The simplest way to send output to the HTTP client is using the #out() method.
# This takes the HTTP headers as a hash parameter, and the body content
# via a block. The headers can be generated as a string using the #http_header()
# method. The output stream can be written directly to using the #print()
# method.
#
# === Generating HTML
#
# Each HTML element has a corresponding method for generating that
# element as a String. The name of this method is the same as that
# of the element, all lowercase. The attributes of the element are
# passed in as a hash, and the body as a no-argument block that evaluates
# to a String. The HTML generation module knows which elements are
# always empty, and silently drops any passed-in body. It also knows
# which elements require matching closing tags and which don't. However,
# it does not know what attributes are legal for which elements.
#
# There are also some additional HTML generation methods mixed in from
# the CGI::HtmlExtension module. These include individual methods for the
# different types of form inputs, and methods for elements that commonly
# take particular attributes where the attributes can be directly specified
# as arguments, rather than via a hash.
#
# === Utility HTML escape and other methods like a function.
#
# There are some utility tool defined in cgi/util.rb .
# And when include, you can use utility methods like a function.
#
# == Examples of use
#
# === Get form values
#
# require "cgi"
# cgi = CGI.new
# value = cgi['field_name'] # <== value string for 'field_name'
# # if not 'field_name' included, then return "".
# fields = cgi.keys # <== array of field names
#
# # returns true if form has 'field_name'
# cgi.has_key?('field_name')
# cgi.has_key?('field_name')
# cgi.include?('field_name')
#
# CAUTION! <code>cgi['field_name']</code> returned an Array with the old
# cgi.rb(included in Ruby 1.6)
#
# === Get form values as hash
#
# require "cgi"
# cgi = CGI.new
# params = cgi.params
#
# cgi.params is a hash.
#
# cgi.params['new_field_name'] = ["value"] # add new param
# cgi.params['field_name'] = ["new_value"] # change value
# cgi.params.delete('field_name') # delete param
# cgi.params.clear # delete all params
#
#
# === Save form values to file
#
# require "pstore"
# db = PStore.new("query.db")
# db.transaction do
# db["params"] = cgi.params
# end
#
#
# === Restore form values from file
#
# require "pstore"
# db = PStore.new("query.db")
# db.transaction do
# cgi.params = db["params"]
# end
#
#
# === Get multipart form values
#
# require "cgi"
# cgi = CGI.new
# value = cgi['field_name'] # <== value string for 'field_name'
# value.read # <== body of value
# value.local_path # <== path to local file of value
# value.original_filename # <== original filename of value
# value.content_type # <== content_type of value
#
# and value has StringIO or Tempfile class methods.
#
# === Get cookie values
#
# require "cgi"
# cgi = CGI.new
# values = cgi.cookies['name'] # <== array of 'name'
# # if not 'name' included, then return [].
# names = cgi.cookies.keys # <== array of cookie names
#
# and cgi.cookies is a hash.
#
# === Get cookie objects
#
# require "cgi"
# cgi = CGI.new
# for name, cookie in cgi.cookies
# cookie.expires = Time.now + 30
# end
# cgi.out("cookie" => cgi.cookies) {"string"}
#
# cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... }
#
# require "cgi"
# cgi = CGI.new
# cgi.cookies['name'].expires = Time.now + 30
# cgi.out("cookie" => cgi.cookies['name']) {"string"}
#
# === Print http header and html string to $DEFAULT_OUTPUT ($>)
#
# require "cgi"
# cgi = CGI.new("html4") # add HTML generation methods
# cgi.out do
# cgi.html do
# cgi.head do
# cgi.title { "TITLE" }
# end +
# cgi.body do
# cgi.form("ACTION" => "uri") do
# cgi.p do
# cgi.textarea("get_text") +
# cgi.br +
# cgi.submit
# end
# end +
# cgi.pre do
# CGI.escapeHTML(
# "params: #{cgi.params.inspect}\n" +
# "cookies: #{cgi.cookies.inspect}\n" +
# ENV.collect do |key, value|
# "#{key} --> #{value}\n"
# end.join("")
# )
# end
# end
# end
# end
#
# # add HTML generation methods
# CGI.new("html3") # html3.2
# CGI.new("html4") # html4.01 (Strict)
# CGI.new("html4Tr") # html4.01 Transitional
# CGI.new("html4Fr") # html4.01 Frameset
# CGI.new("html5") # html5
#
# === Some utility methods
#
# require 'cgi/util'
# CGI.escapeHTML('Usage: foo "bar" <baz>')
#
#
# === Some utility methods like a function
#
# require 'cgi/util'
# include CGI::Util
# escapeHTML('Usage: foo "bar" <baz>')
# h('Usage: foo "bar" <baz>') # alias
#
#
class CGI
VERSION = "0.4.2"
end
require 'cgi/core'
require 'cgi/cookie'
require 'cgi/util'
require 'cgi/escape'
CGI.autoload(:HtmlExtension, 'cgi/html')

View File

@ -1,43 +0,0 @@
# frozen_string_literal: true
name = File.basename(__FILE__, ".gemspec")
version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
/^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
end rescue nil
end
Gem::Specification.new do |spec|
spec.name = name
spec.version = version
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
spec.summary = %q{Support for the Common Gateway Interface protocol.}
spec.description = %q{Support for the Common Gateway Interface protocol.}
spec.homepage = "https://github.com/ruby/cgi"
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.required_ruby_version = ">= 2.5.0"
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
spec.executables = []
spec.files = [
"COPYING",
"BSDL",
"README.md",
*Dir["lib{.rb,/**/*.rb}", "bin/*"] ]
spec.require_paths = ["lib"]
if Gem::Platform === spec.platform and spec.platform =~ 'java' or RUBY_ENGINE == 'jruby'
spec.platform = 'java'
spec.require_paths << "ext/java/org/jruby/ext/cgi/escape/lib"
spec.files += Dir["ext/java/**/*.{rb}", "lib/cgi/escape.jar"]
else
spec.files += Dir["ext/cgi/**/*.{rb,c,h,sh}", "ext/cgi/escape/depend", "lib/cgi/escape.so"]
spec.extensions = ["ext/cgi/escape/extconf.rb"]
end
end

View File

@ -1,210 +0,0 @@
# frozen_string_literal: true
require_relative 'util'
class CGI
# 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
# 'httponly' => 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
# httponly = cookie1.httponly
#
# cookie1.name = 'name'
# cookie1.value = ['value1', 'value2', ...]
# cookie1.path = 'path'
# cookie1.domain = 'domain'
# cookie1.expires = Time.now + 30
# cookie1.secure = true
# cookie1.httponly = true
class Cookie < Array
@@accept_charset="UTF-8" unless defined?(@@accept_charset)
TOKEN_RE = %r"\A[[!-~]&&[^()<>@,;:\\\"/?=\[\]{}]]+\z"
PATH_VALUE_RE = %r"\A[[ -~]&&[^;]]*\z"
DOMAIN_VALUE_RE = %r"\A\.?(?<label>(?!-)[-A-Za-z0-9]+(?<!-))(?:\.\g<label>)*\z"
# Create a new CGI::Cookie object.
#
# :call-seq:
# Cookie.new(name_string,*value)
# Cookie.new(options_hash)
#
# +name_string+::
# The name of the cookie; in this form, there is no #domain or
# #expiration. The #path is gleaned from the +SCRIPT_NAME+ environment
# variable, and #secure is false.
# <tt>*value</tt>::
# value or list of values of the cookie
# +options_hash+::
# A Hash of options to initialize this Cookie. Possible options are:
#
# name:: the name of the cookie. Required.
# value:: the cookie's value or list of values.
# path:: the path for which this cookie applies. Defaults to
# the value of the +SCRIPT_NAME+ environment variable.
# domain:: the domain for which this cookie applies.
# expires:: the time at which this cookie expires, as a +Time+ object.
# secure:: whether this cookie is a secure cookie or not (default to
# false). Secure cookies are only transmitted to HTTPS
# servers.
# httponly:: whether this cookie is a HttpOnly cookie or not (default to
# false). HttpOnly cookies are not available to javascript.
#
# These keywords correspond to attributes of the cookie object.
def initialize(name = "", *value)
@domain = nil
@expires = nil
if name.kind_of?(String)
self.name = name
self.path = (%r|\A(.*/)| =~ ENV["SCRIPT_NAME"] ? $1 : "")
@secure = false
@httponly = false
return super(value)
end
options = name
unless options.has_key?("name")
raise ArgumentError, "`name' required"
end
self.name = options["name"]
value = Array(options["value"])
# simple support for IE
self.path = options["path"] || (%r|\A(.*/)| =~ ENV["SCRIPT_NAME"] ? $1 : "")
self.domain = options["domain"]
@expires = options["expires"]
@secure = options["secure"] == true
@httponly = options["httponly"] == true
super(value)
end
# Name of this cookie, as a +String+
attr_reader :name
# Set name of this cookie
def name=(str)
if str and !TOKEN_RE.match?(str)
raise ArgumentError, "invalid name: #{str.dump}"
end
@name = str
end
# Path for which this cookie applies, as a +String+
attr_reader :path
# Set path for which this cookie applies
def path=(str)
if str and !PATH_VALUE_RE.match?(str)
raise ArgumentError, "invalid path: #{str.dump}"
end
@path = str
end
# Domain for which this cookie applies, as a +String+
attr_reader :domain
# Set domain for which this cookie applies
def domain=(str)
if str and ((str = str.b).bytesize > 255 or !DOMAIN_VALUE_RE.match?(str))
raise ArgumentError, "invalid domain: #{str.dump}"
end
@domain = str
end
# Time at which this cookie expires, as a +Time+
attr_accessor :expires
# True if this cookie is secure; false otherwise
attr_reader :secure
# True if this cookie is httponly; false otherwise
attr_reader :httponly
# Returns the value or list of values for this cookie.
def value
self
end
# Replaces the value of this cookie with a new value or list of values.
def value=(val)
replace(Array(val))
end
# Set whether the Cookie is a secure cookie or not.
#
# +val+ must be a boolean.
def secure=(val)
@secure = val if val == true or val == false
@secure
end
# Set whether the Cookie is a httponly cookie or not.
#
# +val+ must be a boolean.
def httponly=(val)
@httponly = !!val
end
# Convert the Cookie to its string representation.
def to_s
val = collect{|v| CGI.escape(v) }.join("&")
buf = "#{@name}=#{val}".dup
buf << "; domain=#{@domain}" if @domain
buf << "; path=#{@path}" if @path
buf << "; expires=#{CGI.rfc1123_date(@expires)}" if @expires
buf << "; secure" if @secure
buf << "; HttpOnly" if @httponly
buf
end
# Parse a raw cookie string into a hash of cookie-name=>Cookie
# pairs.
#
# cookies = CGI::Cookie.parse("raw_cookie_string")
# # { "name1" => cookie1, "name2" => cookie2, ... }
#
def self.parse(raw_cookie)
cookies = Hash.new([])
return cookies unless raw_cookie
raw_cookie.split(/;\s?/).each do |pairs|
name, values = pairs.split('=',2)
next unless name and values
values ||= ""
values = values.split('&').collect{|v| CGI.unescape(v,@@accept_charset) }
if cookies.has_key?(name)
cookies[name].concat(values)
else
cookies[name] = Cookie.new(name, *values)
end
end
cookies
end
# A summary of cookie string.
def inspect
"#<CGI::Cookie: #{self.to_s.inspect}>"
end
end # class Cookie
end

View File

@ -1,900 +0,0 @@
# frozen_string_literal: true
#--
# Methods for generating HTML, parsing CGI-related parameters, and
# generating HTTP responses.
#++
class CGI
unless const_defined?(:Escape)
module Escape
@@accept_charset = "UTF-8" # :nodoc:
end
include Escape
extend Escape
end
$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$' #: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 _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
private :_no_crlf_check
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
private :_header_for_string
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
private :_header_for_hash
def nph? #:nodoc:
return /IIS\/(\d+)/ =~ $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|
$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
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 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
# 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.delete_prefix('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.delete_prefix('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 = ''.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 # 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("".b)
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 false unless 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=\"?([^\";,]+)\"?| =~ 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("".b)
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" if false # needed for rdoc?
# 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_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
end # class CGI

File diff suppressed because it is too large Load Diff

View File

@ -1,562 +0,0 @@
# frozen_string_literal: true
#
# cgi/session.rb - session support for cgi scripts
#
# Copyright (C) 2001 Yukihiro "Matz" Matsumoto
# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
# Copyright (C) 2000 Information-technology Promotion Agency, Japan
#
# Author: Yukihiro "Matz" Matsumoto
#
# Documentation: William Webber (william@williamwebber.com)
require 'cgi'
require 'tmpdir'
class CGI
# == Overview
#
# This file provides the CGI::Session class, which provides session
# support for CGI scripts. A session is a sequence of HTTP requests
# and responses linked together and associated with a single client.
# Information associated with the session is stored
# on the server between requests. A session id is passed between client
# and server with every request and response, transparently
# to the user. This adds state information to the otherwise stateless
# HTTP request/response protocol.
#
# == Lifecycle
#
# A CGI::Session instance is created from a CGI object. By default,
# this CGI::Session instance will start a new session if none currently
# exists, or continue the current session for this client if one does
# exist. The +new_session+ option can be used to either always or
# never create a new session. See #new() for more details.
#
# #delete() deletes a session from session storage. It
# does not however remove the session id from the client. If the client
# makes another request with the same id, the effect will be to start
# a new session with the old session's id.
#
# == Setting and retrieving session data.
#
# The Session class associates data with a session as key-value pairs.
# This data can be set and retrieved by indexing the Session instance
# using '[]', much the same as hashes (although other hash methods
# are not supported).
#
# When session processing has been completed for a request, the
# session should be closed using the close() method. This will
# store the session's state to persistent storage. If you want
# to store the session's state to persistent storage without
# finishing session processing for this request, call the update()
# method.
#
# == Storing session state
#
# The caller can specify what form of storage to use for the session's
# data with the +database_manager+ option to CGI::Session::new. The
# following storage classes are provided as part of the standard library:
#
# CGI::Session::FileStore:: stores data as plain text in a flat file. Only
# works with String data. This is the default
# storage type.
# CGI::Session::MemoryStore:: stores data in an in-memory hash. The data
# only persists for as long as the current Ruby
# interpreter instance does.
# CGI::Session::PStore:: stores data in Marshalled format. Provided by
# cgi/session/pstore.rb. Supports data of any type,
# and provides file-locking and transaction support.
#
# Custom storage types can also be created by defining a class with
# the following methods:
#
# new(session, options)
# restore # returns hash of session data.
# update
# close
# delete
#
# Changing storage type mid-session does not work. Note in particular
# that by default the FileStore and PStore session data files have the
# same name. If your application switches from one to the other without
# making sure that filenames will be different
# and clients still have old sessions lying around in cookies, then
# things will break nastily!
#
# == Maintaining the session id.
#
# Most session state is maintained on the server. However, a session
# id must be passed backwards and forwards between client and server
# to maintain a reference to this session state.
#
# The simplest way to do this is via cookies. The CGI::Session class
# provides transparent support for session id communication via cookies
# if the client has cookies enabled.
#
# If the client has cookies disabled, the session id must be included
# as a parameter of all requests sent by the client to the server. The
# CGI::Session class in conjunction with the CGI class will transparently
# add the session id as a hidden input field to all forms generated
# using the CGI#form() HTML generation method. No built-in support is
# provided for other mechanisms, such as URL re-writing. The caller is
# responsible for extracting the session id from the session_id
# attribute and manually encoding it in URLs and adding it as a hidden
# input to HTML forms created by other mechanisms. Also, session expiry
# is not automatically handled.
#
# == Examples of use
#
# === Setting the user's name
#
# require 'cgi'
# require 'cgi/session'
# require 'cgi/session/pstore' # provides CGI::Session::PStore
#
# cgi = CGI.new("html4")
#
# session = CGI::Session.new(cgi,
# 'database_manager' => CGI::Session::PStore, # use PStore
# 'session_key' => '_rb_sess_id', # custom session key
# 'session_expires' => Time.now + 30 * 60, # 30 minute timeout
# 'prefix' => 'pstore_sid_') # PStore option
# if cgi.has_key?('user_name') and cgi['user_name'] != ''
# # coerce to String: cgi[] returns the
# # string-like CGI::QueryExtension::Value
# session['user_name'] = cgi['user_name'].to_s
# elsif !session['user_name']
# session['user_name'] = "guest"
# end
# session.close
#
# === Creating a new session safely
#
# require 'cgi'
# require 'cgi/session'
#
# cgi = CGI.new("html4")
#
# # We make sure to delete an old session if one exists,
# # not just to free resources, but to prevent the session
# # from being maliciously hijacked later on.
# begin
# session = CGI::Session.new(cgi, 'new_session' => false)
# session.delete
# rescue ArgumentError # if no old session
# end
# session = CGI::Session.new(cgi, 'new_session' => true)
# session.close
#
class Session
class NoSession < RuntimeError #:nodoc:
end
# The id of this session.
attr_reader :session_id, :new_session
def Session::callback(dbman) #:nodoc:
Proc.new{
dbman[0].close unless dbman.empty?
}
end
# Create a new session id.
#
# The session id is a secure random number by SecureRandom
# if possible, otherwise an SHA512 hash based upon the time,
# a random number, and a constant string. This routine is
# used internally for automatically generated session ids.
def create_new_id
require 'securerandom'
begin
# by OpenSSL, or system provided entropy pool
session_id = SecureRandom.hex(16)
rescue NotImplementedError
# never happens on modern systems
require 'digest'
d = Digest('SHA512').new
now = Time::now
d.update(now.to_s)
d.update(String(now.usec))
d.update(String(rand(0)))
d.update(String($$))
d.update('foobar')
session_id = d.hexdigest[0, 32]
end
session_id
end
private :create_new_id
# Create a new file to store the session data.
#
# This file will be created if it does not exist, or opened if it
# does.
#
# This path is generated under _tmpdir_ from _prefix_, the
# digested session id, and _suffix_.
#
# +option+ is a hash of options for the initializer. The
# following options are recognised:
#
# tmpdir:: the directory to use for storing the FileStore
# file. Defaults to Dir::tmpdir (generally "/tmp"
# on Unix systems).
# prefix:: the prefix to add to the session id when generating
# the filename for this session's FileStore file.
# Defaults to "cgi_sid_".
# suffix:: the prefix to add to the session id when generating
# the filename for this session's FileStore file.
# Defaults to the empty string.
def new_store_file(option={}) # :nodoc:
dir = option['tmpdir'] || Dir::tmpdir
prefix = option['prefix']
suffix = option['suffix']
require 'digest/md5'
md5 = Digest::MD5.hexdigest(session_id)[0,16]
path = dir+"/"
path << prefix if prefix
path << md5
path << suffix if suffix
if File::exist? path
hash = nil
elsif new_session
hash = {}
else
raise NoSession, "uninitialized session"
end
return path, hash
end
# Create a new CGI::Session object for +request+.
#
# +request+ is an instance of the +CGI+ class (see cgi.rb).
# +option+ is a hash of options for initialising this
# CGI::Session instance. The following options are
# recognised:
#
# session_key:: the parameter name used for the session id.
# Defaults to '_session_id'.
# session_id:: the session id to use. If not provided, then
# it is retrieved from the +session_key+ parameter
# of the request, or automatically generated for
# a new session.
# new_session:: if true, force creation of a new session. If not set,
# a new session is only created if none currently
# exists. If false, a new session is never created,
# and if none currently exists and the +session_id+
# option is not set, an ArgumentError is raised.
# database_manager:: the name of the class providing storage facilities
# for session state persistence. Built-in support
# is provided for +FileStore+ (the default),
# +MemoryStore+, and +PStore+ (from
# cgi/session/pstore.rb). See the documentation for
# these classes for more details.
#
# The following options are also recognised, but only apply if the
# session id is stored in a cookie.
#
# session_expires:: the time the current session expires, as a
# +Time+ object. If not set, the session will terminate
# when the user's browser is closed.
# session_domain:: the hostname domain for which this session is valid.
# If not set, defaults to the hostname of the server.
# session_secure:: if +true+, this session will only work over HTTPS.
# session_path:: the path for which this session applies. Defaults
# to the directory of the CGI script.
#
# +option+ is also passed on to the session storage class initializer; see
# the documentation for each session storage class for the options
# they support.
#
# The retrieved or created session is automatically added to +request+
# as a cookie, and also to its +output_hidden+ table, which is used
# to add hidden input elements to forms.
#
# *WARNING* the +output_hidden+
# fields are surrounded by a <fieldset> tag in HTML 4 generation, which
# is _not_ invisible on many browsers; you may wish to disable the
# use of fieldsets with code similar to the following
# (see https://blade.ruby-lang.org/ruby-list/37805)
#
# cgi = CGI.new("html4")
# class << cgi
# undef_method :fieldset
# end
#
def initialize(request, option={})
@new_session = false
session_key = option['session_key'] || '_session_id'
session_id = option['session_id']
unless session_id
if option['new_session']
session_id = create_new_id
@new_session = true
end
end
unless session_id
if request.key?(session_key)
session_id = request[session_key]
session_id = session_id.read if session_id.respond_to?(:read)
end
unless session_id
session_id, = request.cookies[session_key]
end
unless session_id
unless option.fetch('new_session', true)
raise ArgumentError, "session_key `%s' should be supplied"%session_key
end
session_id = create_new_id
@new_session = true
end
end
@session_id = session_id
dbman = option['database_manager'] || FileStore
begin
@dbman = dbman::new(self, option)
rescue NoSession
unless option.fetch('new_session', true)
raise ArgumentError, "invalid session_id `%s'"%session_id
end
session_id = @session_id = create_new_id unless session_id
@new_session=true
retry
end
request.instance_eval do
@output_hidden = {session_key => session_id} unless option['no_hidden']
@output_cookies = [
Cookie::new("name" => session_key,
"value" => session_id,
"expires" => option['session_expires'],
"domain" => option['session_domain'],
"secure" => option['session_secure'],
"path" =>
if option['session_path']
option['session_path']
elsif ENV["SCRIPT_NAME"]
File::dirname(ENV["SCRIPT_NAME"])
else
""
end)
] unless option['no_cookies']
end
@dbprot = [@dbman]
ObjectSpace::define_finalizer(self, Session::callback(@dbprot))
end
# Retrieve the session data for key +key+.
def [](key)
@data ||= @dbman.restore
@data[key]
end
# Set the session data for key +key+.
def []=(key, val)
@write_lock ||= true
@data ||= @dbman.restore
@data[key] = val
end
# Store session data on the server. For some session storage types,
# this is a no-op.
def update
@dbman.update
end
# Store session data on the server and close the session storage.
# For some session storage types, this is a no-op.
def close
@dbman.close
@dbprot.clear
end
# Delete the session from storage. Also closes the storage.
#
# Note that the session's data is _not_ automatically deleted
# upon the session expiring.
def delete
@dbman.delete
@dbprot.clear
end
# File-based session storage class.
#
# Implements session storage as a flat file of 'key=value' values.
# This storage type only works directly with String values; the
# user is responsible for converting other types to Strings when
# storing and from Strings when retrieving.
class FileStore
# Create a new FileStore instance.
#
# This constructor is used internally by CGI::Session. The
# user does not generally need to call it directly.
#
# +session+ is the session for which this instance is being
# created. The session id must only contain alphanumeric
# characters; automatically generated session ids observe
# this requirement.
#
# +option+ is a hash of options for the initializer. The
# following options are recognised:
#
# tmpdir:: the directory to use for storing the FileStore
# file. Defaults to Dir::tmpdir (generally "/tmp"
# on Unix systems).
# prefix:: the prefix to add to the session id when generating
# the filename for this session's FileStore file.
# Defaults to "cgi_sid_".
# suffix:: the prefix to add to the session id when generating
# the filename for this session's FileStore file.
# Defaults to the empty string.
#
# This session's FileStore file will be created if it does
# not exist, or opened if it does.
def initialize(session, option={})
option = {'prefix' => 'cgi_sid_'}.update(option)
@path, @hash = session.new_store_file(option)
end
# Restore session state from the session's FileStore file.
#
# Returns the session state as a hash.
def restore
unless @hash
@hash = {}
begin
lockf = File.open(@path+".lock", "r")
lockf.flock File::LOCK_SH
f = File.open(@path, 'r')
for line in f
line.chomp!
k, v = line.split('=',2)
@hash[CGI.unescape(k)] = Marshal.restore(CGI.unescape(v))
end
ensure
f&.close
lockf&.close
end
end
@hash
end
# Save session state to the session's FileStore file.
def update
return unless @hash
begin
lockf = File.open(@path+".lock", File::CREAT|File::RDWR, 0600)
lockf.flock File::LOCK_EX
f = File.open(@path+".new", File::CREAT|File::TRUNC|File::WRONLY, 0600)
for k,v in @hash
f.printf "%s=%s\n", CGI.escape(k), CGI.escape(String(Marshal.dump(v)))
end
f.close
File.rename @path+".new", @path
ensure
f&.close
lockf&.close
end
end
# Update and close the session's FileStore file.
def close
update
end
# Close and delete the session's FileStore file.
def delete
File::unlink @path+".lock" rescue nil
File::unlink @path+".new" rescue nil
File::unlink @path rescue nil
end
end
# In-memory session storage class.
#
# Implements session storage as a global in-memory hash. Session
# data will only persist for as long as the Ruby interpreter
# instance does.
class MemoryStore
GLOBAL_HASH_TABLE = {} #:nodoc:
# Create a new MemoryStore instance.
#
# +session+ is the session this instance is associated with.
# +option+ is a list of initialisation options. None are
# currently recognized.
def initialize(session, option=nil)
@session_id = session.session_id
unless GLOBAL_HASH_TABLE.key?(@session_id)
unless session.new_session
raise CGI::Session::NoSession, "uninitialized session"
end
GLOBAL_HASH_TABLE[@session_id] = {}
end
end
# Restore session state.
#
# Returns session data as a hash.
def restore
GLOBAL_HASH_TABLE[@session_id]
end
# Update session state.
#
# A no-op.
def update
# don't need to update; hash is shared
end
# Close session storage.
#
# A no-op.
def close
# don't need to close
end
# Delete the session state.
def delete
GLOBAL_HASH_TABLE.delete(@session_id)
end
end
# Dummy session storage class.
#
# Implements session storage place holder. No actual storage
# will be done.
class NullStore
# Create a new NullStore instance.
#
# +session+ is the session this instance is associated with.
# +option+ is a list of initialisation options. None are
# currently recognised.
def initialize(session, option=nil)
end
# Restore (empty) session state.
def restore
{}
end
# Update session state.
#
# A no-op.
def update
end
# Close session storage.
#
# A no-op.
def close
end
# Delete the session state.
#
# A no-op.
def delete
end
end
end
end

View File

@ -1,91 +0,0 @@
# frozen_string_literal: true
#
# cgi/session/pstore.rb - persistent storage of marshalled session data
#
# Documentation: William Webber (william@williamwebber.com)
#
# == Overview
#
# This file provides the CGI::Session::PStore class, which builds
# persistent of session data on top of the pstore library. See
# cgi/session.rb for more details on session storage managers.
require_relative '../session'
begin
require 'pstore'
rescue LoadError
end
class CGI
class Session
# PStore-based session storage class.
#
# This builds upon the top-level PStore class provided by the
# library file pstore.rb. Session data is marshalled and stored
# in a file. File locking and transaction services are provided.
class PStore
# Create a new CGI::Session::PStore instance
#
# This constructor is used internally by CGI::Session. The
# user does not generally need to call it directly.
#
# +session+ is the session for which this instance is being
# created. The session id must only contain alphanumeric
# characters; automatically generated session ids observe
# this requirement.
#
# +option+ is a hash of options for the initializer. The
# following options are recognised:
#
# tmpdir:: the directory to use for storing the PStore
# file. Defaults to Dir::tmpdir (generally "/tmp"
# on Unix systems).
# prefix:: the prefix to add to the session id when generating
# the filename for this session's PStore file.
# Defaults to the empty string.
#
# This session's PStore file will be created if it does
# not exist, or opened if it does.
def initialize(session, option={})
option = {'suffix'=>''}.update(option)
path, @hash = session.new_store_file(option)
@p = ::PStore.new(path)
@p.transaction do |p|
File.chmod(0600, p.path)
end
end
# Restore session state from the session's PStore file.
#
# Returns the session state as a hash.
def restore
unless @hash
@p.transaction do
@hash = @p['hash'] || {}
end
end
@hash
end
# Save session state to the session's PStore file.
def update
@p.transaction do
@p['hash'] = @hash
end
end
# Update and close the session's PStore file.
def close
update
end
# Close and delete the session's PStore file.
def delete
path = @p.path
File::unlink path
end
end if defined?(::PStore)
end
end
# :enddoc:

View File

@ -1,44 +0,0 @@
# frozen_string_literal: true
class CGI
module Util; end
include Util
extend Util
end
module CGI::Util
# 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
def rfc1123_date(time)
time.getgm.strftime("%a, %d %b %Y %T GMT")
end
# 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>
#
def 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
end

View File

@ -1,211 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'cgi'
require 'stringio'
require_relative 'update_env'
class CGICookieTest < Test::Unit::TestCase
include UpdateEnv
def setup
@environ = {}
update_env(
'REQUEST_METHOD' => 'GET',
'SCRIPT_NAME' => nil,
)
@str1="\xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93".dup
@str1.force_encoding("UTF-8") if defined?(::Encoding)
end
def teardown
ENV.update(@environ)
end
def test_cgi_cookie_new_simple
cookie = CGI::Cookie.new('name1', 'val1', '&<>"', @str1)
assert_equal('name1', cookie.name)
assert_equal(['val1', '&<>"', @str1], cookie.value)
assert_nil(cookie.domain)
assert_nil(cookie.expires)
assert_equal('', cookie.path)
assert_equal(false, cookie.secure)
assert_equal(false, cookie.httponly)
assert_equal("name1=val1&%26%3C%3E%22&%E3%82%86%E3%82%93%E3%82%86%E3%82%93; path=", cookie.to_s)
end
def test_cgi_cookie_new_complex
t = Time.gm(2030, 12, 31, 23, 59, 59)
value = ['val1', '&<>"', "\xA5\xE0\xA5\xB9\xA5\xAB".dup]
value[2].force_encoding("EUC-JP") if defined?(::Encoding)
cookie = CGI::Cookie.new('name'=>'name1',
'value'=>value,
'path'=>'/cgi-bin/myapp/',
'domain'=>'www.example.com',
'expires'=>t,
'secure'=>true,
'httponly'=>true
)
assert_equal('name1', cookie.name)
assert_equal(value, cookie.value)
assert_equal('www.example.com', cookie.domain)
assert_equal(t, cookie.expires)
assert_equal('/cgi-bin/myapp/', cookie.path)
assert_equal(true, cookie.secure)
assert_equal(true, cookie.httponly)
assert_equal('name1=val1&%26%3C%3E%22&%A5%E0%A5%B9%A5%AB; domain=www.example.com; path=/cgi-bin/myapp/; expires=Tue, 31 Dec 2030 23:59:59 GMT; secure; HttpOnly', cookie.to_s)
end
def test_cgi_cookie_new_with_domain
h = {'name'=>'name1', 'value'=>'value1'}
cookie = CGI::Cookie.new(h.merge('domain'=>'a.example.com'))
assert_equal('a.example.com', cookie.domain)
cookie = CGI::Cookie.new(h.merge('domain'=>'.example.com'))
assert_equal('.example.com', cookie.domain)
cookie = CGI::Cookie.new(h.merge('domain'=>'1.example.com'))
assert_equal('1.example.com', cookie.domain, 'enhanced by RFC 1123')
assert_raise(ArgumentError) {
CGI::Cookie.new(h.merge('domain'=>'-a.example.com'))
}
assert_raise(ArgumentError) {
CGI::Cookie.new(h.merge('domain'=>'a-.example.com'))
}
end
def test_cgi_cookie_scriptname
cookie = CGI::Cookie.new('name1', 'value1')
assert_equal('', cookie.path)
cookie = CGI::Cookie.new('name'=>'name1', 'value'=>'value1')
assert_equal('', cookie.path)
## when ENV['SCRIPT_NAME'] is set, cookie.path is set automatically
ENV['SCRIPT_NAME'] = '/cgi-bin/app/example.cgi'
cookie = CGI::Cookie.new('name1', 'value1')
assert_equal('/cgi-bin/app/', cookie.path)
cookie = CGI::Cookie.new('name'=>'name1', 'value'=>'value1')
assert_equal('/cgi-bin/app/', cookie.path)
end
def test_cgi_cookie_parse
## ';' separator
cookie_str = 'name1=val1&val2; name2=val2&%26%3C%3E%22&%E3%82%86%E3%82%93%E3%82%86%E3%82%93;_session_id=12345'
cookies = CGI::Cookie.parse(cookie_str)
list = [
['name1', ['val1', 'val2']],
['name2', ['val2', '&<>"',@str1]],
['_session_id', ['12345']],
]
list.each do |name, value|
cookie = cookies[name]
assert_equal(name, cookie.name)
assert_equal(value, cookie.value)
end
## don't allow ',' separator
cookie_str = 'name1=val1&val2, name2=val2'
cookies = CGI::Cookie.parse(cookie_str)
list = [
['name1', ['val1', 'val2, name2=val2']],
]
list.each do |name, value|
cookie = cookies[name]
assert_equal(name, cookie.name)
assert_equal(value, cookie.value)
end
end
def test_cgi_cookie_parse_not_decode_name
cookie_str = "%66oo=baz;foo=bar"
cookies = CGI::Cookie.parse(cookie_str)
assert_equal({"%66oo" => ["baz"], "foo" => ["bar"]}, cookies)
end
def test_cgi_cookie_arrayinterface
cookie = CGI::Cookie.new('name1', 'a', 'b', 'c')
assert_equal('a', cookie[0])
assert_equal('c', cookie[2])
assert_nil(cookie[3])
assert_equal('a', cookie.first)
assert_equal('c', cookie.last)
assert_equal(['A', 'B', 'C'], cookie.collect{|e| e.upcase})
end
def test_cgi_cookie_domain_injection_into_name
name = "a=b; domain=example.com;"
path = "/"
domain = "example.jp"
assert_raise(ArgumentError) do
CGI::Cookie.new('name' => name,
'value' => "value",
'domain' => domain,
'path' => path)
end
end
def test_cgi_cookie_newline_injection_into_name
name = "a=b;\r\nLocation: http://example.com#"
path = "/"
domain = "example.jp"
assert_raise(ArgumentError) do
CGI::Cookie.new('name' => name,
'value' => "value",
'domain' => domain,
'path' => path)
end
end
def test_cgi_cookie_multibyte_injection_into_name
name = "a=b;\u3042"
path = "/"
domain = "example.jp"
assert_raise(ArgumentError) do
CGI::Cookie.new('name' => name,
'value' => "value",
'domain' => domain,
'path' => path)
end
end
def test_cgi_cookie_injection_into_path
name = "name"
path = "/; samesite=none"
domain = "example.jp"
assert_raise(ArgumentError) do
CGI::Cookie.new('name' => name,
'value' => "value",
'domain' => domain,
'path' => path)
end
end
def test_cgi_cookie_injection_into_domain
name = "name"
path = "/"
domain = "example.jp; samesite=none"
assert_raise(ArgumentError) do
CGI::Cookie.new('name' => name,
'value' => "value",
'domain' => domain,
'path' => path)
end
end
instance_methods.each do |method|
private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
end if ENV['TEST']
end

View File

@ -1,307 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'cgi'
require 'stringio'
require_relative 'update_env'
class CGICoreTest < Test::Unit::TestCase
include UpdateEnv
def setup
@environ = {}
#@environ = {
# 'SERVER_PROTOCOL' => 'HTTP/1.1',
# 'REQUEST_METHOD' => 'GET',
# 'SERVER_SOFTWARE' => 'Apache 2.2.0',
#}
#ENV.update(@environ)
end
def teardown
ENV.update(@environ)
$stdout = STDOUT
end
def test_cgi_parse_illegal_query
update_env(
'REQUEST_METHOD' => 'GET',
'QUERY_STRING' => 'a=111&&b=222&c&d=',
'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
cgi = CGI.new
assert_equal(["a","b","c","d"],cgi.keys.sort)
assert_equal("",cgi["d"])
end
def test_cgi_core_params_GET
update_env(
'REQUEST_METHOD' => 'GET',
'QUERY_STRING' => 'id=123&id=456&id=&id&str=%40h+%3D%7E+%2F%5E%24%2F',
'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
cgi = CGI.new
## cgi[]
assert_equal('123', cgi['id'])
assert_equal('@h =~ /^$/', cgi['str'])
## cgi.params
assert_equal(['123', '456', ''], cgi.params['id'])
assert_equal(['@h =~ /^$/'], cgi.params['str'])
## cgi.keys
assert_equal(['id', 'str'], cgi.keys.sort)
## cgi.key?, cgi.has_key?, cgi.include?
assert_equal(true, cgi.key?('id'))
assert_equal(true, cgi.has_key?('id'))
assert_equal(true, cgi.include?('id'))
assert_equal(false, cgi.key?('foo'))
assert_equal(false, cgi.has_key?('foo'))
assert_equal(false, cgi.include?('foo'))
## invalid parameter name
assert_equal('', cgi['*notfound*']) # [ruby-dev:30740]
assert_equal([], cgi.params['*notfound*'])
end
def test_cgi_core_params_POST
query_str = 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F'
update_env(
'REQUEST_METHOD' => 'POST',
'CONTENT_LENGTH' => query_str.length.to_s,
'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
$stdin = StringIO.new
$stdin << query_str
$stdin.rewind
cgi = CGI.new
## cgi[]
assert_equal('123', cgi['id'])
assert_equal('@h =~ /^$/', cgi['str'])
## cgi.params
assert_equal(['123', '456', ''], cgi.params['id'])
assert_equal(['@h =~ /^$/'], cgi.params['str'])
## invalid parameter name
assert_equal('', cgi['*notfound*'])
assert_equal([], cgi.params['*notfound*'])
ensure
$stdin = STDIN
end
def test_cgi_core_params_encoding_check
query_str = 'str=%BE%BE%B9%BE'
update_env(
'REQUEST_METHOD' => 'POST',
'CONTENT_LENGTH' => query_str.length.to_s,
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
$stdin = StringIO.new
$stdin << query_str
$stdin.rewind
if defined?(::Encoding)
hash={}
cgi = CGI.new(:accept_charset=>"UTF-8"){|key,val|hash[key]=val}
## cgi[]
assert_equal("\xBE\xBE\xB9\xBE".dup.force_encoding("UTF-8"), cgi['str'])
## cgi.params
assert_equal(["\xBE\xBE\xB9\xBE".dup.force_encoding("UTF-8")], cgi.params['str'])
## accept-charset error
assert_equal({"str"=>"\xBE\xBE\xB9\xBE".dup.force_encoding("UTF-8")},hash)
$stdin.rewind
assert_raise(CGI::InvalidEncoding) do
cgi = CGI.new(:accept_charset=>"UTF-8")
end
$stdin.rewind
cgi = CGI.new(:accept_charset=>"EUC-JP")
## cgi[]
assert_equal("\xBE\xBE\xB9\xBE".dup.force_encoding("EUC-JP"), cgi['str'])
## cgi.params
assert_equal(["\xBE\xBE\xB9\xBE".dup.force_encoding("EUC-JP")], cgi.params['str'])
else
assert(true)
end
ensure
$stdin = STDIN
end
def test_cgi_core_cookie
update_env(
'REQUEST_METHOD' => 'GET',
'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
cgi = CGI.new
assert_not_equal(nil,cgi.cookies)
[ ['_session_id', ['12345'], ],
['name1', ['val1', 'val2'], ],
].each do |key, expected|
cookie = cgi.cookies[key]
assert_kind_of(CGI::Cookie, cookie)
assert_equal(expected, cookie.value)
assert_equal(false, cookie.secure)
assert_nil(cookie.expires)
assert_nil(cookie.domain)
assert_equal('', cookie.path)
end
end
def test_cgi_core_maxcontentlength
update_env(
'REQUEST_METHOD' => 'POST',
'CONTENT_LENGTH' => (64 * 1024 * 1024).to_s
)
ex = assert_raise(StandardError) do
CGI.new
end
assert_equal("too large post data.", ex.message)
end if CGI.const_defined?(:MAX_CONTENT_LENGTH)
def test_cgi_core_out
update_env(
'REQUEST_METHOD' => 'GET',
'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
cgi = CGI.new
## euc string
euc_str = "\270\253\244\355\241\242\277\315\244\254\245\264\245\337\244\316\244\350\244\246\244\300"
## utf8 (not converted)
options = { 'charset'=>'utf8' }
$stdout = StringIO.new
cgi.out(options) { euc_str }
assert_nil(options['language'])
actual = $stdout.string
expected = "Content-Type: text/html; charset=utf8\r\n" +
"Content-Length: 22\r\n" +
"\r\n" +
euc_str
if defined?(::Encoding)
actual.force_encoding("ASCII-8BIT")
expected.force_encoding("ASCII-8BIT")
end
assert_equal(expected, actual)
## language is keeped
options = { 'charset'=>'Shift_JIS', 'language'=>'en' }
$stdout = StringIO.new
cgi.out(options) { euc_str }
assert_equal('en', options['language'])
## HEAD method
update_env('REQUEST_METHOD' => 'HEAD')
options = { 'charset'=>'utf8' }
$stdout = StringIO.new
cgi.out(options) { euc_str }
actual = $stdout.string
expected = "Content-Type: text/html; charset=utf8\r\n" +
"Content-Length: 22\r\n" +
"\r\n"
assert_equal(expected, actual)
end
def test_cgi_core_print
update_env(
'REQUEST_METHOD' => 'GET',
)
cgi = CGI.new
$stdout = StringIO.new
str = "foobar"
cgi.print(str)
expected = str
actual = $stdout.string
assert_equal(expected, actual)
end
def test_cgi_core_environs
update_env(
'REQUEST_METHOD' => 'GET',
)
cgi = CGI.new
##
list1 = %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
]
# list2 = %w[ CONTENT_LENGTH SERVER_PORT ]
## string expected
list1.each do |name|
update_env(name => "**#{name}**")
end
list1.each do |name|
method = name.sub(/\AHTTP_/, '').downcase
actual = cgi.__send__ method
expected = "**#{name}**"
assert_equal(expected, actual)
end
## integer expected
update_env('CONTENT_LENGTH' => '123')
update_env('SERVER_PORT' => '8080')
assert_equal(123, cgi.content_length)
assert_equal(8080, cgi.server_port)
## raw cookie
update_env('HTTP_COOKIE' => 'name1=val1')
update_env('HTTP_COOKIE2' => 'name2=val2')
assert_equal('name1=val1', cgi.raw_cookie)
assert_equal('name2=val2', cgi.raw_cookie2)
end
def test_cgi_core_htmltype_header
update_env(
'REQUEST_METHOD' => 'GET',
)
## no htmltype
cgi = CGI.new
assert_raise(NoMethodError) do cgi.doctype end
assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
## html3
cgi = CGI.new('html3')
expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">'
assert_equal(expected, cgi.doctype)
assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
## html4
cgi = CGI.new('html4')
expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
assert_equal(expected, cgi.doctype)
assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
## html4 transitional
cgi = CGI.new('html4Tr')
expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
assert_equal(expected, cgi.doctype)
assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
## html4 frameset
cgi = CGI.new('html4Fr')
expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
assert_equal(expected, cgi.doctype)
assert_equal("Content-Type: text/html\r\n\r\n",cgi.header)
## html5
cgi = CGI.new('html5')
expected = '<!DOCTYPE HTML>'
assert_equal(expected, cgi.doctype)
assert_match(/^<HEADER><\/HEADER>$/i,cgi.header)
end
instance_methods.each do |method|
private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
end if ENV['TEST']
end

View File

@ -1,192 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'cgi'
require 'time'
require_relative 'update_env'
class CGIHeaderTest < Test::Unit::TestCase
include UpdateEnv
def setup
@environ = {}
update_env(
'SERVER_PROTOCOL' => 'HTTP/1.1',
'REQUEST_METHOD' => 'GET',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
)
end
def teardown
ENV.update(@environ)
end
def test_cgi_http_header_simple
cgi = CGI.new
## default content type
expected = "Content-Type: text/html\r\n\r\n"
actual = cgi.http_header
assert_equal(expected, actual)
## content type specified as string
expected = "Content-Type: text/xhtml; charset=utf8\r\n\r\n"
actual = cgi.http_header('text/xhtml; charset=utf8')
assert_equal(expected, actual)
## content type specified as hash
expected = "Content-Type: image/png\r\n\r\n"
actual = cgi.http_header('type'=>'image/png')
assert_equal(expected, actual)
## charset specified
expected = "Content-Type: text/html; charset=utf8\r\n\r\n"
actual = cgi.http_header('charset'=>'utf8')
assert_equal(expected, actual)
end
def test_cgi_http_header_complex
cgi = CGI.new
options = {
'type' => 'text/xhtml',
'charset' => 'utf8',
'status' => 'REDIRECT',
'server' => 'webrick',
'connection' => 'close',
'length' => 123,
'language' => 'ja',
'expires' => Time.gm(2000, 1, 23, 12, 34, 56),
'location' => 'http://www.ruby-lang.org/',
}
expected = "Status: 302 Found\r\n".dup
expected << "Server: webrick\r\n"
expected << "Connection: close\r\n"
expected << "Content-Type: text/xhtml; charset=utf8\r\n"
expected << "Content-Length: 123\r\n"
expected << "Content-Language: ja\r\n"
expected << "Expires: Sun, 23 Jan 2000 12:34:56 GMT\r\n"
expected << "location: http://www.ruby-lang.org/\r\n"
expected << "\r\n"
actual = cgi.http_header(options)
assert_equal(expected, actual)
end
def test_cgi_http_header_argerr
cgi = CGI.new
expected = ArgumentError
assert_raise(expected) do
cgi.http_header(nil)
end
end
def test_cgi_http_header_cookie
cgi = CGI.new
cookie1 = CGI::Cookie.new('name1', 'abc', '123')
cookie2 = CGI::Cookie.new('name'=>'name2', 'value'=>'value2', 'secure'=>true)
ctype = "Content-Type: text/html\r\n"
sep = "\r\n"
c1 = "Set-Cookie: name1=abc&123; path=\r\n"
c2 = "Set-Cookie: name2=value2; path=; secure\r\n"
## CGI::Cookie object
actual = cgi.http_header('cookie'=>cookie1)
expected = ctype + c1 + sep
assert_equal(expected, actual)
## String
actual = cgi.http_header('cookie'=>cookie2.to_s)
expected = ctype + c2 + sep
assert_equal(expected, actual)
## Array
actual = cgi.http_header('cookie'=>[cookie1, cookie2])
expected = ctype + c1 + c2 + sep
assert_equal(expected, actual)
## Hash
actual = cgi.http_header('cookie'=>{'name1'=>cookie1, 'name2'=>cookie2})
expected = ctype + c1 + c2 + sep
assert_equal(expected, actual)
end
def test_cgi_http_header_output_cookies
cgi = CGI.new
## output cookies
cookies = [ CGI::Cookie.new('name1', 'abc', '123'),
CGI::Cookie.new('name'=>'name2', 'value'=>'value2', 'secure'=>true),
]
cgi.instance_variable_set('@output_cookies', cookies)
expected = "Content-Type: text/html; charset=utf8\r\n".dup
expected << "Set-Cookie: name1=abc&123; path=\r\n"
expected << "Set-Cookie: name2=value2; path=; secure\r\n"
expected << "\r\n"
## header when string
actual = cgi.http_header('text/html; charset=utf8')
assert_equal(expected, actual)
## _header_for_string
actual = cgi.http_header('type'=>'text/html', 'charset'=>'utf8')
assert_equal(expected, actual)
end
def test_cgi_http_header_nph
time_start = Time.now.to_i
cgi = CGI.new
## 'nph' is true
ENV['SERVER_SOFTWARE'] = 'Apache 2.2.0'
actual1 = cgi.http_header('nph'=>true)
## when old IIS, NPH-mode is forced
ENV['SERVER_SOFTWARE'] = 'IIS/4.0'
actual2 = cgi.http_header
actual3 = cgi.http_header('status'=>'REDIRECT', 'location'=>'http://www.example.com/')
## newer IIS doesn't require NPH-mode ## [ruby-dev:30537]
ENV['SERVER_SOFTWARE'] = 'IIS/5.0'
actual4 = cgi.http_header
actual5 = cgi.http_header('status'=>'REDIRECT', 'location'=>'http://www.example.com/')
time_end = Time.now.to_i
date = /^Date: ([A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d\d:\d\d:\d\d GMT)\r\n/
[actual1, actual2, actual3].each do |actual|
assert_match(date, actual)
assert_include(time_start..time_end, date =~ actual && Time.parse($1).to_i)
actual.sub!(date, "Date: DATE_IS_REMOVED\r\n")
end
## assertion
expected = "HTTP/1.1 200 OK\r\n".dup
expected << "Date: DATE_IS_REMOVED\r\n"
expected << "Server: Apache 2.2.0\r\n"
expected << "Connection: close\r\n"
expected << "Content-Type: text/html\r\n"
expected << "\r\n"
assert_equal(expected, actual1)
expected.sub!(/^Server: .*?\r\n/, "Server: IIS/4.0\r\n")
assert_equal(expected, actual2)
expected.sub!(/^HTTP\/1.1 200 OK\r\n/, "HTTP/1.1 302 Found\r\n")
expected.sub!(/\r\n\r\n/, "\r\nlocation: http://www.example.com/\r\n\r\n")
assert_equal(expected, actual3)
expected = "Content-Type: text/html\r\n".dup
expected << "\r\n"
assert_equal(expected, actual4)
expected = "Status: 302 Found\r\n".dup
expected << "Content-Type: text/html\r\n"
expected << "location: http://www.example.com/\r\n"
expected << "\r\n"
assert_equal(expected, actual5)
ensure
ENV.delete('SERVER_SOFTWARE')
end
def test_cgi_http_header_crlf_injection
cgi = CGI.new
assert_raise(RuntimeError) { cgi.http_header("text/xhtml\r\nBOO") }
assert_raise(RuntimeError) { cgi.http_header("type" => "text/xhtml\r\nBOO") }
assert_raise(RuntimeError) { cgi.http_header("status" => "200 OK\r\nBOO") }
assert_raise(RuntimeError) { cgi.http_header("location" => "text/xhtml\r\nBOO") }
end
instance_methods.each do |method|
private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
end if ENV['TEST']
end

View File

@ -1,149 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'cgi'
require_relative 'update_env'
class CGIModrubyTest < Test::Unit::TestCase
include UpdateEnv
def setup
@environ = {}
update_env(
'SERVER_PROTOCOL' => 'HTTP/1.1',
'REQUEST_METHOD' => 'GET',
#'QUERY_STRING' => 'a=foo&b=bar',
)
CGI.class_eval { const_set(:MOD_RUBY, true) }
Apache._reset()
#@cgi = CGI.new
#@req = Apache.request
end
def teardown
ENV.update(@environ)
CGI.class_eval { remove_const(:MOD_RUBY) }
end
def test_cgi_modruby_simple
req = Apache.request
cgi = CGI.new
assert(req._setup_cgi_env_invoked?)
assert(! req._send_http_header_invoked?)
actual = cgi.http_header
assert_equal('', actual)
assert_equal('text/html', req.content_type)
assert(req._send_http_header_invoked?)
end
def test_cgi_modruby_complex
req = Apache.request
cgi = CGI.new
options = {
'status' => 'FORBIDDEN',
'location' => 'http://www.example.com/',
'type' => 'image/gif',
'content-encoding' => 'deflate',
'cookie' => [ CGI::Cookie.new('name1', 'abc', '123'),
CGI::Cookie.new('name'=>'name2', 'value'=>'value2', 'secure'=>true),
],
}
assert(req._setup_cgi_env_invoked?)
assert(! req._send_http_header_invoked?)
actual = cgi.http_header(options)
assert_equal('', actual)
assert_equal('image/gif', req.content_type)
assert_equal('403 Forbidden', req.status_line)
assert_equal(403, req.status)
assert_equal('deflate', req.content_encoding)
assert_equal('http://www.example.com/', req.headers_out['location'])
assert_equal(["name1=abc&123; path=", "name2=value2; path=; secure"],
req.headers_out['Set-Cookie'])
assert(req._send_http_header_invoked?)
end
def test_cgi_modruby_location
req = Apache.request
cgi = CGI.new
options = {
'status' => '200 OK',
'location' => 'http://www.example.com/',
}
cgi.http_header(options)
assert_equal('200 OK', req.status_line) # should be '302 Found' ?
assert_equal(302, req.status)
assert_equal('http://www.example.com/', req.headers_out['location'])
end
def test_cgi_modruby_requestparams
req = Apache.request
req.args = 'a=foo&b=bar'
cgi = CGI.new
assert_equal('foo', cgi['a'])
assert_equal('bar', cgi['b'])
end
instance_methods.each do |method|
private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
end if ENV['TEST']
end
## dummy class for mod_ruby
class Apache #:nodoc:
def self._reset
@request = Request.new
end
def self.request
return @request
end
class Request
def initialize
hash = {}
def hash.add(name, value)
(self[name] ||= []) << value
end
@http_header = nil
@headers_out = hash
@status_line = nil
@status = nil
@content_type = nil
@content_encoding = nil
end
attr_accessor :headers_out, :status_line, :status, :content_type, :content_encoding
attr_accessor :args
#def args
# return ENV['QUERY_STRING']
#end
def send_http_header
@http_header = '*invoked*'
end
def _send_http_header_invoked?
@http_header ? true : false
end
def setup_cgi_env
@cgi_env = '*invoked*'
end
def _setup_cgi_env_invoked?
@cgi_env ? true : false
end
end
end

View File

@ -1,385 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'cgi'
require 'tempfile'
require 'stringio'
require_relative 'update_env'
##
## usage:
## boundary = 'foobar1234' # or nil
## multipart = MultiPart.new(boundary)
## multipart.append('name1', 'value1')
## multipart.append('file1', File.read('file1.html'), 'file1.html')
## str = multipart.close()
## str.each_line {|line| p line }
## ## output:
## # "--foobar1234\r\n"
## # "Content-Disposition: form-data: name=\"name1\"\r\n"
## # "\r\n"
## # "value1\r\n"
## # "--foobar1234\r\n"
## # "Content-Disposition: form-data: name=\"file1\"; filename=\"file1.html\"\r\n"
## # "Content-Type: text/html\r\n"
## # "\r\n"
## # "<html>\n"
## # "<body><p>Hello</p></body>\n"
## # "</html>\n"
## # "\r\n"
## # "--foobar1234--\r\n"
##
class MultiPart
def initialize(boundary=nil)
@boundary = boundary || create_boundary()
@buf = ''.dup
@buf.force_encoding(::Encoding::ASCII_8BIT) if defined?(::Encoding)
end
attr_reader :boundary
def append(name, value, filename=nil, content_type=nil)
content_type = detect_content_type(filename) if filename && content_type.nil?
s = filename ? "; filename=\"#{filename}\"" : ''
buf = @buf
buf << "--#{boundary}\r\n"
buf << "Content-Disposition: form-data: name=\"#{name}\"#{s}\r\n"
buf << "Content-Type: #{content_type}\r\n" if content_type
buf << "\r\n"
buf << value.b
buf << "\r\n"
return self
end
def close
buf = @buf
@buf = ''.dup
return buf << "--#{boundary}--\r\n"
end
def create_boundary() #:nodoc:
return "--boundary#{rand().to_s[2..-1]}"
end
def detect_content_type(filename) #:nodoc:
filename =~ /\.(\w+)\z/
return MIME_TYPES[$1] || 'application/octet-stream'
end
MIME_TYPES = {
'gif' => 'image/gif',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'png' => 'image/png',
'bmp' => 'image/bmp',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'htm' => 'text/html',
'html' => 'text/html',
'xml' => 'text/xml',
'txt' => 'text/plain',
'text' => 'text/plain',
'css' => 'text/css',
'mpg' => 'video/mpeg',
'mpeg' => 'video/mpeg',
'mov' => 'video/quicktime',
'avi' => 'video/x-msvideo',
'mp3' => 'audio/mpeg',
'mid' => 'audio/midi',
'wav' => 'audio/x-wav',
'zip' => 'application/zip',
#'tar.gz' => 'application/gtar',
'gz' => 'application/gzip',
'bz2' => 'application/bzip2',
'rtf' => 'application/rtf',
'pdf' => 'application/pdf',
'ps' => 'application/postscript',
'js' => 'application/x-javascript',
'xls' => 'application/vnd.ms-excel',
'doc' => 'application/msword',
'ppt' => 'application/vnd.ms-powerpoint',
}
end
class CGIMultipartTest < Test::Unit::TestCase
include UpdateEnv
def setup
@environ = {}
update_env(
'REQUEST_METHOD' => 'POST',
'CONTENT_TYPE' => nil,
'CONTENT_LENGTH' => nil,
)
@tempfiles = []
end
def teardown
ENV.update(@environ)
$stdin.close() if $stdin.is_a?(Tempfile)
$stdin = STDIN
@tempfiles.each {|t|
t.close!
}
end
def _prepare(data)
## create multipart input
multipart = MultiPart.new(defined?(@boundary) ? @boundary : nil)
data.each do |hash|
multipart.append(hash[:name], hash[:value], hash[:filename])
end
input = multipart.close()
input = yield(input) if block_given?
#$stderr.puts "*** debug: input=\n#{input.collect{|line| line.inspect}.join("\n")}"
@boundary ||= multipart.boundary
## set environment
ENV['CONTENT_TYPE'] = "multipart/form-data; boundary=#{@boundary}"
ENV['CONTENT_LENGTH'] = input.length.to_s
ENV['REQUEST_METHOD'] = 'POST'
## set $stdin
tmpfile = Tempfile.new('test_cgi_multipart')
@tempfiles << tmpfile
tmpfile.binmode
tmpfile << input
tmpfile.rewind()
$stdin = tmpfile
end
def _test_multipart(cgi_options={})
caller(0).find {|s| s =~ /in `test_(.*?)'/ }
#testname = $1
#$stderr.puts "*** debug: testname=#{testname.inspect}"
_prepare(@data)
options = {:accept_charset=>"UTF-8"}
options.merge! cgi_options
cgi = CGI.new(options)
expected_names = @data.collect{|hash| hash[:name] }.sort
assert_equal(expected_names, cgi.params.keys.sort)
threshold = 1024*10
@data.each do |hash|
name = hash[:name]
expected = hash[:value]
if hash[:filename] #if file
expected_class = @expected_class || (hash[:value].length < threshold ? StringIO : Tempfile)
assert(cgi.files.keys.member?(hash[:name]))
else
expected_class = String
assert_equal(expected, cgi[name])
assert_equal(false,cgi.files.keys.member?(hash[:name]))
end
assert_kind_of(expected_class, cgi[name])
assert_equal(expected, cgi[name].read())
assert_equal(hash[:filename] || '', cgi[name].original_filename) #if hash[:filename]
assert_equal(hash[:content_type] || '', cgi[name].content_type) #if hash[:content_type]
end
ensure
if cgi
cgi.params.each {|name, vals|
vals.each {|val|
if val.kind_of?(Tempfile) && val.path
val.close!
end
}
}
end
end
def _read(basename)
filename = File.join(File.dirname(__FILE__), 'testdata', basename)
s = File.open(filename, 'rb') {|f| f.read() }
return s
end
def test_cgi_multipart_stringio
@boundary = '----WebKitFormBoundaryAAfvAII+YL9102cX'
@data = [
{:name=>'hidden1', :value=>'foobar'},
{:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A".dup},
{:name=>'file1', :value=>_read('file1.html'),
:filename=>'file1.html', :content_type=>'text/html'},
{:name=>'image1', :value=>_read('small.png'),
:filename=>'small.png', :content_type=>'image/png'}, # small image
]
@data[1][:value].force_encoding(::Encoding::UTF_8) if defined?(::Encoding)
@expected_class = StringIO
_test_multipart()
end
def test_cgi_multipart_tempfile
@boundary = '----WebKitFormBoundaryAAfvAII+YL9102cX'
@data = [
{:name=>'hidden1', :value=>'foobar'},
{:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A".dup},
{:name=>'file1', :value=>_read('file1.html'),
:filename=>'file1.html', :content_type=>'text/html'},
{:name=>'image1', :value=>_read('large.png'),
:filename=>'large.png', :content_type=>'image/png'}, # large image
]
@data[1][:value].force_encoding(::Encoding::UTF_8) if defined?(::Encoding)
@expected_class = Tempfile
_test_multipart()
end
def _set_const(klass, name, value)
old = nil
klass.class_eval do
old = const_get(name)
remove_const(name)
const_set(name, value)
end
return old
end
def test_cgi_multipart_maxmultipartlength
@data = [
{:name=>'image1', :value=>_read('large.png'),
:filename=>'large.png', :content_type=>'image/png'}, # large image
]
begin
ex = assert_raise(StandardError) do
_test_multipart(:max_multipart_length=>2 * 1024) # set via simple scalar
end
assert_equal("too large multipart data.", ex.message)
ensure
end
end
def test_cgi_multipart_maxmultipartlength_lambda
@data = [
{:name=>'image1', :value=>_read('large.png'),
:filename=>'large.png', :content_type=>'image/png'}, # large image
]
begin
ex = assert_raise(StandardError) do
_test_multipart(:max_multipart_length=>lambda{2*1024}) # set via lambda
end
assert_equal("too large multipart data.", ex.message)
ensure
end
end
def test_cgi_multipart_maxmultipartcount
@data = [
{:name=>'file1', :value=>_read('file1.html'),
:filename=>'file1.html', :content_type=>'text/html'},
]
item = @data.first
500.times { @data << item }
#original = _set_const(CGI, :MAX_MULTIPART_COUNT, 128)
begin
ex = assert_raise(StandardError) do
_test_multipart()
end
assert_equal("too many parameters.", ex.message)
ensure
#_set_const(CGI, :MAX_MULTIPART_COUNT, original)
end
end if CGI.const_defined?(:MAX_MULTIPART_COUNT)
def test_cgi_multipart_badbody ## [ruby-dev:28470]
@data = [
{:name=>'file1', :value=>_read('file1.html'),
:filename=>'file1.html', :content_type=>'text/html'},
]
_prepare(@data) do |input|
input2 = input.sub(/--(\r\n)?\z/, "\r\n")
assert input2 != input
#p input2
input2
end
ex = assert_raise(EOFError) do
CGI.new(:accept_charset=>"UTF-8")
end
assert_equal("bad content body", ex.message)
#
_prepare(@data) do |input|
input2 = input.sub(/--(\r\n)?\z/, "")
assert input2 != input
#p input2
input2
end
ex = assert_raise(EOFError) do
CGI.new(:accept_charset=>"UTF-8")
end
assert_equal("bad content body", ex.message)
end
def test_cgi_multipart_quoteboundary ## [JVN#84798830]
@boundary = '(.|\n)*'
@data = [
{:name=>'hidden1', :value=>'foobar'},
{:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A".dup},
{:name=>'file1', :value=>_read('file1.html'),
:filename=>'file1.html', :content_type=>'text/html'},
{:name=>'image1', :value=>_read('small.png'),
:filename=>'small.png', :content_type=>'image/png'}, # small image
]
@data[1][:value].force_encoding("UTF-8")
_prepare(@data)
cgi = CGI.new(:accept_charset=>"UTF-8")
assert_equal('file1.html', cgi['file1'].original_filename)
end
def test_cgi_multipart_boundary_10240 # [Bug #3866]
@boundary = 'AaB03x'
@data = [
{:name=>'file', :value=>"b"*10134,
:filename=>'file.txt', :content_type=>'text/plain'},
{:name=>'foo', :value=>"bar"},
]
_prepare(@data)
cgi = CGI.new(:accept_charset=>"UTF-8")
assert_equal(cgi['foo'], 'bar')
assert_equal(cgi['file'].read, 'b'*10134)
cgi['file'].close! if cgi['file'].kind_of? Tempfile
end
def test_cgi_multipart_without_tempfile
assert_in_out_err([], <<-'EOM')
require 'cgi'
require 'stringio'
ENV['REQUEST_METHOD'] = 'POST'
ENV['CONTENT_TYPE'] = 'multipart/form-data; boundary=foobar1234'
body = <<-BODY.gsub(/\n/, "\r\n")
--foobar1234
Content-Disposition: form-data: name=\"name1\"
value1
--foobar1234
Content-Disposition: form-data: name=\"file1\"; filename=\"file1.html\"
Content-Type: text/html
<html>
<body><p>Hello</p></body>
</html>
--foobar1234--
BODY
ENV['CONTENT_LENGTH'] = body.size.to_s
$stdin = StringIO.new(body)
CGI.new
EOM
end
###
self.instance_methods.each do |method|
private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
end if ENV['TEST']
end

View File

@ -1,169 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'cgi'
require 'cgi/session'
require 'cgi/session/pstore'
require 'stringio'
require 'tmpdir'
require_relative 'update_env'
class CGISessionTest < Test::Unit::TestCase
include UpdateEnv
def setup
@environ = {}
@session_dir = Dir.mktmpdir(%w'session dir')
end
def teardown
ENV.update(@environ)
$stdout = STDOUT
FileUtils.rm_rf(@session_dir)
end
def test_cgi_session_filestore
update_env(
'REQUEST_METHOD' => 'GET',
# 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
# 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
value1="value1"
value2="\x8F\xBC\x8D]".dup
value2.force_encoding("SJIS") if defined?(::Encoding)
cgi = CGI.new
session = CGI::Session.new(cgi,"tmpdir"=>@session_dir)
session["key1"]=value1
session["key2"]=value2
assert_equal(value1,session["key1"])
assert_equal(value2,session["key2"])
session.close
$stdout = StringIO.new
cgi.out{""}
update_env(
'REQUEST_METHOD' => 'GET',
# 'HTTP_COOKIE' => "_session_id=#{session_id}",
'QUERY_STRING' => "_session_id=#{session.session_id}",
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
cgi = CGI.new
session = CGI::Session.new(cgi,"tmpdir"=>@session_dir)
$stdout = StringIO.new
assert_equal(value1,session["key1"])
assert_equal(value2,session["key2"])
session.close
end
def test_cgi_session_pstore
update_env(
'REQUEST_METHOD' => 'GET',
# 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
# 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
value1="value1"
value2="\x8F\xBC\x8D]".dup
value2.force_encoding("SJIS") if defined?(::Encoding)
cgi = CGI.new
session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"database_manager"=>CGI::Session::PStore)
session["key1"]=value1
session["key2"]=value2
assert_equal(value1,session["key1"])
assert_equal(value2,session["key2"])
session.close
$stdout = StringIO.new
cgi.out{""}
update_env(
'REQUEST_METHOD' => 'GET',
# 'HTTP_COOKIE' => "_session_id=#{session_id}",
'QUERY_STRING' => "_session_id=#{session.session_id}",
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
cgi = CGI.new
session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"database_manager"=>CGI::Session::PStore)
$stdout = StringIO.new
assert_equal(value1,session["key1"])
assert_equal(value2,session["key2"])
session.close
end if defined?(::PStore)
def test_cgi_session_specify_session_id
update_env(
'REQUEST_METHOD' => 'GET',
# 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
# 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
value1="value1"
value2="\x8F\xBC\x8D]".dup
value2.force_encoding("SJIS") if defined?(::Encoding)
cgi = CGI.new
session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"session_id"=>"foo")
session["key1"]=value1
session["key2"]=value2
assert_equal(value1,session["key1"])
assert_equal(value2,session["key2"])
assert_equal("foo",session.session_id)
#session_id=session.session_id
session.close
$stdout = StringIO.new
cgi.out{""}
update_env(
'REQUEST_METHOD' => 'GET',
# 'HTTP_COOKIE' => "_session_id=#{session_id}",
'QUERY_STRING' => "_session_id=#{session.session_id}",
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
cgi = CGI.new
session = CGI::Session.new(cgi,"tmpdir"=>@session_dir)
$stdout = StringIO.new
assert_equal(value1,session["key1"])
assert_equal(value2,session["key2"])
assert_equal("foo",session.session_id)
session.close
end
def test_cgi_session_specify_session_key
update_env(
'REQUEST_METHOD' => 'GET',
# 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F',
# 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;',
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
value1="value1"
value2="\x8F\xBC\x8D]".dup
value2.force_encoding("SJIS") if defined?(::Encoding)
cgi = CGI.new
session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"session_key"=>"bar")
session["key1"]=value1
session["key2"]=value2
assert_equal(value1,session["key1"])
assert_equal(value2,session["key2"])
session_id=session.session_id
session.close
$stdout = StringIO.new
cgi.out{""}
update_env(
'REQUEST_METHOD' => 'GET',
'HTTP_COOKIE' => "bar=#{session_id}",
# 'QUERY_STRING' => "bar=#{session.session_id}",
'SERVER_SOFTWARE' => 'Apache 2.2.0',
'SERVER_PROTOCOL' => 'HTTP/1.1',
)
cgi = CGI.new
session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"session_key"=>"bar")
$stdout = StringIO.new
assert_equal(value1,session["key1"])
assert_equal(value2,session["key2"])
session.close
end
end

View File

@ -1,355 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'cgi'
require 'stringio'
require_relative 'update_env'
class CGITagHelperTest < Test::Unit::TestCase
include UpdateEnv
def setup
@environ = {}
#@environ = {
# 'SERVER_PROTOCOL' => 'HTTP/1.1',
# 'REQUEST_METHOD' => 'GET',
# 'SERVER_SOFTWARE' => 'Apache 2.2.0',
#}
#ENV.update(@environ)
end
def teardown
ENV.update(@environ)
$stdout = STDOUT
end
def test_cgi_tag_helper_html3
update_env(
'REQUEST_METHOD' => 'GET',
)
## html3
cgi = CGI.new('html3')
assert_equal('<A HREF=""></A>',cgi.a)
assert_equal('<A HREF="bar"></A>',cgi.a('bar'))
assert_equal('<A HREF="">foo</A>',cgi.a{'foo'})
assert_equal('<A HREF="bar">foo</A>',cgi.a('bar'){'foo'})
assert_equal('<TT></TT>',cgi.tt)
assert_equal('<TT></TT>',cgi.tt('bar'))
assert_equal('<TT>foo</TT>',cgi.tt{'foo'})
assert_equal('<TT>foo</TT>',cgi.tt('bar'){'foo'})
assert_equal('<I></I>',cgi.i)
assert_equal('<I></I>',cgi.i('bar'))
assert_equal('<I>foo</I>',cgi.i{'foo'})
assert_equal('<I>foo</I>',cgi.i('bar'){'foo'})
assert_equal('<B></B>',cgi.b)
assert_equal('<B></B>',cgi.b('bar'))
assert_equal('<B>foo</B>',cgi.b{'foo'})
assert_equal('<B>foo</B>',cgi.b('bar'){'foo'})
assert_equal('<U></U>',cgi.u)
assert_equal('<U></U>',cgi.u('bar'))
assert_equal('<U>foo</U>',cgi.u{'foo'})
assert_equal('<U>foo</U>',cgi.u('bar'){'foo'})
assert_equal('<STRIKE></STRIKE>',cgi.strike)
assert_equal('<STRIKE></STRIKE>',cgi.strike('bar'))
assert_equal('<STRIKE>foo</STRIKE>',cgi.strike{'foo'})
assert_equal('<STRIKE>foo</STRIKE>',cgi.strike('bar'){'foo'})
assert_equal('<BIG></BIG>',cgi.big)
assert_equal('<BIG></BIG>',cgi.big('bar'))
assert_equal('<BIG>foo</BIG>',cgi.big{'foo'})
assert_equal('<BIG>foo</BIG>',cgi.big('bar'){'foo'})
assert_equal('<SMALL></SMALL>',cgi.small)
assert_equal('<SMALL></SMALL>',cgi.small('bar'))
assert_equal('<SMALL>foo</SMALL>',cgi.small{'foo'})
assert_equal('<SMALL>foo</SMALL>',cgi.small('bar'){'foo'})
assert_equal('<SUB></SUB>',cgi.sub)
assert_equal('<SUB></SUB>',cgi.sub('bar'))
assert_equal('<SUB>foo</SUB>',cgi.sub{'foo'})
assert_equal('<SUB>foo</SUB>',cgi.sub('bar'){'foo'})
assert_equal('<SUP></SUP>',cgi.sup)
assert_equal('<SUP></SUP>',cgi.sup('bar'))
assert_equal('<SUP>foo</SUP>',cgi.sup{'foo'})
assert_equal('<SUP>foo</SUP>',cgi.sup('bar'){'foo'})
assert_equal('<EM></EM>',cgi.em)
assert_equal('<EM></EM>',cgi.em('bar'))
assert_equal('<EM>foo</EM>',cgi.em{'foo'})
assert_equal('<EM>foo</EM>',cgi.em('bar'){'foo'})
assert_equal('<STRONG></STRONG>',cgi.strong)
assert_equal('<STRONG></STRONG>',cgi.strong('bar'))
assert_equal('<STRONG>foo</STRONG>',cgi.strong{'foo'})
assert_equal('<STRONG>foo</STRONG>',cgi.strong('bar'){'foo'})
assert_equal('<DFN></DFN>',cgi.dfn)
assert_equal('<DFN></DFN>',cgi.dfn('bar'))
assert_equal('<DFN>foo</DFN>',cgi.dfn{'foo'})
assert_equal('<DFN>foo</DFN>',cgi.dfn('bar'){'foo'})
assert_equal('<CODE></CODE>',cgi.code)
assert_equal('<CODE></CODE>',cgi.code('bar'))
assert_equal('<CODE>foo</CODE>',cgi.code{'foo'})
assert_equal('<CODE>foo</CODE>',cgi.code('bar'){'foo'})
assert_equal('<SAMP></SAMP>',cgi.samp)
assert_equal('<SAMP></SAMP>',cgi.samp('bar'))
assert_equal('<SAMP>foo</SAMP>',cgi.samp{'foo'})
assert_equal('<SAMP>foo</SAMP>',cgi.samp('bar'){'foo'})
assert_equal('<KBD></KBD>',cgi.kbd)
assert_equal('<KBD></KBD>',cgi.kbd('bar'))
assert_equal('<KBD>foo</KBD>',cgi.kbd{'foo'})
assert_equal('<KBD>foo</KBD>',cgi.kbd('bar'){'foo'})
assert_equal('<VAR></VAR>',cgi.var)
assert_equal('<VAR></VAR>',cgi.var('bar'))
assert_equal('<VAR>foo</VAR>',cgi.var{'foo'})
assert_equal('<VAR>foo</VAR>',cgi.var('bar'){'foo'})
assert_equal('<CITE></CITE>',cgi.cite)
assert_equal('<CITE></CITE>',cgi.cite('bar'))
assert_equal('<CITE>foo</CITE>',cgi.cite{'foo'})
assert_equal('<CITE>foo</CITE>',cgi.cite('bar'){'foo'})
assert_equal('<FONT></FONT>',cgi.font)
assert_equal('<FONT></FONT>',cgi.font('bar'))
assert_equal('<FONT>foo</FONT>',cgi.font{'foo'})
assert_equal('<FONT>foo</FONT>',cgi.font('bar'){'foo'})
assert_equal('<ADDRESS></ADDRESS>',cgi.address)
assert_equal('<ADDRESS></ADDRESS>',cgi.address('bar'))
assert_equal('<ADDRESS>foo</ADDRESS>',cgi.address{'foo'})
assert_equal('<ADDRESS>foo</ADDRESS>',cgi.address('bar'){'foo'})
assert_equal('<DIV></DIV>',cgi.div)
assert_equal('<DIV></DIV>',cgi.div('bar'))
assert_equal('<DIV>foo</DIV>',cgi.div{'foo'})
assert_equal('<DIV>foo</DIV>',cgi.div('bar'){'foo'})
assert_equal('<CENTER></CENTER>',cgi.center)
assert_equal('<CENTER></CENTER>',cgi.center('bar'))
assert_equal('<CENTER>foo</CENTER>',cgi.center{'foo'})
assert_equal('<CENTER>foo</CENTER>',cgi.center('bar'){'foo'})
assert_equal('<MAP></MAP>',cgi.map)
assert_equal('<MAP></MAP>',cgi.map('bar'))
assert_equal('<MAP>foo</MAP>',cgi.map{'foo'})
assert_equal('<MAP>foo</MAP>',cgi.map('bar'){'foo'})
assert_equal('<APPLET></APPLET>',cgi.applet)
assert_equal('<APPLET></APPLET>',cgi.applet('bar'))
assert_equal('<APPLET>foo</APPLET>',cgi.applet{'foo'})
assert_equal('<APPLET>foo</APPLET>',cgi.applet('bar'){'foo'})
assert_equal('<PRE></PRE>',cgi.pre)
assert_equal('<PRE></PRE>',cgi.pre('bar'))
assert_equal('<PRE>foo</PRE>',cgi.pre{'foo'})
assert_equal('<PRE>foo</PRE>',cgi.pre('bar'){'foo'})
assert_equal('<XMP></XMP>',cgi.xmp)
assert_equal('<XMP></XMP>',cgi.xmp('bar'))
assert_equal('<XMP>foo</XMP>',cgi.xmp{'foo'})
assert_equal('<XMP>foo</XMP>',cgi.xmp('bar'){'foo'})
assert_equal('<LISTING></LISTING>',cgi.listing)
assert_equal('<LISTING></LISTING>',cgi.listing('bar'))
assert_equal('<LISTING>foo</LISTING>',cgi.listing{'foo'})
assert_equal('<LISTING>foo</LISTING>',cgi.listing('bar'){'foo'})
assert_equal('<DL></DL>',cgi.dl)
assert_equal('<DL></DL>',cgi.dl('bar'))
assert_equal('<DL>foo</DL>',cgi.dl{'foo'})
assert_equal('<DL>foo</DL>',cgi.dl('bar'){'foo'})
assert_equal('<OL></OL>',cgi.ol)
assert_equal('<OL></OL>',cgi.ol('bar'))
assert_equal('<OL>foo</OL>',cgi.ol{'foo'})
assert_equal('<OL>foo</OL>',cgi.ol('bar'){'foo'})
assert_equal('<UL></UL>',cgi.ul)
assert_equal('<UL></UL>',cgi.ul('bar'))
assert_equal('<UL>foo</UL>',cgi.ul{'foo'})
assert_equal('<UL>foo</UL>',cgi.ul('bar'){'foo'})
assert_equal('<DIR></DIR>',cgi.dir)
assert_equal('<DIR></DIR>',cgi.dir('bar'))
assert_equal('<DIR>foo</DIR>',cgi.dir{'foo'})
assert_equal('<DIR>foo</DIR>',cgi.dir('bar'){'foo'})
assert_equal('<MENU></MENU>',cgi.menu)
assert_equal('<MENU></MENU>',cgi.menu('bar'))
assert_equal('<MENU>foo</MENU>',cgi.menu{'foo'})
assert_equal('<MENU>foo</MENU>',cgi.menu('bar'){'foo'})
assert_equal('<SELECT></SELECT>',cgi.select)
assert_equal('<SELECT></SELECT>',cgi.select('bar'))
assert_equal('<SELECT>foo</SELECT>',cgi.select{'foo'})
assert_equal('<SELECT>foo</SELECT>',cgi.select('bar'){'foo'})
assert_equal('<TABLE></TABLE>',cgi.table)
assert_equal('<TABLE></TABLE>',cgi.table('bar'))
assert_equal('<TABLE>foo</TABLE>',cgi.table{'foo'})
assert_equal('<TABLE>foo</TABLE>',cgi.table('bar'){'foo'})
assert_equal('<TITLE></TITLE>',cgi.title)
assert_equal('<TITLE></TITLE>',cgi.title('bar'))
assert_equal('<TITLE>foo</TITLE>',cgi.title{'foo'})
assert_equal('<TITLE>foo</TITLE>',cgi.title('bar'){'foo'})
assert_equal('<STYLE></STYLE>',cgi.style)
assert_equal('<STYLE></STYLE>',cgi.style('bar'))
assert_equal('<STYLE>foo</STYLE>',cgi.style{'foo'})
assert_equal('<STYLE>foo</STYLE>',cgi.style('bar'){'foo'})
assert_equal('<SCRIPT></SCRIPT>',cgi.script)
assert_equal('<SCRIPT></SCRIPT>',cgi.script('bar'))
assert_equal('<SCRIPT>foo</SCRIPT>',cgi.script{'foo'})
assert_equal('<SCRIPT>foo</SCRIPT>',cgi.script('bar'){'foo'})
assert_equal('<H1></H1>',cgi.h1)
assert_equal('<H1></H1>',cgi.h1('bar'))
assert_equal('<H1>foo</H1>',cgi.h1{'foo'})
assert_equal('<H1>foo</H1>',cgi.h1('bar'){'foo'})
assert_equal('<H2></H2>',cgi.h2)
assert_equal('<H2></H2>',cgi.h2('bar'))
assert_equal('<H2>foo</H2>',cgi.h2{'foo'})
assert_equal('<H2>foo</H2>',cgi.h2('bar'){'foo'})
assert_equal('<H3></H3>',cgi.h3)
assert_equal('<H3></H3>',cgi.h3('bar'))
assert_equal('<H3>foo</H3>',cgi.h3{'foo'})
assert_equal('<H3>foo</H3>',cgi.h3('bar'){'foo'})
assert_equal('<H4></H4>',cgi.h4)
assert_equal('<H4></H4>',cgi.h4('bar'))
assert_equal('<H4>foo</H4>',cgi.h4{'foo'})
assert_equal('<H4>foo</H4>',cgi.h4('bar'){'foo'})
assert_equal('<H5></H5>',cgi.h5)
assert_equal('<H5></H5>',cgi.h5('bar'))
assert_equal('<H5>foo</H5>',cgi.h5{'foo'})
assert_equal('<H5>foo</H5>',cgi.h5('bar'){'foo'})
assert_equal('<H6></H6>',cgi.h6)
assert_equal('<H6></H6>',cgi.h6('bar'))
assert_equal('<H6>foo</H6>',cgi.h6{'foo'})
assert_equal('<H6>foo</H6>',cgi.h6('bar'){'foo'})
assert_match(/^<TEXTAREA .*><\/TEXTAREA>$/,cgi.textarea)
assert_match(/COLS="70"/,cgi.textarea)
assert_match(/ROWS="10"/,cgi.textarea)
assert_match(/NAME=""/,cgi.textarea)
assert_match(/^<TEXTAREA .*><\/TEXTAREA>$/,cgi.textarea("bar"))
assert_match(/COLS="70"/,cgi.textarea("bar"))
assert_match(/ROWS="10"/,cgi.textarea("bar"))
assert_match(/NAME="bar"/,cgi.textarea("bar"))
assert_match(/^<TEXTAREA .*>foo<\/TEXTAREA>$/,cgi.textarea{"foo"})
assert_match(/COLS="70"/,cgi.textarea{"foo"})
assert_match(/ROWS="10"/,cgi.textarea{"foo"})
assert_match(/NAME=""/,cgi.textarea{"foo"})
assert_match(/^<TEXTAREA .*>foo<\/TEXTAREA>$/,cgi.textarea("bar"){"foo"})
assert_match(/COLS="70"/,cgi.textarea("bar"){"foo"})
assert_match(/ROWS="10"/,cgi.textarea("bar"){"foo"})
assert_match(/NAME="bar"/,cgi.textarea("bar"){"foo"})
assert_match(/^<FORM .*><\/FORM>$/,cgi.form)
assert_match(/METHOD="post"/,cgi.form)
assert_match(/ENCTYPE="application\/x-www-form-urlencoded"/,cgi.form)
assert_match(/^<FORM .*><\/FORM>$/,cgi.form("bar"))
assert_match(/METHOD="bar"/,cgi.form("bar"))
assert_match(/ENCTYPE="application\/x-www-form-urlencoded"/,cgi.form("bar"))
assert_match(/^<FORM .*>foo<\/FORM>$/,cgi.form{"foo"})
assert_match(/METHOD="post"/,cgi.form{"foo"})
assert_match(/ENCTYPE="application\/x-www-form-urlencoded"/,cgi.form{"foo"})
assert_match(/^<FORM .*>foo<\/FORM>$/,cgi.form("bar"){"foo"})
assert_match(/METHOD="bar"/,cgi.form("bar"){"foo"})
assert_match(/ENCTYPE="application\/x-www-form-urlencoded"/,cgi.form("bar"){"foo"})
assert_equal('<BLOCKQUOTE></BLOCKQUOTE>',cgi.blockquote)
assert_equal('<BLOCKQUOTE CITE="bar"></BLOCKQUOTE>',cgi.blockquote('bar'))
assert_equal('<BLOCKQUOTE>foo</BLOCKQUOTE>',cgi.blockquote{'foo'})
assert_equal('<BLOCKQUOTE CITE="bar">foo</BLOCKQUOTE>',cgi.blockquote('bar'){'foo'})
assert_equal('<CAPTION></CAPTION>',cgi.caption)
assert_equal('<CAPTION ALIGN="bar"></CAPTION>',cgi.caption('bar'))
assert_equal('<CAPTION>foo</CAPTION>',cgi.caption{'foo'})
assert_equal('<CAPTION ALIGN="bar">foo</CAPTION>',cgi.caption('bar'){'foo'})
assert_equal('<IMG SRC="" ALT="">',cgi.img)
assert_equal('<IMG SRC="bar" ALT="">',cgi.img('bar'))
assert_equal('<IMG SRC="" ALT="">',cgi.img{'foo'})
assert_equal('<IMG SRC="bar" ALT="">',cgi.img('bar'){'foo'})
assert_equal('<BASE HREF="">',cgi.base)
assert_equal('<BASE HREF="bar">',cgi.base('bar'))
assert_equal('<BASE HREF="">',cgi.base{'foo'})
assert_equal('<BASE HREF="bar">',cgi.base('bar'){'foo'})
assert_equal('<BASEFONT>',cgi.basefont)
assert_equal('<BASEFONT>',cgi.basefont('bar'))
assert_equal('<BASEFONT>',cgi.basefont{'foo'})
assert_equal('<BASEFONT>',cgi.basefont('bar'){'foo'})
assert_equal('<BR>',cgi.br)
assert_equal('<BR>',cgi.br('bar'))
assert_equal('<BR>',cgi.br{'foo'})
assert_equal('<BR>',cgi.br('bar'){'foo'})
assert_equal('<AREA>',cgi.area)
assert_equal('<AREA>',cgi.area('bar'))
assert_equal('<AREA>',cgi.area{'foo'})
assert_equal('<AREA>',cgi.area('bar'){'foo'})
assert_equal('<LINK>',cgi.link)
assert_equal('<LINK>',cgi.link('bar'))
assert_equal('<LINK>',cgi.link{'foo'})
assert_equal('<LINK>',cgi.link('bar'){'foo'})
assert_equal('<PARAM>',cgi.param)
assert_equal('<PARAM>',cgi.param('bar'))
assert_equal('<PARAM>',cgi.param{'foo'})
assert_equal('<PARAM>',cgi.param('bar'){'foo'})
assert_equal('<HR>',cgi.hr)
assert_equal('<HR>',cgi.hr('bar'))
assert_equal('<HR>',cgi.hr{'foo'})
assert_equal('<HR>',cgi.hr('bar'){'foo'})
assert_equal('<INPUT>',cgi.input)
assert_equal('<INPUT>',cgi.input('bar'))
assert_equal('<INPUT>',cgi.input{'foo'})
assert_equal('<INPUT>',cgi.input('bar'){'foo'})
assert_equal('<ISINDEX>',cgi.isindex)
assert_equal('<ISINDEX>',cgi.isindex('bar'))
assert_equal('<ISINDEX>',cgi.isindex{'foo'})
assert_equal('<ISINDEX>',cgi.isindex('bar'){'foo'})
assert_equal('<META>',cgi.meta)
assert_equal('<META>',cgi.meta('bar'))
assert_equal('<META>',cgi.meta{'foo'})
assert_equal('<META>',cgi.meta('bar'){'foo'})
assert_equal('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>',cgi.html)
assert_equal('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>foo</HTML>',cgi.html{'foo'})
assert_equal('<HEAD>',cgi.head)
assert_equal('<HEAD>foo</HEAD>',cgi.head{'foo'})
assert_equal('<BODY>',cgi.body)
assert_equal('<BODY>foo</BODY>',cgi.body{'foo'})
assert_equal('<P>',cgi.p)
assert_equal('<P>foo</P>',cgi.p{'foo'})
assert_equal('<PLAINTEXT>',cgi.plaintext)
assert_equal('<PLAINTEXT>foo</PLAINTEXT>',cgi.plaintext{'foo'})
assert_equal('<DT>',cgi.dt)
assert_equal('<DT>foo</DT>',cgi.dt{'foo'})
assert_equal('<DD>',cgi.dd)
assert_equal('<DD>foo</DD>',cgi.dd{'foo'})
assert_equal('<LI>',cgi.li)
assert_equal('<LI>foo</LI>',cgi.li{'foo'})
assert_equal('<OPTION>',cgi.option)
assert_equal('<OPTION>foo</OPTION>',cgi.option{'foo'})
assert_equal('<TR>',cgi.tr)
assert_equal('<TR>foo</TR>',cgi.tr{'foo'})
assert_equal('<TH>',cgi.th)
assert_equal('<TH>foo</TH>',cgi.th{'foo'})
assert_equal('<TD>',cgi.td)
assert_equal('<TD>foo</TD>',cgi.td{'foo'})
str=cgi.checkbox_group("foo",["aa","bb"],["cc","dd"])
assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str)
assert_match(/^<INPUT .*TYPE="checkbox".*>bb<INPUT .*TYPE="checkbox".*>dd$/,str)
assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str)
str=cgi.radio_group("foo",["aa","bb"],["cc","dd"])
assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str)
assert_match(/^<INPUT .*TYPE="radio".*>bb<INPUT .*TYPE="radio".*>dd$/,str)
assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str)
str=cgi.checkbox_group("foo",["aa","bb"],["cc","dd",true])
assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str)
assert_match(/^<INPUT .*TYPE="checkbox".*>bb<INPUT .*TYPE="checkbox".*>dd$/,str)
assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str)
assert_match(/^<INPUT .*>bb<INPUT .*CHECKED.*>dd$/,str)
assert_match(/<INPUT .*TYPE="text".*>/,cgi.text_field(:name=>"name",:value=>"value"))
str=cgi.radio_group("foo",["aa","bb"],["cc","dd",false])
assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str)
assert_match(/^<INPUT .*TYPE="radio".*>bb<INPUT .*TYPE="radio".*>dd$/,str)
assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str)
end
=begin
def test_cgi_tag_helper_html4
## html4
cgi = CGI.new('html4')
## html4 transitional
cgi = CGI.new('html4Tr')
## html4 frameset
cgi = CGI.new('html4Fr')
end
=end
def test_cgi_tag_helper_html5
update_env(
'REQUEST_METHOD' => 'GET',
)
## html5
cgi = CGI.new('html5')
assert_equal('<HEADER></HEADER>',cgi.header)
assert_equal('<FOOTER></FOOTER>',cgi.footer)
assert_equal('<ARTICLE></ARTICLE>',cgi.article)
assert_equal('<SECTION></SECTION>',cgi.section)
assert_equal('<!DOCTYPE HTML><HTML BLA="TEST"></HTML>',cgi.html("BLA"=>"TEST"){})
end
end

View File

@ -1,12 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'cgi/util'
class CGIUtilTest < Test::Unit::TestCase
def test_cgi_pretty
assert_equal("<HTML>\n <BODY>\n </BODY>\n</HTML>\n",CGI.pretty("<HTML><BODY></BODY></HTML>"))
assert_equal("<HTML>\n\t<BODY>\n\t</BODY>\n</HTML>\n",CGI.pretty("<HTML><BODY></BODY></HTML>","\t"))
end
end

View File

@ -1,10 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>ムスカ大佐のひとりごと</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF8">
</head>
<body>
<p>バカどもにはちょうどいい目くらましだ。</p>
</body>
</html>

Binary file not shown.

Binary file not shown.