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 => 164; 12use LightyTest; 13 14my $tf = LightyTest->new(); 15my $t; 16 17ok($tf->start_proc == 0, "Starting lighttpd") or die(); 18 19## Basic Request-Handling 20 21$t->{REQUEST} = ( <<EOF 22GET / HTTP/1.0 23EOF 24 ); 25$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 26ok($tf->handle_http($t) == 0, 'Valid HTTP/1.0 Request') or ($tf->stop_proc, die()); 27 28$t->{REQUEST} = ( <<EOF 29OPTIONS * HTTP/1.0 30EOF 31 ); 32$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 33ok($tf->handle_http($t) == 0, 'OPTIONS'); 34 35$t->{REQUEST} = ( <<EOF 36OPTIONS / HTTP/1.1 37Host: www.example.org 38Connection: close 39EOF 40 ); 41$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 42ok($tf->handle_http($t) == 0, 'OPTIONS'); 43 44$t->{REQUEST} = ( <<EOF 45GET /index.html%00 HTTP/1.0 46EOF 47 ); 48$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; 49ok($tf->handle_http($t) == 0, 'URL-encoding, %00'); 50 51$t->{REQUEST} = ( <<EOF 52POST /12345.txt HTTP/1.0 53Host: 123.example.org 54Content-Length: 2147483648 55EOF 56 ); 57$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 413 } ]; 58ok($tf->handle_http($t) == 0, 'Content-Length > max-request-size'); 59 60$t->{REQUEST} = ( <<EOF 61GET /image.jpg HTTP/1.0 62EOF 63 ); 64$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'image/jpeg' } ]; 65ok($tf->handle_http($t) == 0, 'Content-Type - image/jpeg'); 66 67$t->{REQUEST} = ( <<EOF 68GET /image.JPG HTTP/1.0 69EOF 70 ); 71$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'image/jpeg' } ]; 72ok($tf->handle_http($t) == 0, 'Content-Type - image/jpeg (upper case)'); 73 74$t->{REQUEST} = ( <<EOF 75GET /Foo.txt HTTP/1.0 76EOF 77 ); 78$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 79ok($tf->handle_http($t) == 0, 'uppercase filenames'); 80 81$t->{REQUEST} = ( <<EOF 82GET /foobar?foobar HTTP/1.0 83EOF 84 ); 85$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; 86ok($tf->handle_http($t) == 0, 'file not found + querystring'); 87 88$t->{REQUEST} = ( <<EOF 89GET /12345.txt HTTP/1.0 90Host: 123.example.org 91EOF 92 ); 93$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain' } ]; 94ok($tf->handle_http($t) == 0, 'GET, content == 12345, mimetype text/plain'); 95 96$t->{REQUEST} = ( <<EOF 97GET /12345.html HTTP/1.0 98Host: 123.example.org 99EOF 100 ); 101$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/html' } ]; 102ok($tf->handle_http($t) == 0, 'GET, content == 12345, mimetype text/html'); 103 104 105$t->{REQUEST} = ( <<EOF 106POST / HTTP/1.0 107Content-type: application/x-www-form-urlencoded 108Content-length: 0 109EOF 110 ); 111$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 112ok($tf->handle_http($t) == 0, 'POST request, empty request-body'); 113 114$t->{REQUEST} = ( <<EOF 115HEAD / HTTP/1.0 116EOF 117 ); 118$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-HTTP-Content' => ''} ]; 119ok($tf->handle_http($t) == 0, 'HEAD request, no content'); 120 121$t->{REQUEST} = ( <<EOF 122HEAD /12345.html HTTP/1.0 123Host: 123.example.org 124EOF 125 ); 126$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-HTTP-Content' => '', 'Content-Type' => 'text/html', 'Content-Length' => '6'} ]; 127ok($tf->handle_http($t) == 0, 'HEAD request, mimetype text/html, content-length'); 128 129$t->{REQUEST} = ( <<EOF 130HEAD http://123.example.org/12345.html HTTP/1.1 131Connection: close 132EOF 133 ); 134$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, '-HTTP-Content' => '', 'Content-Type' => 'text/html', 'Content-Length' => '6'} ]; 135ok($tf->handle_http($t) == 0, 'Hostname in first line, HTTP/1.1'); 136 137$t->{REQUEST} = ( <<EOF 138HEAD https://123.example.org/12345.html HTTP/1.0 139EOF 140 ); 141$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-HTTP-Content' => '', 'Content-Type' => 'text/html', 'Content-Length' => '6'} ]; 142ok($tf->handle_http($t) == 0, 'Hostname in first line as https url'); 143 144$t->{REQUEST} = ( <<EOF 145HEAD /foobar?foobar HTTP/1.0 146EOF 147 ); 148$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, '-HTTP-Content' => '' } ]; 149ok($tf->handle_http($t) == 0, 'HEAD request, file-not-found, query-string'); 150 151# (expect 200 OK instead of 100 Continue since request body sent with request) 152# (if we waited to send request body, would expect 100 Continue, first) 153$t->{REQUEST} = ( <<EOF 154POST /cgi.pl?post-len HTTP/1.1 155Host: www.example.org 156Connection: close 157Content-Type: application/x-www-form-urlencoded 158Content-Length: 4 159Expect: 100-continue 160 161123 162EOF 163 ); 164$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 165ok($tf->handle_http($t) == 0, 'Continue, Expect'); 166 167# note Transfer-Encoding: chunked tests will fail with 411 Length Required if 168# server.stream-request-body != 0 in lighttpd.conf 169$t->{REQUEST} = ( <<EOF 170POST /cgi.pl?post-len HTTP/1.1 171Host: www.example.org 172Connection: close 173Content-Type: application/x-www-form-urlencoded 174Transfer-Encoding: chunked 175 176a 1770123456789 1780 179 180EOF 181 ); 182$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 183ok($tf->handle_http($t) == 0, 'POST via Transfer-Encoding: chunked, lc hex'); 184 185$t->{REQUEST} = ( <<EOF 186POST /cgi.pl?post-len HTTP/1.1 187Host: www.example.org 188Connection: close 189Content-Type: application/x-www-form-urlencoded 190Transfer-Encoding: chunked 191 192A 1930123456789 1940 195 196EOF 197 ); 198$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 199ok($tf->handle_http($t) == 0, 'POST via Transfer-Encoding: chunked, uc hex'); 200 201$t->{REQUEST} = ( <<EOF 202POST /cgi.pl?post-len HTTP/1.1 203Host: www.example.org 204Connection: close 205Content-Type: application/x-www-form-urlencoded 206Transfer-Encoding: chunked 207 20810 2090123456789abcdef 2100 211 212EOF 213 ); 214$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 215ok($tf->handle_http($t) == 0, 'POST via Transfer-Encoding: chunked, two hex'); 216 217$t->{REQUEST} = ( <<EOF 218POST /cgi.pl?post-len HTTP/1.1 219Host: www.example.org 220Connection: close 221Content-Type: application/x-www-form-urlencoded 222Transfer-Encoding: chunked 223 224a 2250123456789 2260 227Test-Trailer: testing 228 229EOF 230 ); 231$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 232ok($tf->handle_http($t) == 0, 'POST via Transfer-Encoding: chunked, with trailer'); 233 234$t->{REQUEST} = ( <<EOF 235POST /cgi.pl?post-len HTTP/1.1 236Host: www.example.org 237Connection: close 238Content-Type: application/x-www-form-urlencoded 239Transfer-Encoding: chunked 240 241a; comment 2420123456789 2430 244 245EOF 246 ); 247$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 248ok($tf->handle_http($t) == 0, 'POST via Transfer-Encoding: chunked, chunked header comment'); 249 250$t->{REQUEST} = ( <<EOF 251POST /cgi.pl?post-len HTTP/1.1 252Host: www.example.org 253Connection: close 254Content-Type: application/x-www-form-urlencoded 255Transfer-Encoding: chunked 256 257az 2580123456789 2590 260 261EOF 262 ); 263$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 400 } ]; 264ok($tf->handle_http($t) == 0, 'POST via Transfer-Encoding: chunked; bad chunked header'); 265 266$t->{REQUEST} = ( <<EOF 267POST /cgi.pl?post-len HTTP/1.1 268Host: www.example.org 269Connection: close 270Content-Type: application/x-www-form-urlencoded 271Transfer-Encoding: chunked 272 273a 2740123456789xxxxxxxx 2750 276 277EOF 278 ); 279$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 400 } ]; 280ok($tf->handle_http($t) == 0, 'POST via Transfer-Encoding: chunked; mismatch chunked header size and chunked data size'); 281 282$t->{REQUEST} = ( <<EOF 283POST /cgi.pl?post-len HTTP/1.1 284Host: www.example.org 285Connection: close 286Content-Type: application/x-www-form-urlencoded 287Transfer-Encoding: chunked 288 289a ; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 2900123456789 2910 292 293EOF 294 ); 295$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 400 } ]; 296ok($tf->handle_http($t) == 0, 'POST via Transfer-Encoding: chunked; chunked header too long'); 297 298## ranges 299 300$t->{REQUEST} = ( <<EOF 301GET /12345.txt HTTP/1.1 302Host: 123.example.org 303Connection: close 304Range: bytes=0-3 305EOF 306 ); 307$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 206, 'HTTP-Content' => '1234' } ]; 308ok($tf->handle_http($t) == 0, 'GET, Range 0-3'); 309 310$t->{REQUEST} = ( <<EOF 311GET /12345.txt HTTP/1.1 312Host: 123.example.org 313Connection: close 314Range: bytes=-3 315EOF 316 ); 317$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 206, 'HTTP-Content' => '45'."\n" } ]; 318ok($tf->handle_http($t) == 0, 'GET, Range -3'); 319 320$t->{REQUEST} = ( <<EOF 321GET /12345.txt HTTP/1.1 322Host: 123.example.org 323Connection: close 324Range: bytes=3- 325EOF 326 ); 327$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 206, 'HTTP-Content' => '45'."\n" } ]; 328ok($tf->handle_http($t) == 0, 'GET, Range 3-'); 329 330$t->{REQUEST} = ( <<EOF 331GET /12345.txt HTTP/1.1 332Host: 123.example.org 333Connection: close 334Range: bytes=0-1,3-4 335EOF 336 ); 337$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 206, 'HTTP-Content' => '12345' } ]; 338ok($tf->handle_http($t) == 0, 'GET, Range 0-1,3-4 (ranges merged)'); 339 340$t->{REQUEST} = ( <<EOF 341GET /100.txt HTTP/1.1 342Host: 123.example.org 343Connection: close 344Range: bytes=0-1,97-98 345EOF 346 ); 347$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 206, 'HTTP-Content' => <<EOF 348--fkj49sn38dcn3\r 349Content-Type: text/plain\r 350Content-Range: bytes 0-1/100\r 351\r 35212\r 353--fkj49sn38dcn3\r 354Content-Type: text/plain\r 355Content-Range: bytes 97-98/100\r 356\r 357hi\r 358--fkj49sn38dcn3--\r 359EOF 360 } ]; 361ok($tf->handle_http($t) == 0, 'GET, Range 0-1,97-98 (ranges not merged)'); 362 363$t->{REQUEST} = ( <<EOF 364GET /12345.txt HTTP/1.1 365Host: 123.example.org 366Connection: close 367Range: bytes=0- 368EOF 369 ); 370$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 206, 'Content-Range' => 'bytes 0-5/6' } ]; 371ok($tf->handle_http($t) == 0, 'GET, Range 0-'); 372 373$t->{REQUEST} = ( <<EOF 374GET /12345.txt HTTP/1.1 375Host: 123.example.org 376Connection: close 377Range: bytes=0-- 378EOF 379 ); 380$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 416 } ]; 381ok($tf->handle_http($t) == 0, 'GET, Range 0--'); 382 383$t->{REQUEST} = ( <<EOF 384GET /12345.txt HTTP/1.1 385Host: 123.example.org 386Connection: close 387Range: bytes=-2-3 388EOF 389 ); 390$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 416 } ]; 391ok($tf->handle_http($t) == 0, 'GET, Range -2-3'); 392 393$t->{REQUEST} = ( <<EOF 394GET /12345.txt HTTP/1.1 395Host: 123.example.org 396Connection: close 397Range: bytes=-0 398EOF 399 ); 400$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 416, 'HTTP-Content' => <<EOF 401<?xml version="1.0" encoding="iso-8859-1"?> 402<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 403 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 404<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 405 <head> 406 <title>416 Range Not Satisfiable</title> 407 </head> 408 <body> 409 <h1>416 Range Not Satisfiable</h1> 410 </body> 411</html> 412EOF 413 } ]; 414ok($tf->handle_http($t) == 0, 'GET, Range -0'); 415 416$t->{REQUEST} = ( <<EOF 417GET /12345.txt HTTP/1.1 418Host: 123.example.org 419Connection: close 420Range: bytes=25- 421EOF 422 ); 423$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 416, 'HTTP-Content' => <<EOF 424<?xml version="1.0" encoding="iso-8859-1"?> 425<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 426 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 427<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 428 <head> 429 <title>416 Range Not Satisfiable</title> 430 </head> 431 <body> 432 <h1>416 Range Not Satisfiable</h1> 433 </body> 434</html> 435EOF 436 } ]; 437 438ok($tf->handle_http($t) == 0, 'GET, Range start out of range'); 439 440 441$t->{REQUEST} = ( <<EOF 442GET /range.disabled HTTP/1.1 443Host: 123.example.org 444Range: bytes=0- 445Connection: close 446EOF 447 ); 448$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 449ok($tf->handle_http($t) == 0, 'GET, Range with range-requests-disabled'); 450 451$t->{REQUEST} = ( <<EOF 452GET /12345.txt HTTP/1.1 453Host: 123.example.org 454Connection: close 455Range: 0 456Range: bytes=0-3 457EOF 458 ); 459$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => "12345\n" } ]; 460ok($tf->handle_http($t) == 0, 'GET, Range invalid range-unit (first)'); 461 462$t->{REQUEST} = ( <<EOF 463GET /12345.txt HTTP/1.1 464Host: 123.example.org 465Connection: close 466Range: bytes=0-3 467Range: 0 468EOF 469 ); 470$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 206 } ]; 471ok($tf->handle_http($t) == 0, 'GET, Range ignore invalid range (second)'); 472 473$t->{REQUEST} = ( <<EOF 474OPTIONS / HTTP/1.0 475Content-Length: 4 476 4771234 478EOF 479 ); 480$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 481ok($tf->handle_http($t) == 0, 'OPTIONS with Content-Length'); 482 483$t->{REQUEST} = ( <<EOF 484OPTIONS rtsp://221.192.134.146:80 RTSP/1.1 485Host: 221.192.134.146:80 486EOF 487 ); 488$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; 489ok($tf->handle_http($t) == 0, 'OPTIONS for RTSP'); 490 491my $nextyr = (gmtime(time()))[5] + 1900 + 1; 492 493$t->{REQUEST} = ( <<EOF 494GET /index.html HTTP/1.0 495If-Modified-Since2: Sun, 01 Jan $nextyr 00:00:03 GMT 496If-Modified-Since: Sun, 01 Jan $nextyr 00:00:02 GMT 497EOF 498 ); 499$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; 500ok($tf->handle_http($t) == 0, 'Similar Headers (bug #1287)'); 501 502$t->{REQUEST} = ( <<EOF 503GET /index.html HTTP/1.0 504If-Modified-Since: Sun, 01 Jan $nextyr 00:00:02 GMT 505EOF 506 ); 507$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, '-Content-Length' => '', 'Content-Type' => 'text/html' } ]; 508ok($tf->handle_http($t) == 0, 'Status 304 has no Content-Length (#1002)'); 509 510$t->{REQUEST} = ( <<EOF 511GET /12345.txt HTTP/1.0 512Host: 123.example.org 513EOF 514 ); 515$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain' } ]; 516$t->{SLOWREQUEST} = 1; 517ok($tf->handle_http($t) == 0, 'GET, slow \\r\\n\\r\\n (#2105)'); 518undef $t->{SLOWREQUEST}; 519 520$t->{REQUEST} = ( <<EOF 521GET /www/abc/def HTTP/1.0 522EOF 523 ); 524$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; 525ok($tf->handle_http($t) == 0, 'pathinfo on a directory'); 526 527 528$t->{REQUEST} = ( <<EOF 529GET /12345.txt HTTP/1.1 530Connection: ,close 531Host: 123.example.org 532EOF 533 ); 534$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ]; 535ok($tf->handle_http($t) == 0, 'Connection-header, leading comma'); 536 537$t->{REQUEST} = ( <<EOF 538GET /12345.txt HTTP/1.1 539Connection: close,,TE 540Host: 123.example.org 541EOF 542 ); 543$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ]; 544ok($tf->handle_http($t) == 0, 'Connection-header, no value between two commas'); 545 546$t->{REQUEST} = ( <<EOF 547GET /12345.txt HTTP/1.1 548Connection: close, ,TE 549Host: 123.example.org 550EOF 551 ); 552$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ]; 553ok($tf->handle_http($t) == 0, 'Connection-header, space between two commas'); 554 555$t->{REQUEST} = ( <<EOF 556GET /12345.txt HTTP/1.1 557Connection: close, 558Host: 123.example.org 559EOF 560 ); 561$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ]; 562ok($tf->handle_http($t) == 0, 'Connection-header, comma after value'); 563 564$t->{REQUEST} = ( <<EOF 565GET /12345.txt HTTP/1.1 566Connection: close, 567Host: 123.example.org 568EOF 569 ); 570$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/plain', 'Connection' => 'close' } ]; 571ok($tf->handle_http($t) == 0, 'Connection-header, comma and space after value'); 572 573 574## Low-Level Response-Header Parsing - HTTP/1.1 575 576$t->{REQUEST} = ( <<EOF 577GET / HTTP/1.1 578Host: www.example.org 579Connection: close 580EOF 581 ); 582$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, '+Date' => '' } ]; 583ok($tf->handle_http($t) == 0, 'Date header'); 584 585 586## Low-Level Response-Header Parsing - Content-Length 587 588 589$t->{REQUEST} = ( <<EOF 590GET /12345.html HTTP/1.0 591Host: 123.example.org 592EOF 593 ); 594$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Length' => '6' } ]; 595ok($tf->handle_http($t) == 0, 'Content-Length for text/html'); 596 597$t->{REQUEST} = ( <<EOF 598GET /12345.txt HTTP/1.0 599Host: 123.example.org 600EOF 601 ); 602$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Length' => '6' } ]; 603ok($tf->handle_http($t) == 0, 'Content-Length for text/plain'); 604 605 606## Low-Level Response-Header Parsing - Location 607 608$t->{REQUEST} = ( <<EOF 609GET /dummydir HTTP/1.0 610EOF 611 ); 612$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => '/dummydir/' } ]; 613ok($tf->handle_http($t) == 0, 'internal redirect in directory'); 614 615$t->{REQUEST} = ( <<EOF 616GET /dummydir?foo HTTP/1.0 617EOF 618 ); 619$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => '/dummydir/?foo' } ]; 620ok($tf->handle_http($t) == 0, 'internal redirect in directory + querystring'); 621 622$t->{REQUEST} = ( <<EOF 623GET /~test%20ä_ HTTP/1.0 624EOF 625 ); 626$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => '/~test%20%C3%A4_/' } ]; 627ok($tf->handle_http($t) == 0, 'internal redirect in directory with special characters'); 628 629$t->{REQUEST} = ( <<EOF 630GET /~test%20ä_?foo HTTP/1.0 631EOF 632 ); 633$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => '/~test%20%C3%A4_/?foo' } ]; 634ok($tf->handle_http($t) == 0, 'internal redirect in directory with special characters + querystring'); 635 636 637## simple-vhost 638 639$t->{REQUEST} = ( <<EOF 640GET /12345.txt HTTP/1.0 641Host: no-simple.example.org 642EOF 643 ); 644$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Length' => '6' } ]; 645ok($tf->handle_http($t) == 0, 'disabling simple-vhost via conditionals'); 646 647$t->{REQUEST} = ( <<EOF 648GET /12345.txt HTTP/1.0 649Host: simple.example.org 650EOF 651 ); 652$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; 653ok($tf->handle_http($t) == 0, 'simple-vhost via conditionals'); 654 655 656## keep-alive 657 658$t->{REQUEST} = ( <<EOF 659GET /12345.txt HTTP/1.0 660Connection: keep-alive 661Host: 123.example.org 662 663GET /12345.txt HTTP/1.0 664Host: 123.example.org 665Connection: close 666EOF 667 ); 668$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 669ok($tf->handle_http($t) == 0, 'Explicit HTTP/1.0 Keep-Alive'); 670undef $t->{RESPONSE}; 671 672$t->{REQUEST} = ( <<EOF 673GET /12345.txt HTTP/1.0 674Connection: keep-alive 675Host: 123.example.org 676 677GET /12345.txt HTTP/1.0 678Host: 123.example.org 679Connection: close 680EOF 681 ); 682$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 683ok($tf->handle_http($t) == 0, 'Explicit HTTP/1.0 Keep-Alive'); 684undef $t->{RESPONSE}; 685 686$t->{REQUEST} = ( <<EOF 687GET /12345.txt HTTP/1.0 688Connection: keep-alive 689Host: 123.example.org 690 691GET /12345.txt HTTP/1.0 692Host: 123.example.org 693EOF 694 ); 695$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 696ok($tf->handle_http($t) == 0, 'Implicit HTTP/1.0 Keep-Alive'); 697 698$t->{REQUEST} = ( <<EOF 699GET /12345.txt HTTP/1.1 700Connection: keep-alive 701Host: 123.example.org 702 703GET /12345.txt HTTP/1.1 704Host: 123.example.org 705Connection: close 706EOF 707 ); 708$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 709ok($tf->handle_http($t) == 0, 'Explicit HTTP/1.1 Keep-Alive'); 710 711$t->{REQUEST} = ( <<EOF 712GET /12345.txt HTTP/1.1 713Host: 123.example.org 714 715GET /12345.txt HTTP/1.1 716Host: 123.example.org 717Connection: close 718EOF 719 ); 720$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 721ok($tf->handle_http($t) == 0, 'Implicit HTTP/1.1 Keep-Alive'); 722 723$t->{REQUEST} = ( <<EOF 724GET /12345.txt HTTP/1.1 725Host: 123.example.org 726 727 728GET /12345.txt HTTP/1.1 729Host: 123.example.org 730Connection: close 731EOF 732 ); 733$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; 734ok($tf->handle_http($t) == 0, 'Implicit HTTP/1.1 Keep-Alive w/ extra blank b/w requests'); 735 736$t->{REQUEST} = ( <<EOF 737GET /12345.txt HTTP/1.1 738Host: 123.example.org 739 740 741 742GET /12345.txt HTTP/1.1 743Host: 123.example.org 744Connection: close 745EOF 746 ); 747$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; 748ok($tf->handle_http($t) == 0, 'Implicit HTTP/1.1 Keep-Alive w/ excess blank b/w requests'); 749 750 751## 404 handlers 752 753$t->{REQUEST} = ( <<EOF 754GET /static/notfound HTTP/1.0 755Host: errors.example.org 756EOF 757 ); 758$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => "static not found\n" } ]; 759ok($tf->handle_http($t) == 0, '404 handler => static'); 760 761$t->{REQUEST} = ( <<EOF 762GET /dynamic/200/notfound HTTP/1.0 763Host: errors.example.org 764EOF 765 ); 766$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => "found here\n" } ]; 767ok($tf->handle_http($t) == 0, '404 handler => dynamic(200)'); 768 769$t->{REQUEST} = ( <<EOF 770GET /dynamic/302/notfound HTTP/1.0 771Host: errors.example.org 772EOF 773 ); 774$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 302, 'Location' => "http://www.example.org/" } ]; 775ok($tf->handle_http($t) == 0, '404 handler => dynamic(302)'); 776 777$t->{REQUEST} = ( <<EOF 778GET /dynamic/404/notfound HTTP/1.0 779Host: errors.example.org 780EOF 781 ); 782$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'HTTP-Content' => "Not found here\n" } ]; 783ok($tf->handle_http($t) == 0, '404 handler => dynamic(404)'); 784 785$t->{REQUEST} = ( <<EOF 786GET /dynamic/redirect_status/ HTTP/1.0 787Host: errors.example.org 788EOF 789 ); 790$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'HTTP-Content' => "REDIRECT_STATUS\n" } ]; 791ok($tf->handle_http($t) == 0, 'error handler => dynamic(REDIRECT_STATUS)'); 792 793$t->{REQUEST} = ( <<EOF 794GET /dynamic/nostatus/notfound HTTP/1.0 795Host: errors.example.org 796EOF 797 ); 798$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => "found here\n" } ]; 799ok($tf->handle_http($t) == 0, '404 handler => dynamic(nostatus)'); 800 801$t->{REQUEST} = ( <<EOF 802GET /cgi.pl?send404 HTTP/1.0 803Host: errors.example.org 804EOF 805 ); 806$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'HTTP-Content' => "send404\n" } ]; 807ok($tf->handle_http($t) == 0, '404 generated by CGI should stay 404'); 808 809 810## config conditions 811 812$t->{REQUEST} = ( <<EOF 813GET /nofile.png HTTP/1.0 814Host: referer.example.org 815EOF 816 ); 817$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; 818ok($tf->handle_http($t) == 0, 'condition: Referer - no referer'); 819 820$t->{REQUEST} = ( <<EOF 821GET /nofile.png HTTP/1.0 822Host: referer.example.org 823Referer: http://referer.example.org/ 824EOF 825 ); 826$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; 827ok($tf->handle_http($t) == 0, 'condition: Referer - referer matches regex'); 828 829$t->{REQUEST} = ( <<EOF 830GET /image.jpg HTTP/1.0 831Host: www.example.org 832EOF 833 ); 834$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 835ok($tf->handle_http($t) == 0, 'condition: Referer - no referer'); 836 837$t->{REQUEST} = ( <<EOF 838GET /image.jpg HTTP/1.0 839Host: www.example.org 840Referer: http://referer.example.org/ 841EOF 842 ); 843$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 844ok($tf->handle_http($t) == 0, 'condition: Referer - referer matches regex'); 845 846$t->{REQUEST} = ( <<EOF 847GET /image.jpg HTTP/1.0 848Host: www.example.org 849Referer: http://evil-referer.example.org/ 850EOF 851 ); 852$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 853ok($tf->handle_http($t) == 0, 'condition: Referer - referer doesn\'t match'); 854 855$t->{REQUEST} = ( <<EOF 856GET /nofile HTTP/1.1 857Host: bug255.example.org 858 859GET /nofile HTTP/1.1 860Host: bug255.example.org 861Connection: close 862EOF 863 ); 864$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 403 }, { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 403 } ]; 865ok($tf->handle_http($t) == 0, 'remote ip cache (#255)'); 866 867$t->{REQUEST} = ( <<EOF 868GET /empty-ref.noref HTTP/1.0 869Cookie: empty-ref 870EOF 871 ); 872$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 873ok($tf->handle_http($t) == 0, 'condition: $HTTP["referer"] == "" and Referer is no set'); 874 875$t->{REQUEST} = ( <<EOF 876GET /empty-ref.noref HTTP/1.0 877Cookie: empty-ref 878Referer: 879EOF 880 ); 881$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 882ok($tf->handle_http($t) == 0, 'condition: $HTTP["referer"] == "" and Referer is empty'); 883 884$t->{REQUEST} = ( <<EOF 885GET /empty-ref.noref HTTP/1.0 886Cookie: empty-ref 887Referer: foobar 888EOF 889 ); 890$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; 891ok($tf->handle_http($t) == 0, 'condition: $HTTP["referer"] == "" and Referer: foobar'); 892 893 894## case-insensitive filesystem policy 895 896## check if lower-casing works 897 898$t->{REQUEST} = ( <<EOF 899GET /image.JPG HTTP/1.0 900Host: lowercase-allow 901EOF 902 ); 903$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 904ok($tf->handle_http($t) == 0, 'uppercase access'); 905 906$t->{REQUEST} = ( <<EOF 907GET /image.jpg HTTP/1.0 908Host: lowercase-allow 909EOF 910 ); 911$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 912ok($tf->handle_http($t) == 0, 'lowercase access'); 913 914## check that mod_auth works 915 916$t->{REQUEST} = ( <<EOF 917GET /image.JPG HTTP/1.0 918Host: lowercase-auth 919EOF 920 ); 921$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; 922ok($tf->handle_http($t) == 0, 'uppercase access'); 923 924$t->{REQUEST} = ( <<EOF 925GET /image.jpg HTTP/1.0 926Host: lowercase-auth 927EOF 928 ); 929$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; 930ok($tf->handle_http($t) == 0, 'lowercase access'); 931 932 933## check that mod_staticfile exclude works 934$t->{REQUEST} = ( <<EOF 935GET /image.JPG HTTP/1.0 936Host: lowercase-exclude 937EOF 938 ); 939$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 940ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension'); 941 942$t->{REQUEST} = ( <<EOF 943GET /image.jpg HTTP/1.0 944Host: lowercase-exclude 945EOF 946 ); 947$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 948ok($tf->handle_http($t) == 0, 'lowercase access'); 949 950 951## check that mod_access exclude works 952$t->{REQUEST} = ( <<EOF 953GET /image.JPG HTTP/1.0 954Host: lowercase-deny 955EOF 956 ); 957$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 958ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location'); 959 960$t->{REQUEST} = ( <<EOF 961GET /image.jpg HTTP/1.0 962Host: lowercase-deny 963EOF 964 ); 965$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 966ok($tf->handle_http($t) == 0, 'lowercase access'); 967 968 969## symlink policy 970 971my $docroot = $tf->{'TESTDIR'}."/tmp/lighttpd/servers/www.example.org/pages"; 972 973sub init_testbed { 974 return 0 unless eval { symlink("",""); 1 }; 975 my $f = "$docroot/index.html"; 976 my $l = "$docroot/index.xhtml"; 977 my $rc = undef; 978 unless (-l $l) { 979 return 0 unless symlink($f,$l); 980 }; 981 $f = "$docroot/expire"; 982 $l = "$docroot/symlinked"; 983 $rc = undef; 984 unless (-l $l) { 985 return 0 unless symlink($f,$l); 986 } 987 return 1; 988}; 989 990SKIP: { 991 skip "perl does not support symlinking or setting up the symlinks failed.", 8 unless init_testbed; 992 993# allow case 994# simple file 995 $t->{REQUEST} = ( <<EOF 996GET /index.html HTTP/1.0 997Host: symlink.example.org 998EOF 999 ); 1000 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1001 ok($tf->handle_http($t) == 0, 'allow: simple file'); 1002 1003# symlinked file 1004 $t->{REQUEST} = ( <<EOF 1005GET /index.xhtml HTTP/1.0 1006Host: symlink.example.org 1007EOF 1008 ); 1009 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1010 ok($tf->handle_http($t) == 0, 'allow: symlinked file'); 1011 1012# directly symlinked dir 1013 $t->{REQUEST} = ( <<EOF 1014GET /symlinked/ HTTP/1.0 1015Host: symlink.example.org 1016EOF 1017 ); 1018 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1019 ok($tf->handle_http($t) == 0, 'allow: directly symlinked dir'); 1020 1021# symlinked dir in path 1022 $t->{REQUEST} = ( <<EOF 1023GET /symlinked/access.txt HTTP/1.0 1024Host: symlink.example.org 1025EOF 1026 ); 1027 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1028 ok($tf->handle_http($t) == 0, 'allow: symlinked dir in path'); 1029 1030# deny case 1031# simple file 1032 $t->{REQUEST} = ( <<EOF 1033GET /index.html HTTP/1.0 1034Host: nosymlink.example.org 1035EOF 1036 ); 1037 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1038 ok($tf->handle_http($t) == 0, 'deny: simple file'); 1039 1040# symlinked file 1041 $t->{REQUEST} = ( <<EOF 1042GET /index.xhtml HTTP/1.0 1043Host: nosymlink.example.org 1044EOF 1045 ); 1046 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 1047 ok($tf->handle_http($t) == 0, 'deny: symlinked file'); 1048 1049# directly symlinked dir 1050 $t->{REQUEST} = ( <<EOF 1051GET /symlinked/ HTTP/1.0 1052Host: nosymlink.example.org 1053EOF 1054 ); 1055 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 1056 ok($tf->handle_http($t) == 0, 'deny: directly symlinked dir'); 1057 1058# symlinked dir in path 1059 $t->{REQUEST} = ( <<EOF 1060GET /symlinked/access.txt HTTP/1.0 1061Host: nosymlink.example.org 1062EOF 1063 ); 1064 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; 1065 ok($tf->handle_http($t) == 0, 'deny: symlinked dir in path'); 1066 1067}; 1068 1069 1070## mod_auth 1071 1072$t->{REQUEST} = ( <<EOF 1073GET /server-status HTTP/1.0 1074Host: auth-plain.example.org 1075EOF 1076 ); 1077$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; 1078ok($tf->handle_http($t) == 0, 'Missing Auth-token'); 1079 1080$t->{REQUEST} = ( <<EOF 1081GET /server-config HTTP/1.0 1082Host: auth-plain.example.org 1083Authorization: Basic \x80mFuOmphb 1084EOF 1085 ); 1086$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; 1087ok($tf->handle_http($t) == 0, 'Basic-Auth: Invalid base64 Auth-token'); 1088 1089$t->{REQUEST} = ( <<EOF 1090GET /server-config HTTP/1.0 1091Host: auth-plain.example.org 1092Authorization: Basic bm90Oml0Cg== 1093EOF 1094 ); 1095$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; 1096ok($tf->handle_http($t) == 0, 'Basic-Auth: Wrong Auth-token'); 1097 1098$t->{REQUEST} = ( <<EOF 1099GET /server-config HTTP/1.0 1100Host: auth-plain.example.org 1101Authorization: Basic amFuOmphbg== 1102EOF 1103 ); 1104$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1105ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - plain'); 1106 1107SKIP: { 1108 skip "no crypt-des under openbsd", 2 if $^O eq 'openbsd'; 1109$t->{REQUEST} = ( <<EOF 1110GET /server-config HTTP/1.0 1111Host: auth-htpasswd.example.org 1112Authorization: Basic ZGVzOmRlcw== 1113EOF 1114 ); 1115$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1116ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (des)'); 1117 1118$t->{REQUEST} = ( <<EOF 1119GET /server-config HTTP/1.0 1120Host: auth-htpasswd.example.org 1121Authorization: basic ZGVzOmRlcw== 1122EOF 1123 ); 1124$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1125ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (des) (lowercase)'); 1126} 1127 1128$t->{REQUEST} = ( <<EOF 1129GET /server-config HTTP/1.0 1130Host: auth-htpasswd.example.org 1131Authorization: Basic c2hhOnNoYQ== 1132EOF 1133 ); 1134$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1135ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (sha)'); 1136 1137$t->{REQUEST} = ( <<EOF 1138GET /server-config HTTP/1.0 1139Host: auth-htpasswd.example.org 1140Authorization: Basic c2hhOnNoYg== 1141EOF 1142 ); 1143$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; 1144ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (sha, wrong password)'); 1145 1146$t->{REQUEST} = ( <<EOF 1147GET /server-config HTTP/1.0 1148Host: auth-htpasswd.example.org 1149Authorization: Basic YXByLW1kNTphcHItbWQ1 1150EOF 1151 ); 1152$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1153ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (apr-md5)'); 1154 1155$t->{REQUEST} = ( <<EOF 1156GET /server-config HTTP/1.0 1157Host: auth-htpasswd.example.org 1158Authorization: Basic YXByLW1kNTphcHItbWQ2 1159EOF 1160 ); 1161$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; 1162ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (apr-md5, wrong password)'); 1163 1164SKIP: { 1165 skip "no crypt-md5 under cygwin", 1 if $^O eq 'cygwin'; 1166 skip "no crypt-md5 under darwin", 1 if $^O eq 'darwin'; 1167 skip "no crypt-md5 under openbsd",1 if $^O eq 'openbsd'; 1168$t->{REQUEST} = ( <<EOF 1169GET /server-config HTTP/1.0 1170Host: auth-htpasswd.example.org 1171Authorization: Basic bWQ1Om1kNQ== 1172EOF 1173 ); 1174$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1175ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (crypt-md5)'); 1176} 1177 1178$t->{REQUEST} = ( <<EOF 1179GET /server-config HTTP/1.0 1180Host: auth-plain.example.org 1181Authorization: Basic bWQ1Om1kNA== 1182EOF 1183 ); 1184$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; 1185ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token'); 1186 1187## this should not crash 1188$t->{REQUEST} = ( <<EOF 1189GET /server-status HTTP/1.0 1190Host: auth-plain.example.org 1191User-Agent: Wget/1.9.1 1192Authorization: Digest username="jan", realm="jan", nonce="9a5428ccc05b086a08d918e73b01fc6f", 1193 uri="/server-status", response="ea5f7d9a30b8b762f9610ccb87dea74f" 1194EOF 1195 ); 1196$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; 1197ok($tf->handle_http($t) == 0, 'Digest-Auth: missing qop, no crash'); 1198 1199# (Note: test case is invalid; mismatch between request line and uri="..." 1200# is not what is intended to be tested here, but that is what is invalid) 1201# https://redmine.lighttpd.net/issues/477 1202## this should not crash 1203$t->{REQUEST} = ( <<EOF 1204GET /server-status HTTP/1.0 1205Host: auth-plain.example.org 1206User-Agent: Wget/1.9.1 1207Authorization: Digest username="jan", realm="jan", 1208 nonce="b1d12348b4620437c43dd61c50ae4639", 1209 uri="/MJ-BONG.xm.mpc", qop=auth, noncecount=00000001", 1210 cnonce="036FCA5B86F7E7C4965C7F9B8FE714B7", 1211 response="29B32C2953C763C6D033C8A49983B87E" 1212EOF 1213 ); 1214$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; 1215ok($tf->handle_http($t) == 0, 'Digest-Auth: missing nc (noncecount instead), no crash'); 1216 1217$t->{REQUEST} = ( <<EOF 1218GET /server-config HTTP/1.0 1219Host: auth-plain.example.org 1220Authorization: Basic = 1221EOF 1222 ); 1223$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; 1224ok($tf->handle_http($t) == 0, 'Basic-Auth: Invalid Base64'); 1225 1226$t->{REQUEST} = ( <<EOF 1227GET /server-status HTTP/1.0 1228Host: auth-plain.example.org 1229Authorization: Digest username="jan", realm="download archiv", 1230 nonce="b3b26457000000003a9b34a3cd56d26e48a52a498ac9765d4b", 1231 uri="/server-status", qop=auth, nc=00000001, 1232 algorithm="md5-sess", response="049b000fb00ab51dddea6f093a96aa2e" 1233EOF 1234 ); 1235$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; 1236ok($tf->handle_http($t) == 0, 'Digest-Auth: md5-sess + missing cnonce'); 1237 1238 $t->{REQUEST} = ( <<EOF 1239GET /server-status HTTP/1.0 1240Host: auth-plain.example.org 1241Authorization: Digest username="jan", realm="download archiv", 1242 nonce="b3b26457000000003a9b34a3cd56d26e48a52a498ac9765d4b", 1243 uri="/server-status", qop=auth, nc=00000001, cnonce="65ee1b37", 1244 algorithm="md5", response="049b000fb00ab51dddea6f093a96aa2e" 1245EOF 1246 ); 1247$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401, 'WWW-Authenticate' => '/, stale=true$/' } ]; 1248ok($tf->handle_http($t) == 0, 'Digest-Auth: stale nonce'); 1249 1250$t->{REQUEST} = ( <<EOF 1251GET /server-status HTTP/1.0 1252Host: auth-plain.example.org 1253Authorization: Digest username = "jan", realm = "download archiv", 1254 nonce = "b3b26457000000003a9b34a3cd56d26e48a52a498ac9765d4b", 1255 uri = "/server-status", qop = auth, nc = 00000001, cnonce = "65ee1b37", 1256 algorithm = "md5", response = "049b000fb00ab51dddea6f093a96aa2e" 1257EOF 1258 ); # note: trailing whitespace at end of request line above is intentional 1259$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401, 'WWW-Authenticate' => '/, stale=true$/' } ]; 1260ok($tf->handle_http($t) == 0, 'Digest-Auth: BWS, trailing WS, stale nonce'); 1261 1262 1263## mod_cgi 1264 1265$t->{REQUEST} = ( <<EOF 1266GET /cgi.pl HTTP/1.0 1267EOF 1268 ); 1269$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1270ok($tf->handle_http($t) == 0, 'perl via cgi'); 1271 1272if ($^O ne "cygwin") { 1273 $t->{REQUEST} = ( <<EOF 1274GET /cgi.pl%20%20%20 HTTP/1.0 1275EOF 1276 ); 1277 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; 1278 ok($tf->handle_http($t) == 0, 'No source retrieval'); 1279} else { 1280 ok(1, 'No source retrieval; skipped on cygwin; see response.c'); 1281} 1282 1283$t->{REQUEST} = ( <<EOF 1284GET /cgi.pl/foo?env=SCRIPT_NAME HTTP/1.0 1285EOF 1286 ); 1287$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '/cgi.pl' } ]; 1288ok($tf->handle_http($t) == 0, 'perl via cgi + pathinfo'); 1289 1290$t->{REQUEST} = ( <<EOF 1291GET /cgi.pl?internal-redir HTTP/1.0 1292EOF 1293 ); 1294$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1295ok($tf->handle_http($t) == 0, 'perl via cgi and internal redirect from CGI'); 1296 1297$t->{REQUEST} = ( <<EOF 1298GET /cgi.pl?xsendfile HTTP/1.0 1299Host: cgi.example.org 1300EOF 1301 ); 1302$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Length' => 4348 } ]; 1303ok($tf->handle_http($t) == 0, 'X-Sendfile'); 1304 1305$t->{REQUEST} = ( <<EOF 1306GET /cgi.pl?external-redir HTTP/1.0 1307Host: www.example.org 1308EOF 1309 ); 1310$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 302, 'Location' => 'http://www.example.org:2048/' } ]; 1311ok($tf->handle_http($t) == 0, 'Status + Location via FastCGI'); 1312 1313$t->{REQUEST} = ( <<EOF 1314GET /cgi.pl/?external-redir HTTP/1.0 1315Host: www.example.org 1316EOF 1317 ); 1318$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 302, 'Location' => 'http://www.example.org:2048/' } ]; 1319ok($tf->handle_http($t) == 0, 'Trailing slash as path-info (#1989: workaround broken operating systems)'); 1320 1321$t->{REQUEST} = ( <<EOF 1322GET /cgi.pl?nph=30 HTTP/1.0 1323EOF 1324 ); 1325$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ]; 1326ok($tf->handle_http($t) == 0, 'NPH + perl, invalid status-code (#14)'); 1327 1328$t->{REQUEST} = ( <<EOF 1329GET /cgi.pl?nph=304 HTTP/1.0 1330EOF 1331 ); 1332$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; 1333ok($tf->handle_http($t) == 0, 'NPH + perl, setting status-code (#1125)'); 1334 1335$t->{REQUEST} = ( <<EOF 1336GET /cgi.pl?nph=200 HTTP/1.0 1337EOF 1338 ); 1339$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1340ok($tf->handle_http($t) == 0, 'NPH + perl, setting status-code'); 1341 1342$t->{REQUEST} = ( <<EOF 1343GET /cgi.pl?env=GATEWAY_INTERFACE HTTP/1.0 1344EOF 1345 ); 1346$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'CGI/1.1' } ]; 1347ok($tf->handle_http($t) == 0, 'cgi-env: GATEWAY_INTERFACE'); 1348 1349$t->{REQUEST} = ( <<EOF 1350GET /cgi.pl?query_string HTTP/1.0 1351EOF 1352 ); 1353$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'query_string', 'Content-Type' => 'text/plain' } ]; 1354ok($tf->handle_http($t) == 0, 'cgi-env: QUERY_STRING'); 1355 1356$t->{REQUEST} = ( <<EOF 1357GET /cgi.pl?env=SCRIPT_NAME HTTP/1.0 1358EOF 1359 ); 1360$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '/cgi.pl' } ]; 1361ok($tf->handle_http($t) == 0, 'cgi-env: SCRIPT_NAME'); 1362 1363$t->{REQUEST} = ( <<EOF 1364GET /cgi.pl/path/info?env=SCRIPT_NAME HTTP/1.0 1365EOF 1366 ); 1367$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '/cgi.pl' } ]; 1368ok($tf->handle_http($t) == 0, 'cgi-env: SCRIPT_NAME w/ PATH_INFO'); 1369 1370$t->{REQUEST} = ( <<EOF 1371GET /cgi.pl/path/info?env=PATH_INFO HTTP/1.0 1372EOF 1373 ); 1374$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '/path/info' } ]; 1375ok($tf->handle_http($t) == 0, 'cgi-env: PATH_INFO'); 1376 1377$t->{REQUEST} = ( <<EOF 1378GET /cgi.pl?env=HTTP_XX_YY123 HTTP/1.0 1379xx-yy123: foo 1380EOF 1381 ); 1382$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'foo' } ]; 1383ok($tf->handle_http($t) == 0, 'cgi-env: quoting headers with numbers'); 1384 1385$t->{REQUEST} = ( <<EOF 1386GET /cgi.pl?env=HTTP_HOST HTTP/1.0 1387Host: www.example.org 1388EOF 1389 ); 1390$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'www.example.org' } ]; 1391ok($tf->handle_http($t) == 0, 'cgi-env: HTTP_HOST'); 1392 1393$t->{REQUEST} = ( <<EOF 1394GET /cgi.pl?env=HTTP_HOST HTTP/1.1 1395Host: www.example.org 1396Connection: close 1397EOF 1398 ); 1399$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, '+Content-Length' => '' } ]; 1400ok($tf->handle_http($t) == 0, 'cgi-env: HTTP_HOST'); 1401 1402$t->{REQUEST} = ( <<EOF 1403GET /cgi.pl?env=ABSENT HTTP/1.1 1404Host: www.example.org 1405Connection: close 1406EOF 1407 ); 1408$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '[ABSENT not found]' } ]; 1409ok($tf->handle_http($t) == 0, 'cgi-env: ABSENT'); 1410 1411$t->{REQUEST} = ( <<EOF 1412GET /cgi.pl?env=BLANK_VALUE HTTP/1.1 1413Host: www.example.org 1414Connection: close 1415EOF 1416 ); 1417$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, 'HTTP-Content' => '' } ]; 1418ok($tf->handle_http($t) == 0, 'cgi-env: BLANK_VALUE'); 1419 1420# broken header crash 1421$t->{REQUEST} = ( <<EOF 1422GET /cgi.pl?crlfcrash HTTP/1.0 1423EOF 1424 ); 1425$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 302, 'Location' => 'http://www.example.org/' } ]; 1426ok($tf->handle_http($t) == 0, 'broken header via perl cgi'); 1427 1428 1429## mod_deflate 1430 1431$t->{REQUEST} = ( <<EOF 1432GET /index.html HTTP/1.0 1433Host: deflate.example.org 1434Accept-Encoding: deflate 1435EOF 1436 ); 1437$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Vary' => '' } ]; 1438ok($tf->handle_http($t) == 0, 'Vary is set'); 1439 1440$t->{REQUEST} = ( <<EOF 1441GET /index.html HTTP/1.0 1442Accept-Encoding: deflate 1443Host: deflate.example.org 1444EOF 1445 ); 1446$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Vary' => '', 'Content-Length' => '1294', '+Content-Encoding' => '' } ]; 1447ok($tf->handle_http($t) == 0, 'deflate - Content-Length and Content-Encoding is set'); 1448 1449$t->{REQUEST} = ( <<EOF 1450GET /index.html HTTP/1.0 1451Accept-Encoding: deflate 1452Host: deflate-cache.example.org 1453EOF 1454 ); 1455$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Vary' => '', 'Content-Length' => '1294', '+Content-Encoding' => '' } ]; 1456ok($tf->handle_http($t) == 0, 'deflate - Content-Length and Content-Encoding is set'); 1457 1458$t->{REQUEST} = ( <<EOF 1459GET /index.html HTTP/1.0 1460Accept-Encoding: gzip 1461Host: deflate.example.org 1462EOF 1463 ); 1464$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Vary' => '', 'Content-Length' => '1306', '+Content-Encoding' => '' } ]; 1465ok($tf->handle_http($t) == 0, 'gzip - Content-Length and Content-Encoding is set'); 1466 1467$t->{REQUEST} = ( <<EOF 1468GET /index.html HTTP/1.0 1469Accept-Encoding: gzip 1470Host: deflate-cache.example.org 1471EOF 1472 ); 1473$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Vary' => '', 'Content-Length' => '1306', '+Content-Encoding' => '' } ]; 1474ok($tf->handle_http($t) == 0, 'gzip - Content-Length and Content-Encoding is set'); 1475 1476 1477$t->{REQUEST} = ( <<EOF 1478GET /index.txt HTTP/1.0 1479Host: deflate.example.org 1480Accept-Encoding: gzip, deflate 1481EOF 1482 ); 1483$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Vary' => '', '+Content-Encoding' => '' } ]; 1484ok($tf->handle_http($t) == 0, 'gzip, deflate - Content-Length and Content-Encoding is set'); 1485 1486$t->{REQUEST} = ( <<EOF 1487GET /index.txt HTTP/1.0 1488Host: deflate.example.org 1489Accept-Encoding: gzip, deflate 1490EOF 1491 ); 1492$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Vary' => '', '+Content-Encoding' => '', 'Content-Type' => "text/plain; charset=utf-8" } ]; 1493ok($tf->handle_http($t) == 0, 'Content-Type is from the original file'); 1494 1495$t->{REQUEST} = ( <<EOF 1496GET /index.txt HTTP/1.0 1497Host: deflate.example.org 1498Accept-encoding: 1499X-Accept-encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0 1500User-Agent: MYOB/6.66 (AN/ON) 1501Connection: close 1502EOF 1503 ); 1504$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-Content-Encoding' => '', 'Content-Type' => "text/plain; charset=utf-8" } ]; 1505ok($tf->handle_http($t) == 0, 'Empty Accept-Encoding'); 1506 1507$t->{REQUEST} = ( <<EOF 1508GET /index.txt HTTP/1.0 1509Accept-Encoding: bzip2, gzip, deflate 1510Host: deflate-cache.example.org 1511EOF 1512 ); 1513$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Vary' => '', 'Content-Encoding' => 'gzip', 'Content-Type' => "text/plain" } ]; 1514ok($tf->handle_http($t) == 0, 'bzip2 requested but disabled'); 1515 1516 1517## mod_extforward 1518 1519$t->{REQUEST} = ( <<EOF 1520GET /cgi.pl?env=REMOTE_ADDR HTTP/1.0 1521Host: www.example.org 1522X-Forwarded-For: 127.0.10.1 1523EOF 1524); 1525$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.10.1' } ]; 1526ok($tf->handle_http($t) == 0, 'expect 127.0.10.1, from single ip'); 1527 1528$t->{REQUEST} = ( <<EOF 1529GET /cgi.pl?env=REMOTE_ADDR HTTP/1.0 1530Host: www.example.org 1531X-Forwarded-For: 127.0.10.1, 127.0.20.1 1532EOF 1533); 1534$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.20.1' } ]; 1535ok($tf->handle_http($t) == 0, 'expect 127.0.20.1, from two ips'); 1536 1537$t->{REQUEST} = ( <<EOF 1538GET /cgi.pl?env=REMOTE_ADDR HTTP/1.0 1539Host: www.example.org 1540X-Forwarded-For: 127.0.10.1, 127.0.20.1, 127.0.30.1 1541EOF 1542); 1543$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.20.1' } ]; 1544ok($tf->handle_http($t) == 0, 'expect 127.0.20.1, from chained proxies'); 1545 1546$t->{REQUEST} = ( <<EOF 1547GET /cgi.pl?env=REMOTE_ADDR HTTP/1.0 1548Host: www.example.org 1549Forwarded: for=127.0.10.1, for=127.0.20.1;proto=https, for=127.0.30.1;proto=http 1550EOF 1551); 1552$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.20.1' } ]; 1553ok($tf->handle_http($t) == 0, 'expect 127.0.20.1, from chained proxies'); 1554 1555 1556## mod_proxy 1557 1558do { 1559 1560my $tf_proxy = LightyTest->new(); 1561$tf_proxy->{CONFIGFILE} = 'proxy.conf'; 1562 1563local $ENV{EPHEMERAL_PORT} = $tf->{PORT}; 1564ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or last; 1565 1566$t->{REQUEST} = ( <<EOF 1567GET /index.html HTTP/1.0 1568Host: www.example.org 1569EOF 1570 ); 1571$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; 1572ok($tf_proxy->handle_http($t) == 0, 'valid request'); 1573 1574$t->{REQUEST} = ( <<EOF 1575GET /index.html HTTP/1.0 1576Host: www.example.org 1577EOF 1578 ); 1579$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'lighttpd-1.4.x' } ]; 1580ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server'); 1581 1582$t->{REQUEST} = ( <<EOF 1583GET /rewrite/all/some+test%3axxx%20with%20space HTTP/1.0 1584Host: www.example.org 1585EOF 1586 ); 1587$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '/some+test%3Axxx%20with%20space' } ]; 1588ok($tf_proxy->handle_http($t) == 0, 'rewrited urls work with encoded path'); 1589 1590ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy"); 1591 1592} while (0); 1593 1594 1595## mod_setenv 1596 1597$t->{REQUEST} = ( <<EOF 1598GET /cgi.pl?env=TRAC_ENV HTTP/1.0 1599Host: www.example.org 1600EOF 1601 ); 1602$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'tracenv' } ]; 1603ok($tf->handle_http($t) == 0, 'query first setenv'); 1604 1605$t->{REQUEST} = ( <<EOF 1606GET /cgi.pl?env=SETENV HTTP/1.0 1607Host: www.example.org 1608EOF 1609 ); 1610$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'setenv' } ]; 1611ok($tf->handle_http($t) == 0, 'query second setenv'); 1612 1613$t->{REQUEST} = ( <<EOF 1614GET /cgi.pl?env=NEWENV HTTP/1.0 1615Host: www.example.org 1616EOF 1617 ); 1618$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'newenv' } ]; 1619ok($tf->handle_http($t) == 0, 'query set-environment'); 1620 1621$t->{REQUEST} = ( <<EOF 1622GET /cgi.pl?env=HTTP_FOO HTTP/1.0 1623Host: www.example.org 1624EOF 1625 ); 1626$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'foo' } ]; 1627ok($tf->handle_http($t) == 0, 'query add-request-header'); 1628 1629$t->{REQUEST} = ( <<EOF 1630GET /cgi.pl?env=HTTP_FOO2 HTTP/1.0 1631Host: www.example.org 1632EOF 1633 ); 1634$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'foo2' } ]; 1635ok($tf->handle_http($t) == 0, 'query set-request-header'); 1636 1637$t->{REQUEST} = ( <<EOF 1638GET /index.html HTTP/1.0 1639Host: www.example.org 1640EOF 1641 ); 1642$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'BAR' => 'foo' } ]; 1643ok($tf->handle_http($t) == 0, 'query add-response-header'); 1644 1645$t->{REQUEST} = ( <<EOF 1646GET /index.html HTTP/1.0 1647Host: www.example.org 1648EOF 1649 ); 1650$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'BAR2' => 'bar2' } ]; 1651ok($tf->handle_http($t) == 0, 'query set-response-header'); 1652 1653 1654ok($tf->stop_proc == 0, "Stopping lighttpd"); 1655