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