1#!/usr/bin/env perl
2BEGIN {
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;
7}
8
9use strict;
10use IO::Socket;
11use Test::More tests => 36;
12use LightyTest;
13
14my $tf = LightyTest->new();
15my $t;
16
17ok($tf->start_proc == 0, "Starting lighttpd") or die();
18
19## Low-Level Request-Header Parsing - URI
20
21$t->{REQUEST}  = ( <<EOF
22GET /index%2ehtml HTTP/1.0
23EOF
24 );
25$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
26ok($tf->handle_http($t) == 0, 'URL-encoding');
27
28$t->{REQUEST}  = ( <<EOF
29GET /index.html%00 HTTP/1.0
30EOF
31 );
32$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ];
33ok($tf->handle_http($t) == 0, 'URL-encoding, %00');
34
35
36
37## Low-Level Request-Header Parsing - Host
38
39$t->{REQUEST}  = ( <<EOF
40GET / HTTP/1.0
41Host: www.example.org
42EOF
43 );
44$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
45ok($tf->handle_http($t) == 0, 'hostname');
46
47$t->{REQUEST}  = ( <<EOF
48GET / HTTP/1.0
49Host: 127.0.0.1
50EOF
51 );
52$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53ok($tf->handle_http($t) == 0, 'IPv4 address');
54
55$t->{REQUEST}  = ( <<EOF
56GET / HTTP/1.0
57Host: [::1]
58EOF
59 );
60$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
61ok($tf->handle_http($t) == 0, 'IPv6 address');
62
63$t->{REQUEST}  = ( <<EOF
64GET / HTTP/1.0
65Host: www.example.org:80
66EOF
67 );
68$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
69ok($tf->handle_http($t) == 0, 'hostname + port');
70
71$t->{REQUEST}  = ( <<EOF
72GET / HTTP/1.0
73Host: 127.0.0.1:80
74EOF
75 );
76$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
77ok($tf->handle_http($t) == 0, 'IPv4 address + port');
78
79$t->{REQUEST}  = ( <<EOF
80GET / HTTP/1.0
81Host: [::1]:80
82EOF
83 );
84$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
85ok($tf->handle_http($t) == 0, 'IPv6 address + port');
86
87$t->{REQUEST}  = ( <<EOF
88GET / HTTP/1.0
89Host: ../123.org
90EOF
91 );
92$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
93ok($tf->handle_http($t) == 0, 'directory traversal');
94
95$t->{REQUEST}  = ( <<EOF
96GET / HTTP/1.0
97Host: .jsdh.sfdg.sdfg.
98EOF
99 );
100$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
101ok($tf->handle_http($t) == 0, 'leading and trailing dot');
102
103$t->{REQUEST}  = ( <<EOF
104GET / HTTP/1.0
105Host: jsdh.sfdg.sdfg.
106EOF
107 );
108$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
109ok($tf->handle_http($t) == 0, 'trailing dot is ok');
110
111$t->{REQUEST}  = ( <<EOF
112GET / HTTP/1.0
113Host: .jsdh.sfdg.sdfg
114EOF
115 );
116$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
117ok($tf->handle_http($t) == 0, 'leading dot');
118
119
120$t->{REQUEST}  = ( <<EOF
121GET / HTTP/1.0
122Host: jsdh..sfdg.sdfg
123EOF
124 );
125$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
126ok($tf->handle_http($t) == 0, 'two dots');
127
128$t->{REQUEST}  = ( <<EOF
129GET / HTTP/1.0
130Host: jsdh.sfdg.sdfg:asd
131EOF
132 );
133$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
134ok($tf->handle_http($t) == 0, 'broken port-number');
135
136$t->{REQUEST}  = ( <<EOF
137GET / HTTP/1.0
138Host: jsdh.sfdg.sdfg:-1
139EOF
140 );
141$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
142ok($tf->handle_http($t) == 0, 'negative port-number');
143
144
145$t->{REQUEST}  = ( <<EOF
146GET / HTTP/1.0
147Host: :80
148EOF
149 );
150$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
151ok($tf->handle_http($t) == 0, 'port given but host missing');
152
153$t->{REQUEST}  = ( <<EOF
154GET / HTTP/1.0
155Host: .jsdh.sfdg.:sdfg.
156EOF
157 );
158$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
159ok($tf->handle_http($t) == 0, 'port and host are broken');
160
161$t->{REQUEST}  = ( <<EOF
162GET / HTTP/1.0
163Host: a.b-c.d123
164EOF
165 );
166$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
167ok($tf->handle_http($t) == 0, 'allowed characters in host-name');
168
169$t->{REQUEST}  = ( <<EOF
170GET / HTTP/1.0
171Host: -a.c
172EOF
173 );
174$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
175ok($tf->handle_http($t) == 0, 'leading dash');
176
177$t->{REQUEST}  = ( <<EOF
178GET / HTTP/1.0
179Host: .
180EOF
181 );
182$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
183ok($tf->handle_http($t) == 0, 'dot only');
184
185$t->{REQUEST}  = ( <<EOF
186GET / HTTP/1.0
187Host: a192.168.2.10:1234
188EOF
189 );
190$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
191ok($tf->handle_http($t) == 0, 'broken IPv4 address - non-digit');
192
193$t->{REQUEST}  = ( <<EOF
194GET / HTTP/1.0
195Host: 192.168.2:1234
196EOF
197 );
198$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
199ok($tf->handle_http($t) == 0, 'broken IPv4 address - too short');
200
201
202
203## Low-Level Request-Header Parsing - Content-Length
204
205
206$t->{REQUEST}  = ( <<EOF
207GET /index.html HTTP/1.0
208Content-Length: -2
209EOF
210 );
211$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
212ok($tf->handle_http($t) == 0, 'negative Content-Length');
213
214$t->{REQUEST}  = ( <<EOF
215POST /12345.txt HTTP/1.0
216Host: 123.example.org
217Content-Length: 2147483648
218EOF
219 );
220$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 413 } ];
221ok($tf->handle_http($t) == 0, 'Content-Length > max-request-size');
222
223$t->{REQUEST}  = ( <<EOF
224POST /12345.txt HTTP/1.0
225Host: 123.example.org
226Content-Length:
227EOF
228 );
229$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 411 } ];
230ok($tf->handle_http($t) == 0, 'Content-Length is empty');
231
232print "\nLow-Level Request-Header Parsing - HTTP/1.1\n";
233$t->{REQUEST}  = ( <<EOF
234GET / HTTP/1.1
235EOF
236 );
237$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 400 } ];
238ok($tf->handle_http($t) == 0, 'Host missing');
239
240print "\nContent-Type\n";
241$t->{REQUEST}  = ( <<EOF
242GET /image.jpg HTTP/1.0
243EOF
244 );
245$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'image/jpeg' } ];
246ok($tf->handle_http($t) == 0, 'Content-Type - image/jpeg');
247
248$t->{REQUEST}  = ( <<EOF
249GET /image.JPG HTTP/1.0
250EOF
251 );
252$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'image/jpeg' } ];
253ok($tf->handle_http($t) == 0, 'Content-Type - image/jpeg (upper case)');
254
255$t->{REQUEST}  = ( <<EOF
256GET /a HTTP/1.0
257EOF
258 );
259$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'application/octet-stream' } ];
260ok($tf->handle_http($t) == 0, 'Content-Type - unknown');
261
262$t->{REQUEST}  = ( <<EOF
263GET  HTTP/1.0
264EOF
265 );
266$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
267ok($tf->handle_http($t) == 0, 'empty request-URI');
268
269$t->{REQUEST}  = ( <<EOF
270GET /Foo.txt HTTP/1.0
271EOF
272 );
273$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
274ok($tf->handle_http($t) == 0, 'uppercase filenames');
275
276$t->{REQUEST}  = ( <<EOF
277GET / HTTP/1.0
278Location: foo
279Location: foobar
280  baz
281EOF
282 );
283$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
284ok($tf->handle_http($t) == 0, '#1232 - duplicate headers with line-wrapping');
285
286$t->{REQUEST}  = ( <<EOF
287GET / HTTP/1.0
288Location:
289Location: foobar
290  baz
291EOF
292 );
293$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
294ok($tf->handle_http($t) == 0, '#1232 - duplicate headers with line-wrapping - test 2');
295
296$t->{REQUEST}  = ( <<EOF
297GET / HTTP/1.0
298A:
299Location: foobar
300  baz
301EOF
302 );
303$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
304ok($tf->handle_http($t) == 0, '#1232 - duplicate headers with line-wrapping - test 3');
305
306
307
308
309ok($tf->stop_proc == 0, "Stopping lighttpd");
310
311