Removed CGI library without CGI::Escape features
This commit is contained in:
parent
a61f51f66d
commit
600c616507
Notes:
git
2025-05-09 05:27:42 +00:00
298
lib/cgi.rb
298
lib/cgi.rb
@ -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')
|
@ -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
|
@ -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
|
||||
|
||||
|
900
lib/cgi/core.rb
900
lib/cgi/core.rb
@ -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
|
1035
lib/cgi/html.rb
1035
lib/cgi/html.rb
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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:
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
10
test/cgi/testdata/file1.html
vendored
10
test/cgi/testdata/file1.html
vendored
@ -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>
|
BIN
test/cgi/testdata/large.png
vendored
BIN
test/cgi/testdata/large.png
vendored
Binary file not shown.
BIN
test/cgi/testdata/small.png
vendored
BIN
test/cgi/testdata/small.png
vendored
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user