[core] stay in CON_STATE_CLOSE until done with req
[lighttpd.git] / tests / request.t
bloba1ff4db0a60b4da3eeeb2f10be767f5fea217d58
1 #!/usr/bin/env perl
2 BEGIN {
3 # add current source dir to the include-path
4 # we need this for make distcheck
5 (my $srcdir = $0) =~ s,/[^/]+$,/,;
6 unshift @INC, $srcdir;
9 use strict;
10 use IO::Socket;
11 use Test::More tests => 52;
12 use LightyTest;
14 my $tf = LightyTest->new();
15 my $t;
17 ok($tf->start_proc == 0, "Starting lighttpd") or die();
19 ## Basic Request-Handling
21 $t->{REQUEST} = ( <<EOF
22 GET /foobar HTTP/1.0
23 EOF
25 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ];
26 ok($tf->handle_http($t) == 0, 'file not found');
28 $t->{REQUEST} = ( <<EOF
29 GET /foobar?foobar HTTP/1.0
30 EOF
32 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ];
33 ok($tf->handle_http($t) == 0, 'file not found + querystring');
35 $t->{REQUEST} = ( <<EOF
36 GET /12345.txt HTTP/1.0
37 Host: 123.example.org
38 EOF
40 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain' } ];
41 ok($tf->handle_http($t) == 0, 'GET, content == 12345, mimetype text/plain');
43 $t->{REQUEST} = ( <<EOF
44 GET /12345.html HTTP/1.0
45 Host: 123.example.org
46 EOF
48 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/html' } ];
49 ok($tf->handle_http($t) == 0, 'GET, content == 12345, mimetype text/html');
51 $t->{REQUEST} = ( <<EOF
52 GET /dummyfile.bla HTTP/1.0
53 Host: 123.example.org
54 EOF
56 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'application/octet-stream' } ];
57 ok($tf->handle_http($t) == 0, 'GET, content == 12345, mimetype application/octet-stream');
59 $t->{REQUEST} = ( <<EOF
60 POST / HTTP/1.0
61 EOF
63 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 411 } ];
64 ok($tf->handle_http($t) == 0, 'POST request, no Content-Length');
67 $t->{REQUEST} = ( <<EOF
68 POST / HTTP/1.0
69 Content-type: application/x-www-form-urlencoded
70 Content-length: 0
71 EOF
73 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
74 ok($tf->handle_http($t) == 0, 'POST request, empty request-body');
76 $t->{REQUEST} = ( <<EOF
77 HEAD / HTTP/1.0
78 EOF
80 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-HTTP-Content' => ''} ];
81 ok($tf->handle_http($t) == 0, 'HEAD request, no content');
83 $t->{REQUEST} = ( <<EOF
84 HEAD /12345.html HTTP/1.0
85 Host: 123.example.org
86 EOF
88 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-HTTP-Content' => '', 'Content-Type' => 'text/html', 'Content-Length' => '6'} ];
89 ok($tf->handle_http($t) == 0, 'HEAD request, mimetype text/html, content-length');
91 $t->{REQUEST} = ( <<EOF
92 HEAD http://123.example.org/12345.html HTTP/1.1
93 Connection: close
94 EOF
96 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, '-HTTP-Content' => '', 'Content-Type' => 'text/html', 'Content-Length' => '6'} ];
97 ok($tf->handle_http($t) == 0, 'Hostname in first line, HTTP/1.1');
99 $t->{REQUEST} = ( <<EOF
100 HEAD https://123.example.org/12345.html HTTP/1.0
103 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-HTTP-Content' => '', 'Content-Type' => 'text/html', 'Content-Length' => '6'} ];
104 ok($tf->handle_http($t) == 0, 'Hostname in first line as https url');
106 $t->{REQUEST} = ( <<EOF
107 HEAD /foobar?foobar HTTP/1.0
110 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, '-HTTP-Content' => '' } ];
111 ok($tf->handle_http($t) == 0, 'HEAD request, file-not-found, query-string');
113 $t->{REQUEST} = ( <<EOF
114 GET / HTTP/1.1
115 Connection: close
116 Expect: 100-continue
119 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 417 } ];
120 ok($tf->handle_http($t) == 0, 'Continue, Expect');
122 ## ranges
124 $t->{REQUEST} = ( <<EOF
125 GET /12345.txt HTTP/1.0
126 Host: 123.example.org
127 Range: bytes=0-3
130 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 206, 'HTTP-Content' => '1234' } ];
131 ok($tf->handle_http($t) == 0, 'GET, Range 0-3');
133 $t->{REQUEST} = ( <<EOF
134 GET /12345.txt HTTP/1.0
135 Host: 123.example.org
136 Range: bytes=-3
139 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 206, 'HTTP-Content' => '45'."\n" } ];
140 ok($tf->handle_http($t) == 0, 'GET, Range -3');
142 $t->{REQUEST} = ( <<EOF
143 GET /12345.txt HTTP/1.0
144 Host: 123.example.org
145 Range: bytes=3-
148 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 206, 'HTTP-Content' => '45'."\n" } ];
149 ok($tf->handle_http($t) == 0, 'GET, Range 3-');
151 $t->{REQUEST} = ( <<EOF
152 GET /12345.txt HTTP/1.0
153 Host: 123.example.org
154 Range: bytes=0-1,3-4
157 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 206, 'HTTP-Content' => <<EOF
159 --fkj49sn38dcn3\r
160 Content-Range: bytes 0-1/6\r
161 Content-Type: text/plain\r
163 12\r
164 --fkj49sn38dcn3\r
165 Content-Range: bytes 3-4/6\r
166 Content-Type: text/plain\r
168 45\r
169 --fkj49sn38dcn3--\r
171 } ];
172 ok($tf->handle_http($t) == 0, 'GET, Range 0-1,3-4');
174 $t->{REQUEST} = ( <<EOF
175 GET /12345.txt HTTP/1.0
176 Host: 123.example.org
177 Range: bytes=0--
180 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
181 ok($tf->handle_http($t) == 0, 'GET, Range 0--');
183 $t->{REQUEST} = ( <<EOF
184 GET /12345.txt HTTP/1.0
185 Host: 123.example.org
186 Range: bytes=-2-3
189 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
190 ok($tf->handle_http($t) == 0, 'GET, Range -2-3');
192 $t->{REQUEST} = ( <<EOF
193 GET /12345.txt HTTP/1.0
194 Host: 123.example.org
195 Range: bytes=-0
198 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 416, 'HTTP-Content' => <<EOF
199 <?xml version="1.0" encoding="iso-8859-1"?>
200 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
201 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
202 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
203 <head>
204 <title>416 - Requested Range Not Satisfiable</title>
205 </head>
206 <body>
207 <h1>416 - Requested Range Not Satisfiable</h1>
208 </body>
209 </html>
211 } ];
212 ok($tf->handle_http($t) == 0, 'GET, Range -0');
214 $t->{REQUEST} = ( <<EOF
215 GET /12345.txt HTTP/1.0
216 Host: 123.example.org
217 Range: bytes=25-
220 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 416, 'HTTP-Content' => <<EOF
221 <?xml version="1.0" encoding="iso-8859-1"?>
222 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
223 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
224 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
225 <head>
226 <title>416 - Requested Range Not Satisfiable</title>
227 </head>
228 <body>
229 <h1>416 - Requested Range Not Satisfiable</h1>
230 </body>
231 </html>
233 } ];
235 ok($tf->handle_http($t) == 0, 'GET, Range start out of range');
238 $t->{REQUEST} = ( <<EOF
239 GET / HTTP/1.0
240 Hsgfsdjf: asdfhdf
241 hdhd: shdfhfdasd
242 hfhr: jfghsdfg
243 jfuuehdmn: sfdgjfdg
244 jvcbzufdg: sgfdfg
245 hrnvcnd: jfjdfg
246 jfusfdngmd: gfjgfdusdfg
247 nfj: jgfdjdfg
248 jfue: jfdfdg
251 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
252 ok($tf->handle_http($t) == 0, 'larger headers');
255 $t->{REQUEST} = ( <<EOF
256 GET / HTTP/1.0
257 Host: www.example.org
258 Host: 123.example.org
261 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
262 ok($tf->handle_http($t) == 0, 'Duplicate Host headers, Bug #25');
265 $t->{REQUEST} = ( <<EOF
266 GET / HTTP/1.0
267 Content-Length: 5
268 Content-Length: 4
271 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
272 ok($tf->handle_http($t) == 0, 'Duplicate Content-Length headers');
274 $t->{REQUEST} = ( <<EOF
275 GET / HTTP/1.0
276 Content-Type: 5
277 Content-Type: 4
280 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
281 ok($tf->handle_http($t) == 0, 'Duplicate Content-Type headers');
283 $t->{REQUEST} = ( <<EOF
284 GET / HTTP/1.0
285 Range: bytes=5-6
286 Range: bytes=5-9
289 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
290 ok($tf->handle_http($t) == 0, 'Duplicate Range headers');
292 $t->{REQUEST} = ( <<EOF
293 GET / HTTP/1.0
294 If-None-Match: 5
295 If-None-Match: 4
298 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
299 ok($tf->handle_http($t) == 0, 'Duplicate If-None-Match headers');
301 $t->{REQUEST} = ( <<EOF
302 GET / HTTP/1.0
303 If-Modified-Since: 5
304 If-Modified-Since: 4
307 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
308 ok($tf->handle_http($t) == 0, 'Duplicate If-Modified-Since headers');
310 $t->{REQUEST} = ( <<EOF
311 GET /range.pdf HTTP/1.0
312 Range: bytes=0-
315 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
316 ok($tf->handle_http($t) == 0, 'GET, Range with range-requests-disabled');
318 $t->{REQUEST} = ( <<EOF
319 GET / HTTP/1.0
320 Content-Length: 4
322 1234
325 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
326 ok($tf->handle_http($t) == 0, 'GET with Content-Length');
328 $t->{REQUEST} = ( <<EOF
329 OPTIONS / HTTP/1.0
330 Content-Length: 4
332 1234
335 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
336 ok($tf->handle_http($t) == 0, 'OPTIONS with Content-Length');
338 $t->{REQUEST} = ( <<EOF
339 OPTIONS rtsp://221.192.134.146:80 RTSP/1.1
340 Host: 221.192.134.146:80
343 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
344 ok($tf->handle_http($t) == 0, 'OPTIONS for RTSP');
346 $t->{REQUEST} = ( <<EOF
347 HEAD / HTTP/1.0
348 Content-Length: 4
350 1234
353 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
354 ok($tf->handle_http($t) == 0, 'HEAD with Content-Length');
356 $t->{REQUEST} = ( <<EOF
357 GET /index.html HTTP/1.0
358 If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
359 If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
362 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
363 ok($tf->handle_http($t) == 0, 'Duplicate If-Mod-Since, with equal timestamps');
365 $t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: \0\r\n\r\n" );
366 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
367 ok($tf->handle_http($t) == 0, 'invalid chars in Header values (bug #1286)');
369 $t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: \r\n\r\n" );
370 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
371 ok($tf->handle_http($t) == 0, 'empty If-Modified-Since');
373 $t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: foobar\r\n\r\n" );
374 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
375 ok($tf->handle_http($t) == 0, 'broken If-Modified-Since');
377 $t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: this string is too long to be a valid timestamp\r\n\r\n" );
378 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
379 ok($tf->handle_http($t) == 0, 'broken If-Modified-Since');
382 $t->{REQUEST} = ( <<EOF
383 GET /index.html HTTP/1.0
384 If-Modified-Since2: Sun, 01 Jan 2036 00:00:03 GMT
385 If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
388 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
389 ok($tf->handle_http($t) == 0, 'Similar Headers (bug #1287)');
391 $t->{REQUEST} = ( <<EOF
392 GET /index.html HTTP/1.0
393 If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
396 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, 'Content-Type' => 'text/html' } ];
397 ok($tf->handle_http($t) == 0, 'If-Modified-Since');
399 $t->{REQUEST} = ( <<EOF
400 GET /index.html HTTP/1.0
401 If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
404 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, '-Content-Length' => '' } ];
405 ok($tf->handle_http($t) == 0, 'Status 304 has no Content-Length (#1002)');
407 $t->{REQUEST} = ( <<EOF
408 GET /12345.txt HTTP/1.0
409 Host: 123.example.org
412 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain' } ];
413 $t->{SLOWREQUEST} = 1;
414 ok($tf->handle_http($t) == 0, 'GET, slow \\r\\n\\r\\n (#2105)');
415 undef $t->{SLOWREQUEST};
417 print "\nPathinfo for static files\n";
418 $t->{REQUEST} = ( <<EOF
419 GET /image.jpg/index.php HTTP/1.0
422 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'image/jpeg' } ];
423 ok($tf->handle_http($t) == 0, 'static file accepting pathinfo by default');
425 $t->{REQUEST} = ( <<EOF
426 GET /image.jpg/index.php HTTP/1.0
427 Host: zzz.example.org
430 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
431 ok($tf->handle_http($t) == 0, 'static file with forbidden pathinfo');
434 print "\nConnection header\n";
435 $t->{REQUEST} = ( <<EOF
436 GET /12345.txt HTTP/1.1
437 Connection : close
438 Host: 123.example.org
441 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ];
442 ok($tf->handle_http($t) == 0, 'Connection-header, spaces before ":"');
444 $t->{REQUEST} = ( <<EOF
445 GET /12345.txt HTTP/1.1
446 Connection: ,close
447 Host: 123.example.org
450 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ];
451 ok($tf->handle_http($t) == 0, 'Connection-header, leading comma');
453 $t->{REQUEST} = ( <<EOF
454 GET /12345.txt HTTP/1.1
455 Connection: close,,TE
456 Host: 123.example.org
459 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ];
460 ok($tf->handle_http($t) == 0, 'Connection-header, no value between two commas');
462 $t->{REQUEST} = ( <<EOF
463 GET /12345.txt HTTP/1.1
464 Connection: close, ,TE
465 Host: 123.example.org
468 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ];
469 ok($tf->handle_http($t) == 0, 'Connection-header, space between two commas');
471 $t->{REQUEST} = ( <<EOF
472 GET /12345.txt HTTP/1.1
473 Connection: close,
474 Host: 123.example.org
477 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ];
478 ok($tf->handle_http($t) == 0, 'Connection-header, comma after value');
480 $t->{REQUEST} = ( <<EOF
481 GET /12345.txt HTTP/1.1
482 Connection: close,
483 Host: 123.example.org
486 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ];
487 ok($tf->handle_http($t) == 0, 'Connection-header, comma and space after value');
489 ok($tf->stop_proc == 0, "Stopping lighttpd");