1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
# 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
|