cgialt 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.txt +137 -0
- data/bench.rb +245 -0
- data/lib/cgialt.rb +43 -0
- data/lib/cgialt/cookie.rb +245 -0
- data/lib/cgialt/core.rb +1463 -0
- data/lib/cgialt/html.rb +1030 -0
- data/lib/cgialt/util.rb +166 -0
- data/setup.rb +1331 -0
- data/test/test_cgi_cookie.rb +108 -0
- data/test/test_cgi_core.rb +305 -0
- data/test/test_cgi_header.rb +178 -0
- data/test/test_cgi_modruby.rb +146 -0
- data/test/test_cgi_multipart.rb +295 -0
- data/test/testdata/file1.html +10 -0
- data/test/testdata/large.png +0 -0
- data/test/testdata/small.png +0 -0
- metadata +63 -0
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
#require 'cgi'
|
3
|
+
require(ENV['CGI'] || 'cgi')
|
4
|
+
|
5
|
+
|
6
|
+
class CGIModrubyTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@environ = {
|
11
|
+
'SERVER_PROTOCOL' => 'HTTP/1.1',
|
12
|
+
'REQUEST_METHOD' => 'GET',
|
13
|
+
#'QUERY_STRING' => 'a=foo&b=bar',
|
14
|
+
}
|
15
|
+
ENV.update(@environ)
|
16
|
+
CGI.class_eval { const_set(:MOD_RUBY, true) }
|
17
|
+
Apache._reset()
|
18
|
+
#@cgi = CGI.new
|
19
|
+
#@req = Apache.request
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def teardown
|
24
|
+
@environ.each do |key, val| ENV.delete(key) end
|
25
|
+
CGI.class_eval { remove_const(:MOD_RUBY) }
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def test_cgi_modruby_simple
|
30
|
+
req = Apache.request
|
31
|
+
cgi = CGI.new
|
32
|
+
assert(req._setup_cgi_env_invoked?)
|
33
|
+
assert(! req._send_http_header_invoked?)
|
34
|
+
actual = cgi.header
|
35
|
+
assert_equal('', actual)
|
36
|
+
assert_equal('text/html', req.content_type)
|
37
|
+
assert(req._send_http_header_invoked?)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def test_cgi_modruby_complex
|
42
|
+
req = Apache.request
|
43
|
+
cgi = CGI.new
|
44
|
+
options = {
|
45
|
+
'status' => 'FORBIDDEN',
|
46
|
+
'location' => 'http://www.example.com/',
|
47
|
+
'type' => 'image/gif',
|
48
|
+
'content-encoding' => 'deflate',
|
49
|
+
'cookie' => [ CGI::Cookie.new('name1', 'abc', '123'),
|
50
|
+
CGI::Cookie.new('name'=>'name2', 'value'=>'value2', 'secure'=>true),
|
51
|
+
],
|
52
|
+
}
|
53
|
+
assert(req._setup_cgi_env_invoked?)
|
54
|
+
assert(! req._send_http_header_invoked?)
|
55
|
+
actual = cgi.header(options)
|
56
|
+
assert_equal('', actual)
|
57
|
+
assert_equal('image/gif', req.content_type)
|
58
|
+
assert_equal('403 Forbidden', req.status_line)
|
59
|
+
assert_equal(403, req.status)
|
60
|
+
assert_equal('deflate', req.content_encoding)
|
61
|
+
assert_equal('http://www.example.com/', req.headers_out['location'])
|
62
|
+
assert_equal(["name1=abc&123; path=", "name2=value2; path=; secure"],
|
63
|
+
req.headers_out['Set-Cookie'])
|
64
|
+
assert(req._send_http_header_invoked?)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def test_cgi_modruby_location
|
69
|
+
req = Apache.request
|
70
|
+
cgi = CGI.new
|
71
|
+
options = {
|
72
|
+
'status' => '200 OK',
|
73
|
+
'location' => 'http://www.example.com/',
|
74
|
+
}
|
75
|
+
actual = cgi.header(options)
|
76
|
+
assert_equal('200 OK', req.status_line) # should be '302 Found' ?
|
77
|
+
assert_equal(302, req.status)
|
78
|
+
assert_equal('http://www.example.com/', req.headers_out['location'])
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def test_cgi_modruby_requestparams
|
83
|
+
req = Apache.request
|
84
|
+
req.args = 'a=foo&b=bar'
|
85
|
+
cgi = CGI.new
|
86
|
+
assert_equal('foo', cgi['a'])
|
87
|
+
assert_equal('bar', cgi['b'])
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
instance_methods.each do |method|
|
92
|
+
private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
|
93
|
+
end if ENV['TEST']
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
## dummy class for mod_ruby
|
100
|
+
class Apache #:nodoc:
|
101
|
+
|
102
|
+
def self._reset
|
103
|
+
@request = Request.new
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.request
|
107
|
+
return @request
|
108
|
+
end
|
109
|
+
|
110
|
+
class Request
|
111
|
+
|
112
|
+
def initialize
|
113
|
+
hash = {}
|
114
|
+
def hash.add(name, value)
|
115
|
+
(self[name] ||= []) << value
|
116
|
+
end
|
117
|
+
@headers_out = hash
|
118
|
+
@status_line = nil
|
119
|
+
@status = nil
|
120
|
+
@content_type = nil
|
121
|
+
@content_encoding = nil
|
122
|
+
end
|
123
|
+
attr_accessor :headers_out, :status_line, :status, :content_type, :content_encoding
|
124
|
+
|
125
|
+
attr_accessor :args
|
126
|
+
#def args
|
127
|
+
# return ENV['QUERY_STRING']
|
128
|
+
#end
|
129
|
+
|
130
|
+
def send_http_header
|
131
|
+
@http_header = '*invoked*'
|
132
|
+
end
|
133
|
+
def _send_http_header_invoked?
|
134
|
+
@http_header ? true : false
|
135
|
+
end
|
136
|
+
|
137
|
+
def setup_cgi_env
|
138
|
+
@cgi_env = '*invoked*'
|
139
|
+
end
|
140
|
+
def _setup_cgi_env_invoked?
|
141
|
+
@cgi_env ? true : false
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
#require 'cgi'
|
3
|
+
require(ENV['CGI'] || 'cgi')
|
4
|
+
require 'tempfile'
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
|
8
|
+
##
|
9
|
+
## usage:
|
10
|
+
## boundary = 'foobar1234' # or nil
|
11
|
+
## multipart = MultiPart.new(boundary)
|
12
|
+
## multipart.append('name1', 'value1')
|
13
|
+
## multipart.append('file1', File.read('file1.html'), 'file1.html')
|
14
|
+
## str = multipart.close()
|
15
|
+
## str.each_line {|line| p line }
|
16
|
+
## ## output:
|
17
|
+
## # "--foobar1234\r\n"
|
18
|
+
## # "Content-Disposition: form-data: name=\"name1\"\r\n"
|
19
|
+
## # "\r\n"
|
20
|
+
## # "value1\r\n"
|
21
|
+
## # "--foobar1234\r\n"
|
22
|
+
## # "Content-Disposition: form-data: name=\"file1\"; filename=\"file1.html\"\r\n"
|
23
|
+
## # "Content-Type: text/html\r\n"
|
24
|
+
## # "\r\n"
|
25
|
+
## # "<html>\n"
|
26
|
+
## # "<body><p>Hello</p></body>\n"
|
27
|
+
## # "</html>\n"
|
28
|
+
## # "\r\n"
|
29
|
+
## # "--foobar1234--\r\n"
|
30
|
+
##
|
31
|
+
class MultiPart
|
32
|
+
|
33
|
+
def initialize(boundary=nil)
|
34
|
+
@boundary = boundary || create_boundary()
|
35
|
+
@buf = ''
|
36
|
+
end
|
37
|
+
attr_reader :boundary
|
38
|
+
|
39
|
+
def append(name, value, filename=nil, content_type=nil)
|
40
|
+
content_type = detect_content_type(filename) if filename && content_type.nil?
|
41
|
+
s = filename ? "; filename=\"#{filename}\"" : ''
|
42
|
+
buf = @buf
|
43
|
+
buf << "--#{boundary}\r\n"
|
44
|
+
buf << "Content-Disposition: form-data: name=\"#{name}\"#{s}\r\n"
|
45
|
+
buf << "Content-Type: #{content_type}\r\n" if content_type
|
46
|
+
buf << "\r\n"
|
47
|
+
buf << value
|
48
|
+
buf << "\r\n"
|
49
|
+
return self
|
50
|
+
end
|
51
|
+
|
52
|
+
def close
|
53
|
+
buf = @buf
|
54
|
+
@buf = ''
|
55
|
+
return buf << "--#{boundary}--\r\n"
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_boundary() #:nodoc:
|
59
|
+
return "--boundary#{rand().to_s[2..-1]}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def detect_content_type(filename) #:nodoc:
|
63
|
+
filename =~ /\.(\w+)\z/
|
64
|
+
return MIME_TYPES[$1] || 'application/octet-stream'
|
65
|
+
end
|
66
|
+
|
67
|
+
MIME_TYPES = {
|
68
|
+
'gif' => 'image/gif',
|
69
|
+
'jpg' => 'image/jpeg',
|
70
|
+
'jpeg' => 'image/jpeg',
|
71
|
+
'png' => 'image/png',
|
72
|
+
'bmp' => 'image/bmp',
|
73
|
+
'tif' => 'image/tiff',
|
74
|
+
'tiff' => 'image/tiff',
|
75
|
+
'htm' => 'text/html',
|
76
|
+
'html' => 'text/html',
|
77
|
+
'xml' => 'text/xml',
|
78
|
+
'txt' => 'text/plain',
|
79
|
+
'text' => 'text/plain',
|
80
|
+
'css' => 'text/css',
|
81
|
+
'mpg' => 'video/mpeg',
|
82
|
+
'mpeg' => 'video/mpeg',
|
83
|
+
'mov' => 'video/quicktime',
|
84
|
+
'avi' => 'video/x-msvideo',
|
85
|
+
'mp3' => 'audio/mpeg',
|
86
|
+
'mid' => 'audio/midi',
|
87
|
+
'wav' => 'audio/x-wav',
|
88
|
+
'zip' => 'application/zip',
|
89
|
+
#'tar.gz' => 'application/gtar',
|
90
|
+
'gz' => 'application/gzip',
|
91
|
+
'bz2' => 'application/bzip2',
|
92
|
+
'rtf' => 'application/rtf',
|
93
|
+
'pdf' => 'application/pdf',
|
94
|
+
'ps' => 'application/postscript',
|
95
|
+
'js' => 'application/x-javascript',
|
96
|
+
'xls' => 'application/vnd.ms-excel',
|
97
|
+
'doc' => 'application/msword',
|
98
|
+
'ppt' => 'application/vnd.ms-powerpoint',
|
99
|
+
}
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
class CGIMultipartTest < Test::Unit::TestCase
|
106
|
+
|
107
|
+
def setup
|
108
|
+
ENV['REQUEST_METHOD'] = 'POST'
|
109
|
+
end
|
110
|
+
|
111
|
+
def teardown
|
112
|
+
%[REQUEST_METHOD CONTENT_TYPE CONTENT_LENGTH REQUEST_METHOD].each do |name|
|
113
|
+
ENV.delete(name)
|
114
|
+
end
|
115
|
+
$stdin.close() if $stdin.is_a?(Tempfile)
|
116
|
+
$stdin = STDIN
|
117
|
+
end
|
118
|
+
|
119
|
+
def _prepare(data)
|
120
|
+
## create multipart input
|
121
|
+
multipart = MultiPart.new(@boundary)
|
122
|
+
data.each do |hash|
|
123
|
+
multipart.append(hash[:name], hash[:value], hash[:filename])
|
124
|
+
end
|
125
|
+
input = multipart.close()
|
126
|
+
input = yield(input) if block_given?
|
127
|
+
#$stderr.puts "*** debug: input=\n#{input.collect{|line| line.inspect}.join("\n")}"
|
128
|
+
@boundary ||= multipart.boundary
|
129
|
+
## set environment
|
130
|
+
ENV['CONTENT_TYPE'] = "multipart/form-data; boundary=#{@boundary}"
|
131
|
+
ENV['CONTENT_LENGTH'] = input.length.to_s
|
132
|
+
ENV['REQUEST_METHOD'] = 'POST'
|
133
|
+
## set $stdin
|
134
|
+
tmpfile = Tempfile.new(self.name)
|
135
|
+
tmpfile << input
|
136
|
+
tmpfile.rewind()
|
137
|
+
$stdin = tmpfile
|
138
|
+
end
|
139
|
+
|
140
|
+
def _test_multipart
|
141
|
+
caller(0).find {|s| s =~ /in `test_(.*?)'/ }
|
142
|
+
testname = $1
|
143
|
+
#$stderr.puts "*** debug: testname=#{testname.inspect}"
|
144
|
+
_prepare(@data)
|
145
|
+
cgi = CGI.new
|
146
|
+
expected_names = @data.collect{|hash| hash[:name] }.sort
|
147
|
+
assert_equal(expected_names, cgi.params.keys.sort)
|
148
|
+
threshold = 1024*10
|
149
|
+
@data.each do |hash|
|
150
|
+
name = hash[:name]
|
151
|
+
expected = hash[:value]
|
152
|
+
expected_class = @expected_class || (hash[:value].length < threshold ? StringIO : Tempfile)
|
153
|
+
assert_kind_of(expected_class, cgi[name])
|
154
|
+
assert_equal(expected, cgi[name].read())
|
155
|
+
assert_equal(hash[:filename] || '', cgi[name].original_filename) #if hash[:filename]
|
156
|
+
assert_equal(hash[:content_type] || '', cgi[name].content_type) #if hash[:content_type]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
def _read(basename)
|
162
|
+
filename = File.join(File.dirname(__FILE__), 'testdata', basename)
|
163
|
+
s = File.open(filename, 'rb') {|f| f.read() }
|
164
|
+
return s
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
def test_cgi_multipart_stringio
|
169
|
+
@boundary = '----WebKitFormBoundaryAAfvAII+YL9102cX'
|
170
|
+
@data = [
|
171
|
+
{:name=>'hidden1', :value=>'foobar'},
|
172
|
+
{:name=>'text1', :value=>"\202\240\202\242\202\244\202\246\202\250"},
|
173
|
+
{:name=>'file1', :value=>_read('file1.html'),
|
174
|
+
:filename=>'file1.html', :content_type=>'text/html'},
|
175
|
+
{:name=>'image1', :value=>_read('small.png'),
|
176
|
+
:filename=>'small.png', :content_type=>'image/png'}, # small image
|
177
|
+
]
|
178
|
+
@expected_class = StringIO
|
179
|
+
_test_multipart()
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
def test_cgi_multipart_tempfile
|
184
|
+
@boundary = '----WebKitFormBoundaryAAfvAII+YL9102cX'
|
185
|
+
@data = [
|
186
|
+
{:name=>'hidden1', :value=>'foobar'},
|
187
|
+
{:name=>'text1', :value=>"\202\240\202\242\202\244\202\246\202\250"},
|
188
|
+
{:name=>'file1', :value=>_read('file1.html'),
|
189
|
+
:filename=>'file1.html', :content_type=>'text/html'},
|
190
|
+
{:name=>'image1', :value=>_read('large.png'),
|
191
|
+
:filename=>'large.png', :content_type=>'image/png'}, # large image
|
192
|
+
]
|
193
|
+
@expected_class = Tempfile
|
194
|
+
_test_multipart()
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
def _set_const(klass, name, value)
|
199
|
+
old = nil
|
200
|
+
klass.class_eval do
|
201
|
+
old = const_get(name)
|
202
|
+
remove_const(name)
|
203
|
+
const_set(name, value)
|
204
|
+
end
|
205
|
+
return old
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
def test_cgi_multipart_maxmultipartlength
|
210
|
+
@data = [
|
211
|
+
{:name=>'image1', :value=>_read('large.png'),
|
212
|
+
:filename=>'large.png', :content_type=>'image/png'}, # large image
|
213
|
+
]
|
214
|
+
original = _set_const(CGI, :MAX_MULTIPART_LENGTH, 2 * 1024)
|
215
|
+
begin
|
216
|
+
ex = assert_raise(StandardError) do
|
217
|
+
_test_multipart()
|
218
|
+
end
|
219
|
+
assert_equal("too large multipart data.", ex.message)
|
220
|
+
ensure
|
221
|
+
_set_const(CGI, :MAX_MULTIPART_LENGTH, original)
|
222
|
+
end
|
223
|
+
end if CGI.const_defined?(:MAX_MULTIPART_LENGTH)
|
224
|
+
|
225
|
+
|
226
|
+
def test_cgi_multipart_maxmultipartcount
|
227
|
+
@data = [
|
228
|
+
{:name=>'file1', :value=>_read('file1.html'),
|
229
|
+
:filename=>'file1.html', :content_type=>'text/html'},
|
230
|
+
]
|
231
|
+
item = @data.first
|
232
|
+
500.times { @data << item }
|
233
|
+
#original = _set_const(CGI, :MAX_MULTIPART_COUNT, 128)
|
234
|
+
begin
|
235
|
+
ex = assert_raise(StandardError) do
|
236
|
+
_test_multipart()
|
237
|
+
end
|
238
|
+
assert_equal("too many parameters.", ex.message)
|
239
|
+
ensure
|
240
|
+
#_set_const(CGI, :MAX_MULTIPART_COUNT, original)
|
241
|
+
end
|
242
|
+
end if CGI.const_defined?(:MAX_MULTIPART_COUNT)
|
243
|
+
|
244
|
+
|
245
|
+
def test_cgi_multipart_badbody ## [ruby-dev:28470]
|
246
|
+
@data = [
|
247
|
+
{:name=>'file1', :value=>_read('file1.html'),
|
248
|
+
:filename=>'file1.html', :content_type=>'text/html'},
|
249
|
+
]
|
250
|
+
_prepare(@data) do |input|
|
251
|
+
input2 = input.sub(/--(\r\n)?\z/, "\r\n")
|
252
|
+
assert input2 != input
|
253
|
+
#p input2
|
254
|
+
input2
|
255
|
+
end
|
256
|
+
ex = assert_raise(EOFError) do
|
257
|
+
cgi = CGI.new
|
258
|
+
end
|
259
|
+
assert_equal("bad boundary end of body part", ex.message)
|
260
|
+
#
|
261
|
+
_prepare(@data) do |input|
|
262
|
+
input2 = input.sub(/--(\r\n)?\z/, "")
|
263
|
+
assert input2 != input
|
264
|
+
#p input2
|
265
|
+
input2
|
266
|
+
end
|
267
|
+
ex = assert_raise(EOFError) do
|
268
|
+
cgi = CGI.new
|
269
|
+
end
|
270
|
+
assert_equal("bad content body", ex.message)
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
def test_cgi_multipart_quoteboundary ## [JVN#84798830]
|
275
|
+
@boundary = '(.|\n)*'
|
276
|
+
@data = [
|
277
|
+
{:name=>'hidden1', :value=>'foobar'},
|
278
|
+
{:name=>'text1', :value=>"\202\240\202\242\202\244\202\246\202\250"},
|
279
|
+
{:name=>'file1', :value=>_read('file1.html'),
|
280
|
+
:filename=>'file1.html', :content_type=>'text/html'},
|
281
|
+
{:name=>'image1', :value=>_read('small.png'),
|
282
|
+
:filename=>'small.png', :content_type=>'image/png'}, # small image
|
283
|
+
]
|
284
|
+
_prepare(@data)
|
285
|
+
cgi = CGI.new
|
286
|
+
assert_equal('file1.html', cgi['file1'].original_filename)
|
287
|
+
end
|
288
|
+
|
289
|
+
###
|
290
|
+
|
291
|
+
self.instance_methods.each do |method|
|
292
|
+
private method if method =~ /^test_(.*)/ && $1 != ENV['TEST']
|
293
|
+
end if ENV['TEST']
|
294
|
+
|
295
|
+
end
|