request.t 53 KB

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