RequestTest.php 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpFoundation\Tests;
  11. use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
  12. use Symfony\Component\HttpFoundation\Session\Session;
  13. use Symfony\Component\HttpFoundation\Request;
  14. class RequestTest extends \PHPUnit_Framework_TestCase
  15. {
  16. public function testInitialize()
  17. {
  18. $request = new Request();
  19. $request->initialize(array('foo' => 'bar'));
  20. $this->assertEquals('bar', $request->query->get('foo'), '->initialize() takes an array of query parameters as its first argument');
  21. $request->initialize(array(), array('foo' => 'bar'));
  22. $this->assertEquals('bar', $request->request->get('foo'), '->initialize() takes an array of request parameters as its second argument');
  23. $request->initialize(array(), array(), array('foo' => 'bar'));
  24. $this->assertEquals('bar', $request->attributes->get('foo'), '->initialize() takes an array of attributes as its third argument');
  25. $request->initialize(array(), array(), array(), array(), array(), array('HTTP_FOO' => 'bar'));
  26. $this->assertEquals('bar', $request->headers->get('FOO'), '->initialize() takes an array of HTTP headers as its sixth argument');
  27. }
  28. public function testGetLocale()
  29. {
  30. $request = new Request();
  31. $request->setLocale('pl');
  32. $locale = $request->getLocale();
  33. $this->assertEquals('pl', $locale);
  34. }
  35. public function testGetUser()
  36. {
  37. $request = Request::create('http://user_test:password_test@test.com/');
  38. $user = $request->getUser();
  39. $this->assertEquals('user_test', $user);
  40. }
  41. public function testGetPassword()
  42. {
  43. $request = Request::create('http://user_test:password_test@test.com/');
  44. $password = $request->getPassword();
  45. $this->assertEquals('password_test', $password);
  46. }
  47. public function testIsNoCache()
  48. {
  49. $request = new Request();
  50. $isNoCache = $request->isNoCache();
  51. $this->assertFalse($isNoCache);
  52. }
  53. public function testGetContentType()
  54. {
  55. $request = new Request();
  56. $contentType = $request->getContentType();
  57. $this->assertNull($contentType);
  58. }
  59. public function testSetDefaultLocale()
  60. {
  61. $request = new Request();
  62. $request->setDefaultLocale('pl');
  63. $locale = $request->getLocale();
  64. $this->assertEquals('pl', $locale);
  65. }
  66. public function testCreate()
  67. {
  68. $request = Request::create('http://test.com/foo?bar=baz');
  69. $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri());
  70. $this->assertEquals('/foo', $request->getPathInfo());
  71. $this->assertEquals('bar=baz', $request->getQueryString());
  72. $this->assertEquals(80, $request->getPort());
  73. $this->assertEquals('test.com', $request->getHttpHost());
  74. $this->assertFalse($request->isSecure());
  75. $request = Request::create('http://test.com/foo', 'GET', array('bar' => 'baz'));
  76. $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri());
  77. $this->assertEquals('/foo', $request->getPathInfo());
  78. $this->assertEquals('bar=baz', $request->getQueryString());
  79. $this->assertEquals(80, $request->getPort());
  80. $this->assertEquals('test.com', $request->getHttpHost());
  81. $this->assertFalse($request->isSecure());
  82. $request = Request::create('http://test.com/foo?bar=foo', 'GET', array('bar' => 'baz'));
  83. $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri());
  84. $this->assertEquals('/foo', $request->getPathInfo());
  85. $this->assertEquals('bar=baz', $request->getQueryString());
  86. $this->assertEquals(80, $request->getPort());
  87. $this->assertEquals('test.com', $request->getHttpHost());
  88. $this->assertFalse($request->isSecure());
  89. $request = Request::create('https://test.com/foo?bar=baz');
  90. $this->assertEquals('https://test.com/foo?bar=baz', $request->getUri());
  91. $this->assertEquals('/foo', $request->getPathInfo());
  92. $this->assertEquals('bar=baz', $request->getQueryString());
  93. $this->assertEquals(443, $request->getPort());
  94. $this->assertEquals('test.com', $request->getHttpHost());
  95. $this->assertTrue($request->isSecure());
  96. $request = Request::create('test.com:90/foo');
  97. $this->assertEquals('http://test.com:90/foo', $request->getUri());
  98. $this->assertEquals('/foo', $request->getPathInfo());
  99. $this->assertEquals('test.com', $request->getHost());
  100. $this->assertEquals('test.com:90', $request->getHttpHost());
  101. $this->assertEquals(90, $request->getPort());
  102. $this->assertFalse($request->isSecure());
  103. $request = Request::create('https://test.com:90/foo');
  104. $this->assertEquals('https://test.com:90/foo', $request->getUri());
  105. $this->assertEquals('/foo', $request->getPathInfo());
  106. $this->assertEquals('test.com', $request->getHost());
  107. $this->assertEquals('test.com:90', $request->getHttpHost());
  108. $this->assertEquals(90, $request->getPort());
  109. $this->assertTrue($request->isSecure());
  110. $request = Request::create('https://127.0.0.1:90/foo');
  111. $this->assertEquals('https://127.0.0.1:90/foo', $request->getUri());
  112. $this->assertEquals('/foo', $request->getPathInfo());
  113. $this->assertEquals('127.0.0.1', $request->getHost());
  114. $this->assertEquals('127.0.0.1:90', $request->getHttpHost());
  115. $this->assertEquals(90, $request->getPort());
  116. $this->assertTrue($request->isSecure());
  117. $request = Request::create('https://[::1]:90/foo');
  118. $this->assertEquals('https://[::1]:90/foo', $request->getUri());
  119. $this->assertEquals('/foo', $request->getPathInfo());
  120. $this->assertEquals('[::1]', $request->getHost());
  121. $this->assertEquals('[::1]:90', $request->getHttpHost());
  122. $this->assertEquals(90, $request->getPort());
  123. $this->assertTrue($request->isSecure());
  124. $request = Request::create('https://[::1]/foo');
  125. $this->assertEquals('https://[::1]/foo', $request->getUri());
  126. $this->assertEquals('/foo', $request->getPathInfo());
  127. $this->assertEquals('[::1]', $request->getHost());
  128. $this->assertEquals('[::1]', $request->getHttpHost());
  129. $this->assertEquals(443, $request->getPort());
  130. $this->assertTrue($request->isSecure());
  131. $json = '{"jsonrpc":"2.0","method":"echo","id":7,"params":["Hello World"]}';
  132. $request = Request::create('http://example.com/jsonrpc', 'POST', array(), array(), array(), array(), $json);
  133. $this->assertEquals($json, $request->getContent());
  134. $this->assertFalse($request->isSecure());
  135. $request = Request::create('http://test.com');
  136. $this->assertEquals('http://test.com/', $request->getUri());
  137. $this->assertEquals('/', $request->getPathInfo());
  138. $this->assertEquals('', $request->getQueryString());
  139. $this->assertEquals(80, $request->getPort());
  140. $this->assertEquals('test.com', $request->getHttpHost());
  141. $this->assertFalse($request->isSecure());
  142. $request = Request::create('http://test.com?test=1');
  143. $this->assertEquals('http://test.com/?test=1', $request->getUri());
  144. $this->assertEquals('/', $request->getPathInfo());
  145. $this->assertEquals('test=1', $request->getQueryString());
  146. $this->assertEquals(80, $request->getPort());
  147. $this->assertEquals('test.com', $request->getHttpHost());
  148. $this->assertFalse($request->isSecure());
  149. $request = Request::create('http://test.com:90/?test=1');
  150. $this->assertEquals('http://test.com:90/?test=1', $request->getUri());
  151. $this->assertEquals('/', $request->getPathInfo());
  152. $this->assertEquals('test=1', $request->getQueryString());
  153. $this->assertEquals(90, $request->getPort());
  154. $this->assertEquals('test.com:90', $request->getHttpHost());
  155. $this->assertFalse($request->isSecure());
  156. $request = Request::create('http://username:password@test.com');
  157. $this->assertEquals('http://test.com/', $request->getUri());
  158. $this->assertEquals('/', $request->getPathInfo());
  159. $this->assertEquals('', $request->getQueryString());
  160. $this->assertEquals(80, $request->getPort());
  161. $this->assertEquals('test.com', $request->getHttpHost());
  162. $this->assertEquals('username', $request->getUser());
  163. $this->assertEquals('password', $request->getPassword());
  164. $this->assertFalse($request->isSecure());
  165. $request = Request::create('http://username@test.com');
  166. $this->assertEquals('http://test.com/', $request->getUri());
  167. $this->assertEquals('/', $request->getPathInfo());
  168. $this->assertEquals('', $request->getQueryString());
  169. $this->assertEquals(80, $request->getPort());
  170. $this->assertEquals('test.com', $request->getHttpHost());
  171. $this->assertEquals('username', $request->getUser());
  172. $this->assertSame('', $request->getPassword());
  173. $this->assertFalse($request->isSecure());
  174. $request = Request::create('http://test.com/?foo');
  175. $this->assertEquals('/?foo', $request->getRequestUri());
  176. $this->assertEquals(array('foo' => ''), $request->query->all());
  177. // assume rewrite rule: (.*) --> app/app.php; app/ is a symlink to a symfony web/ directory
  178. $request = Request::create('http://test.com/apparthotel-1234', 'GET', array(), array(), array(),
  179. array(
  180. 'DOCUMENT_ROOT' => '/var/www/www.test.com',
  181. 'SCRIPT_FILENAME' => '/var/www/www.test.com/app/app.php',
  182. 'SCRIPT_NAME' => '/app/app.php',
  183. 'PHP_SELF' => '/app/app.php/apparthotel-1234',
  184. ));
  185. $this->assertEquals('http://test.com/apparthotel-1234', $request->getUri());
  186. $this->assertEquals('/apparthotel-1234', $request->getPathInfo());
  187. $this->assertEquals('', $request->getQueryString());
  188. $this->assertEquals(80, $request->getPort());
  189. $this->assertEquals('test.com', $request->getHttpHost());
  190. $this->assertFalse($request->isSecure());
  191. }
  192. public function testCreateCheckPrecedence()
  193. {
  194. // server is used by default
  195. $request = Request::create('/', 'DELETE', array(), array(), array(), array(
  196. 'HTTP_HOST' => 'example.com',
  197. 'HTTPS' => 'on',
  198. 'SERVER_PORT' => 443,
  199. 'PHP_AUTH_USER' => 'fabien',
  200. 'PHP_AUTH_PW' => 'pa$$',
  201. 'QUERY_STRING' => 'foo=bar',
  202. 'CONTENT_TYPE' => 'application/json',
  203. ));
  204. $this->assertEquals('example.com', $request->getHost());
  205. $this->assertEquals(443, $request->getPort());
  206. $this->assertTrue($request->isSecure());
  207. $this->assertEquals('fabien', $request->getUser());
  208. $this->assertEquals('pa$$', $request->getPassword());
  209. $this->assertEquals('', $request->getQueryString());
  210. $this->assertEquals('application/json', $request->headers->get('CONTENT_TYPE'));
  211. // URI has precedence over server
  212. $request = Request::create('http://thomas:pokemon@example.net:8080/?foo=bar', 'GET', array(), array(), array(), array(
  213. 'HTTP_HOST' => 'example.com',
  214. 'HTTPS' => 'on',
  215. 'SERVER_PORT' => 443,
  216. ));
  217. $this->assertEquals('example.net', $request->getHost());
  218. $this->assertEquals(8080, $request->getPort());
  219. $this->assertFalse($request->isSecure());
  220. $this->assertEquals('thomas', $request->getUser());
  221. $this->assertEquals('pokemon', $request->getPassword());
  222. $this->assertEquals('foo=bar', $request->getQueryString());
  223. }
  224. public function testDuplicate()
  225. {
  226. $request = new Request(array('foo' => 'bar'), array('foo' => 'bar'), array('foo' => 'bar'), array(), array(), array('HTTP_FOO' => 'bar'));
  227. $dup = $request->duplicate();
  228. $this->assertEquals($request->query->all(), $dup->query->all(), '->duplicate() duplicates a request an copy the current query parameters');
  229. $this->assertEquals($request->request->all(), $dup->request->all(), '->duplicate() duplicates a request an copy the current request parameters');
  230. $this->assertEquals($request->attributes->all(), $dup->attributes->all(), '->duplicate() duplicates a request an copy the current attributes');
  231. $this->assertEquals($request->headers->all(), $dup->headers->all(), '->duplicate() duplicates a request an copy the current HTTP headers');
  232. $dup = $request->duplicate(array('foo' => 'foobar'), array('foo' => 'foobar'), array('foo' => 'foobar'), array(), array(), array('HTTP_FOO' => 'foobar'));
  233. $this->assertEquals(array('foo' => 'foobar'), $dup->query->all(), '->duplicate() overrides the query parameters if provided');
  234. $this->assertEquals(array('foo' => 'foobar'), $dup->request->all(), '->duplicate() overrides the request parameters if provided');
  235. $this->assertEquals(array('foo' => 'foobar'), $dup->attributes->all(), '->duplicate() overrides the attributes if provided');
  236. $this->assertEquals(array('foo' => array('foobar')), $dup->headers->all(), '->duplicate() overrides the HTTP header if provided');
  237. }
  238. public function testDuplicateWithFormat()
  239. {
  240. $request = new Request(array(), array(), array('_format' => 'json'));
  241. $dup = $request->duplicate();
  242. $this->assertEquals('json', $dup->getRequestFormat());
  243. $this->assertEquals('json', $dup->attributes->get('_format'));
  244. $request = new Request();
  245. $request->setRequestFormat('xml');
  246. $dup = $request->duplicate();
  247. $this->assertEquals('xml', $dup->getRequestFormat());
  248. }
  249. /**
  250. * @dataProvider getFormatToMimeTypeMapProvider
  251. */
  252. public function testGetFormatFromMimeType($format, $mimeTypes)
  253. {
  254. $request = new Request();
  255. foreach ($mimeTypes as $mime) {
  256. $this->assertEquals($format, $request->getFormat($mime));
  257. }
  258. $request->setFormat($format, $mimeTypes);
  259. foreach ($mimeTypes as $mime) {
  260. $this->assertEquals($format, $request->getFormat($mime));
  261. }
  262. }
  263. public function testGetFormatFromMimeTypeWithParameters()
  264. {
  265. $request = new Request();
  266. $this->assertEquals('json', $request->getFormat('application/json; charset=utf-8'));
  267. }
  268. /**
  269. * @dataProvider getFormatToMimeTypeMapProvider
  270. */
  271. public function testGetMimeTypeFromFormat($format, $mimeTypes)
  272. {
  273. if (null !== $format) {
  274. $request = new Request();
  275. $this->assertEquals($mimeTypes[0], $request->getMimeType($format));
  276. }
  277. }
  278. public function getFormatToMimeTypeMapProvider()
  279. {
  280. return array(
  281. array(null, array(null, 'unexistent-mime-type')),
  282. array('txt', array('text/plain')),
  283. array('js', array('application/javascript', 'application/x-javascript', 'text/javascript')),
  284. array('css', array('text/css')),
  285. array('json', array('application/json', 'application/x-json')),
  286. array('xml', array('text/xml', 'application/xml', 'application/x-xml')),
  287. array('rdf', array('application/rdf+xml')),
  288. array('atom', array('application/atom+xml')),
  289. );
  290. }
  291. public function testGetUri()
  292. {
  293. $server = array();
  294. // Standard Request on non default PORT
  295. // http://host:8080/index.php/path/info?query=string
  296. $server['HTTP_HOST'] = 'host:8080';
  297. $server['SERVER_NAME'] = 'servername';
  298. $server['SERVER_PORT'] = '8080';
  299. $server['QUERY_STRING'] = 'query=string';
  300. $server['REQUEST_URI'] = '/index.php/path/info?query=string';
  301. $server['SCRIPT_NAME'] = '/index.php';
  302. $server['PATH_INFO'] = '/path/info';
  303. $server['PATH_TRANSLATED'] = 'redirect:/index.php/path/info';
  304. $server['PHP_SELF'] = '/index_dev.php/path/info';
  305. $server['SCRIPT_FILENAME'] = '/some/where/index.php';
  306. $request = new Request();
  307. $request->initialize(array(), array(), array(), array(), array(), $server);
  308. $this->assertEquals('http://host:8080/index.php/path/info?query=string', $request->getUri(), '->getUri() with non default port');
  309. // Use std port number
  310. $server['HTTP_HOST'] = 'host';
  311. $server['SERVER_NAME'] = 'servername';
  312. $server['SERVER_PORT'] = '80';
  313. $request->initialize(array(), array(), array(), array(), array(), $server);
  314. $this->assertEquals('http://host/index.php/path/info?query=string', $request->getUri(), '->getUri() with default port');
  315. // Without HOST HEADER
  316. unset($server['HTTP_HOST']);
  317. $server['SERVER_NAME'] = 'servername';
  318. $server['SERVER_PORT'] = '80';
  319. $request->initialize(array(), array(), array(), array(), array(), $server);
  320. $this->assertEquals('http://servername/index.php/path/info?query=string', $request->getUri(), '->getUri() with default port without HOST_HEADER');
  321. // Request with URL REWRITING (hide index.php)
  322. // RewriteCond %{REQUEST_FILENAME} !-f
  323. // RewriteRule ^(.*)$ index.php [QSA,L]
  324. // http://host:8080/path/info?query=string
  325. $server = array();
  326. $server['HTTP_HOST'] = 'host:8080';
  327. $server['SERVER_NAME'] = 'servername';
  328. $server['SERVER_PORT'] = '8080';
  329. $server['REDIRECT_QUERY_STRING'] = 'query=string';
  330. $server['REDIRECT_URL'] = '/path/info';
  331. $server['SCRIPT_NAME'] = '/index.php';
  332. $server['QUERY_STRING'] = 'query=string';
  333. $server['REQUEST_URI'] = '/path/info?toto=test&1=1';
  334. $server['SCRIPT_NAME'] = '/index.php';
  335. $server['PHP_SELF'] = '/index.php';
  336. $server['SCRIPT_FILENAME'] = '/some/where/index.php';
  337. $request->initialize(array(), array(), array(), array(), array(), $server);
  338. $this->assertEquals('http://host:8080/path/info?query=string', $request->getUri(), '->getUri() with rewrite');
  339. // Use std port number
  340. // http://host/path/info?query=string
  341. $server['HTTP_HOST'] = 'host';
  342. $server['SERVER_NAME'] = 'servername';
  343. $server['SERVER_PORT'] = '80';
  344. $request->initialize(array(), array(), array(), array(), array(), $server);
  345. $this->assertEquals('http://host/path/info?query=string', $request->getUri(), '->getUri() with rewrite and default port');
  346. // Without HOST HEADER
  347. unset($server['HTTP_HOST']);
  348. $server['SERVER_NAME'] = 'servername';
  349. $server['SERVER_PORT'] = '80';
  350. $request->initialize(array(), array(), array(), array(), array(), $server);
  351. $this->assertEquals('http://servername/path/info?query=string', $request->getUri(), '->getUri() with rewrite, default port without HOST_HEADER');
  352. // With encoded characters
  353. $server = array(
  354. 'HTTP_HOST' => 'host:8080',
  355. 'SERVER_NAME' => 'servername',
  356. 'SERVER_PORT' => '8080',
  357. 'QUERY_STRING' => 'query=string',
  358. 'REQUEST_URI' => '/ba%20se/index_dev.php/foo%20bar/in+fo?query=string',
  359. 'SCRIPT_NAME' => '/ba se/index_dev.php',
  360. 'PATH_TRANSLATED' => 'redirect:/index.php/foo bar/in+fo',
  361. 'PHP_SELF' => '/ba se/index_dev.php/path/info',
  362. 'SCRIPT_FILENAME' => '/some/where/ba se/index_dev.php',
  363. );
  364. $request->initialize(array(), array(), array(), array(), array(), $server);
  365. $this->assertEquals(
  366. 'http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string',
  367. $request->getUri()
  368. );
  369. // with user info
  370. $server['PHP_AUTH_USER'] = 'fabien';
  371. $request->initialize(array(), array(), array(), array(), array(), $server);
  372. $this->assertEquals('http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string', $request->getUri());
  373. $server['PHP_AUTH_PW'] = 'symfony';
  374. $request->initialize(array(), array(), array(), array(), array(), $server);
  375. $this->assertEquals('http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string', $request->getUri());
  376. }
  377. public function testGetUriForPath()
  378. {
  379. $request = Request::create('http://test.com/foo?bar=baz');
  380. $this->assertEquals('http://test.com/some/path', $request->getUriForPath('/some/path'));
  381. $request = Request::create('http://test.com:90/foo?bar=baz');
  382. $this->assertEquals('http://test.com:90/some/path', $request->getUriForPath('/some/path'));
  383. $request = Request::create('https://test.com/foo?bar=baz');
  384. $this->assertEquals('https://test.com/some/path', $request->getUriForPath('/some/path'));
  385. $request = Request::create('https://test.com:90/foo?bar=baz');
  386. $this->assertEquals('https://test.com:90/some/path', $request->getUriForPath('/some/path'));
  387. $server = array();
  388. // Standard Request on non default PORT
  389. // http://host:8080/index.php/path/info?query=string
  390. $server['HTTP_HOST'] = 'host:8080';
  391. $server['SERVER_NAME'] = 'servername';
  392. $server['SERVER_PORT'] = '8080';
  393. $server['QUERY_STRING'] = 'query=string';
  394. $server['REQUEST_URI'] = '/index.php/path/info?query=string';
  395. $server['SCRIPT_NAME'] = '/index.php';
  396. $server['PATH_INFO'] = '/path/info';
  397. $server['PATH_TRANSLATED'] = 'redirect:/index.php/path/info';
  398. $server['PHP_SELF'] = '/index_dev.php/path/info';
  399. $server['SCRIPT_FILENAME'] = '/some/where/index.php';
  400. $request = new Request();
  401. $request->initialize(array(), array(), array(), array(), array(), $server);
  402. $this->assertEquals('http://host:8080/index.php/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with non default port');
  403. // Use std port number
  404. $server['HTTP_HOST'] = 'host';
  405. $server['SERVER_NAME'] = 'servername';
  406. $server['SERVER_PORT'] = '80';
  407. $request->initialize(array(), array(), array(), array(), array(), $server);
  408. $this->assertEquals('http://host/index.php/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with default port');
  409. // Without HOST HEADER
  410. unset($server['HTTP_HOST']);
  411. $server['SERVER_NAME'] = 'servername';
  412. $server['SERVER_PORT'] = '80';
  413. $request->initialize(array(), array(), array(), array(), array(), $server);
  414. $this->assertEquals('http://servername/index.php/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with default port without HOST_HEADER');
  415. // Request with URL REWRITING (hide index.php)
  416. // RewriteCond %{REQUEST_FILENAME} !-f
  417. // RewriteRule ^(.*)$ index.php [QSA,L]
  418. // http://host:8080/path/info?query=string
  419. $server = array();
  420. $server['HTTP_HOST'] = 'host:8080';
  421. $server['SERVER_NAME'] = 'servername';
  422. $server['SERVER_PORT'] = '8080';
  423. $server['REDIRECT_QUERY_STRING'] = 'query=string';
  424. $server['REDIRECT_URL'] = '/path/info';
  425. $server['SCRIPT_NAME'] = '/index.php';
  426. $server['QUERY_STRING'] = 'query=string';
  427. $server['REQUEST_URI'] = '/path/info?toto=test&1=1';
  428. $server['SCRIPT_NAME'] = '/index.php';
  429. $server['PHP_SELF'] = '/index.php';
  430. $server['SCRIPT_FILENAME'] = '/some/where/index.php';
  431. $request->initialize(array(), array(), array(), array(), array(), $server);
  432. $this->assertEquals('http://host:8080/some/path', $request->getUriForPath('/some/path'), '->getUri() with rewrite');
  433. // Use std port number
  434. // http://host/path/info?query=string
  435. $server['HTTP_HOST'] = 'host';
  436. $server['SERVER_NAME'] = 'servername';
  437. $server['SERVER_PORT'] = '80';
  438. $request->initialize(array(), array(), array(), array(), array(), $server);
  439. $this->assertEquals('http://host/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with rewrite and default port');
  440. // Without HOST HEADER
  441. unset($server['HTTP_HOST']);
  442. $server['SERVER_NAME'] = 'servername';
  443. $server['SERVER_PORT'] = '80';
  444. $request->initialize(array(), array(), array(), array(), array(), $server);
  445. $this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with rewrite, default port without HOST_HEADER');
  446. $this->assertEquals('servername', $request->getHttpHost());
  447. // with user info
  448. $server['PHP_AUTH_USER'] = 'fabien';
  449. $request->initialize(array(), array(), array(), array(), array(), $server);
  450. $this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path'));
  451. $server['PHP_AUTH_PW'] = 'symfony';
  452. $request->initialize(array(), array(), array(), array(), array(), $server);
  453. $this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path'));
  454. }
  455. /**
  456. * @dataProvider getRelativeUriForPathData()
  457. */
  458. public function testGetRelativeUriForPath($expected, $pathinfo, $path)
  459. {
  460. $this->assertEquals($expected, Request::create($pathinfo)->getRelativeUriForPath($path));
  461. }
  462. public function getRelativeUriForPathData()
  463. {
  464. return array(
  465. array('me.png', '/foo', '/me.png'),
  466. array('../me.png', '/foo/bar', '/me.png'),
  467. array('me.png', '/foo/bar', '/foo/me.png'),
  468. array('../baz/me.png', '/foo/bar/b', '/foo/baz/me.png'),
  469. array('../../fooz/baz/me.png', '/foo/bar/b', '/fooz/baz/me.png'),
  470. array('baz/me.png', '/foo/bar/b', 'baz/me.png'),
  471. );
  472. }
  473. public function testGetUserInfo()
  474. {
  475. $request = new Request();
  476. $server = array('PHP_AUTH_USER' => 'fabien');
  477. $request->initialize(array(), array(), array(), array(), array(), $server);
  478. $this->assertEquals('fabien', $request->getUserInfo());
  479. $server['PHP_AUTH_USER'] = '0';
  480. $request->initialize(array(), array(), array(), array(), array(), $server);
  481. $this->assertEquals('0', $request->getUserInfo());
  482. $server['PHP_AUTH_PW'] = '0';
  483. $request->initialize(array(), array(), array(), array(), array(), $server);
  484. $this->assertEquals('0:0', $request->getUserInfo());
  485. }
  486. public function testGetSchemeAndHttpHost()
  487. {
  488. $request = new Request();
  489. $server = array();
  490. $server['SERVER_NAME'] = 'servername';
  491. $server['SERVER_PORT'] = '90';
  492. $request->initialize(array(), array(), array(), array(), array(), $server);
  493. $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost());
  494. $server['PHP_AUTH_USER'] = 'fabien';
  495. $request->initialize(array(), array(), array(), array(), array(), $server);
  496. $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost());
  497. $server['PHP_AUTH_USER'] = '0';
  498. $request->initialize(array(), array(), array(), array(), array(), $server);
  499. $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost());
  500. $server['PHP_AUTH_PW'] = '0';
  501. $request->initialize(array(), array(), array(), array(), array(), $server);
  502. $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost());
  503. }
  504. /**
  505. * @dataProvider getQueryStringNormalizationData
  506. */
  507. public function testGetQueryString($query, $expectedQuery, $msg)
  508. {
  509. $request = new Request();
  510. $request->server->set('QUERY_STRING', $query);
  511. $this->assertSame($expectedQuery, $request->getQueryString(), $msg);
  512. }
  513. public function getQueryStringNormalizationData()
  514. {
  515. return array(
  516. array('foo', 'foo', 'works with valueless parameters'),
  517. array('foo=', 'foo=', 'includes a dangling equal sign'),
  518. array('bar=&foo=bar', 'bar=&foo=bar', '->works with empty parameters'),
  519. array('foo=bar&bar=', 'bar=&foo=bar', 'sorts keys alphabetically'),
  520. // GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded).
  521. // PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str.
  522. array('him=John%20Doe&her=Jane+Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes spaces in both encodings "%20" and "+"'),
  523. array('foo[]=1&foo[]=2', 'foo%5B%5D=1&foo%5B%5D=2', 'allows array notation'),
  524. array('foo=1&foo=2', 'foo=1&foo=2', 'allows repeated parameters'),
  525. array('pa%3Dram=foo%26bar%3Dbaz&test=test', 'pa%3Dram=foo%26bar%3Dbaz&test=test', 'works with encoded delimiters'),
  526. array('0', '0', 'allows "0"'),
  527. array('Jane Doe&John%20Doe', 'Jane%20Doe&John%20Doe', 'normalizes encoding in keys'),
  528. array('her=Jane Doe&him=John%20Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes encoding in values'),
  529. array('foo=bar&&&test&&', 'foo=bar&test', 'removes unneeded delimiters'),
  530. array('formula=e=m*c^2', 'formula=e%3Dm%2Ac%5E2', 'correctly treats only the first "=" as delimiter and the next as value'),
  531. // Ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway.
  532. // PHP also does not include them when building _GET.
  533. array('foo=bar&=a=b&=x=y', 'foo=bar', 'removes params with empty key'),
  534. );
  535. }
  536. public function testGetQueryStringReturnsNull()
  537. {
  538. $request = new Request();
  539. $this->assertNull($request->getQueryString(), '->getQueryString() returns null for non-existent query string');
  540. $request->server->set('QUERY_STRING', '');
  541. $this->assertNull($request->getQueryString(), '->getQueryString() returns null for empty query string');
  542. }
  543. public function testGetHost()
  544. {
  545. $request = new Request();
  546. $request->initialize(array('foo' => 'bar'));
  547. $this->assertEquals('', $request->getHost(), '->getHost() return empty string if not initialized');
  548. $request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.example.com'));
  549. $this->assertEquals('www.example.com', $request->getHost(), '->getHost() from Host Header');
  550. // Host header with port number
  551. $request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.example.com:8080'));
  552. $this->assertEquals('www.example.com', $request->getHost(), '->getHost() from Host Header with port number');
  553. // Server values
  554. $request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.example.com'));
  555. $this->assertEquals('www.example.com', $request->getHost(), '->getHost() from server name');
  556. $request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.example.com', 'HTTP_HOST' => 'www.host.com'));
  557. $this->assertEquals('www.host.com', $request->getHost(), '->getHost() value from Host header has priority over SERVER_NAME ');
  558. }
  559. public function testGetPort()
  560. {
  561. $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
  562. 'HTTP_X_FORWARDED_PROTO' => 'https',
  563. 'HTTP_X_FORWARDED_PORT' => '443',
  564. ));
  565. $port = $request->getPort();
  566. $this->assertEquals(80, $port, 'Without trusted proxies FORWARDED_PROTO and FORWARDED_PORT are ignored.');
  567. Request::setTrustedProxies(array('1.1.1.1'));
  568. $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
  569. 'HTTP_X_FORWARDED_PROTO' => 'https',
  570. 'HTTP_X_FORWARDED_PORT' => '8443',
  571. ));
  572. $this->assertEquals(80, $request->getPort(), 'With PROTO and PORT on untrusted connection server value takes precedence.');
  573. $request->server->set('REMOTE_ADDR', '1.1.1.1');
  574. $this->assertEquals(8443, $request->getPort(), 'With PROTO and PORT set PORT takes precedence.');
  575. $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
  576. 'HTTP_X_FORWARDED_PROTO' => 'https',
  577. ));
  578. $this->assertEquals(80, $request->getPort(), 'With only PROTO set getPort() ignores trusted headers on untrusted connection.');
  579. $request->server->set('REMOTE_ADDR', '1.1.1.1');
  580. $this->assertEquals(443, $request->getPort(), 'With only PROTO set getPort() defaults to 443.');
  581. $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
  582. 'HTTP_X_FORWARDED_PROTO' => 'http',
  583. ));
  584. $this->assertEquals(80, $request->getPort(), 'If X_FORWARDED_PROTO is set to HTTP getPort() ignores trusted headers on untrusted connection.');
  585. $request->server->set('REMOTE_ADDR', '1.1.1.1');
  586. $this->assertEquals(80, $request->getPort(), 'If X_FORWARDED_PROTO is set to HTTP getPort() returns port of the original request.');
  587. $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
  588. 'HTTP_X_FORWARDED_PROTO' => 'On',
  589. ));
  590. $this->assertEquals(80, $request->getPort(), 'With only PROTO set and value is On, getPort() ignores trusted headers on untrusted connection.');
  591. $request->server->set('REMOTE_ADDR', '1.1.1.1');
  592. $this->assertEquals(443, $request->getPort(), 'With only PROTO set and value is On, getPort() defaults to 443.');
  593. $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
  594. 'HTTP_X_FORWARDED_PROTO' => '1',
  595. ));
  596. $this->assertEquals(80, $request->getPort(), 'With only PROTO set and value is 1, getPort() ignores trusted headers on untrusted connection.');
  597. $request->server->set('REMOTE_ADDR', '1.1.1.1');
  598. $this->assertEquals(443, $request->getPort(), 'With only PROTO set and value is 1, getPort() defaults to 443.');
  599. $request = Request::create('http://example.com', 'GET', array(), array(), array(), array(
  600. 'HTTP_X_FORWARDED_PROTO' => 'something-else',
  601. ));
  602. $port = $request->getPort();
  603. $this->assertEquals(80, $port, 'With only PROTO set and value is not recognized, getPort() defaults to 80.');
  604. Request::setTrustedProxies(array());
  605. }
  606. /**
  607. * @expectedException \RuntimeException
  608. */
  609. public function testGetHostWithFakeHttpHostValue()
  610. {
  611. $request = new Request();
  612. $request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.host.com?query=string'));
  613. $request->getHost();
  614. }
  615. public function testGetSetMethod()
  616. {
  617. $request = new Request();
  618. $this->assertEquals('GET', $request->getMethod(), '->getMethod() returns GET if no method is defined');
  619. $request->setMethod('get');
  620. $this->assertEquals('GET', $request->getMethod(), '->getMethod() returns an uppercased string');
  621. $request->setMethod('PURGE');
  622. $this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method even if it is not a standard one');
  623. $request->setMethod('POST');
  624. $this->assertEquals('POST', $request->getMethod(), '->getMethod() returns the method POST if no _method is defined');
  625. $request->setMethod('POST');
  626. $request->request->set('_method', 'purge');
  627. $this->assertEquals('POST', $request->getMethod(), '->getMethod() does not return the method from _method if defined and POST but support not enabled');
  628. $request = new Request();
  629. $request->setMethod('POST');
  630. $request->request->set('_method', 'purge');
  631. $this->assertFalse(Request::getHttpMethodParameterOverride(), 'httpMethodParameterOverride should be disabled by default');
  632. Request::enableHttpMethodParameterOverride();
  633. $this->assertTrue(Request::getHttpMethodParameterOverride(), 'httpMethodParameterOverride should be enabled now but it is not');
  634. $this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST');
  635. $this->disableHttpMethodParameterOverride();
  636. $request = new Request();
  637. $request->setMethod('POST');
  638. $request->query->set('_method', 'purge');
  639. $this->assertEquals('POST', $request->getMethod(), '->getMethod() does not return the method from _method if defined and POST but support not enabled');
  640. $request = new Request();
  641. $request->setMethod('POST');
  642. $request->query->set('_method', 'purge');
  643. Request::enableHttpMethodParameterOverride();
  644. $this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST');
  645. $this->disableHttpMethodParameterOverride();
  646. $request = new Request();
  647. $request->setMethod('POST');
  648. $request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete');
  649. $this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override even though _method is set if defined and POST');
  650. $request = new Request();
  651. $request->setMethod('POST');
  652. $request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete');
  653. $this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override if defined and POST');
  654. }
  655. /**
  656. * @dataProvider testGetClientIpsProvider
  657. */
  658. public function testGetClientIp($expected, $remoteAddr, $httpForwardedFor, $trustedProxies)
  659. {
  660. $request = $this->getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies);
  661. $this->assertEquals($expected[0], $request->getClientIp());
  662. Request::setTrustedProxies(array());
  663. }
  664. /**
  665. * @dataProvider testGetClientIpsProvider
  666. */
  667. public function testGetClientIps($expected, $remoteAddr, $httpForwardedFor, $trustedProxies)
  668. {
  669. $request = $this->getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies);
  670. $this->assertEquals($expected, $request->getClientIps());
  671. Request::setTrustedProxies(array());
  672. }
  673. /**
  674. * @dataProvider testGetClientIpsForwardedProvider
  675. */
  676. public function testGetClientIpsForwarded($expected, $remoteAddr, $httpForwarded, $trustedProxies)
  677. {
  678. $request = $this->getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies);
  679. $this->assertEquals($expected, $request->getClientIps());
  680. Request::setTrustedProxies(array());
  681. }
  682. public function testGetClientIpsForwardedProvider()
  683. {
  684. // $expected $remoteAddr $httpForwarded $trustedProxies
  685. return array(
  686. array(array('127.0.0.1'), '127.0.0.1', 'for="_gazonk"', null),
  687. array(array('127.0.0.1'), '127.0.0.1', 'for="_gazonk"', array('127.0.0.1')),
  688. array(array('88.88.88.88'), '127.0.0.1', 'for="88.88.88.88:80"', array('127.0.0.1')),
  689. array(array('192.0.2.60'), '::1', 'for=192.0.2.60;proto=http;by=203.0.113.43', array('::1')),
  690. array(array('2620:0:1cfe:face:b00c::3', '192.0.2.43'), '::1', 'for=192.0.2.43, for=2620:0:1cfe:face:b00c::3', array('::1')),
  691. array(array('2001:db8:cafe::17'), '::1', 'for="[2001:db8:cafe::17]:4711', array('::1')),
  692. );
  693. }
  694. public function testGetClientIpsProvider()
  695. {
  696. // $expected $remoteAddr $httpForwardedFor $trustedProxies
  697. return array(
  698. // simple IPv4
  699. array(array('88.88.88.88'), '88.88.88.88', null, null),
  700. // trust the IPv4 remote addr
  701. array(array('88.88.88.88'), '88.88.88.88', null, array('88.88.88.88')),
  702. // simple IPv6
  703. array(array('::1'), '::1', null, null),
  704. // trust the IPv6 remote addr
  705. array(array('::1'), '::1', null, array('::1')),
  706. // forwarded for with remote IPv4 addr not trusted
  707. array(array('127.0.0.1'), '127.0.0.1', '88.88.88.88', null),
  708. // forwarded for with remote IPv4 addr trusted
  709. array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88', array('127.0.0.1')),
  710. // forwarded for with remote IPv4 and all FF addrs trusted
  711. array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88', array('127.0.0.1', '88.88.88.88')),
  712. // forwarded for with remote IPv4 range trusted
  713. array(array('88.88.88.88'), '123.45.67.89', '88.88.88.88', array('123.45.67.0/24')),
  714. // forwarded for with remote IPv6 addr not trusted
  715. array(array('1620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3', null),
  716. // forwarded for with remote IPv6 addr trusted
  717. array(array('2620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3', array('1620:0:1cfe:face:b00c::3')),
  718. // forwarded for with remote IPv6 range trusted
  719. array(array('88.88.88.88'), '2a01:198:603:0:396e:4789:8e99:890f', '88.88.88.88', array('2a01:198:603:0::/65')),
  720. // multiple forwarded for with remote IPv4 addr trusted
  721. array(array('88.88.88.88', '87.65.43.21', '127.0.0.1'), '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89')),
  722. // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted
  723. array(array('87.65.43.21', '127.0.0.1'), '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89', '88.88.88.88')),
  724. // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted but in the middle
  725. array(array('88.88.88.88', '127.0.0.1'), '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89', '87.65.43.21')),
  726. // multiple forwarded for with remote IPv4 addr and all reverse proxies trusted
  727. array(array('127.0.0.1'), '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89', '87.65.43.21', '88.88.88.88', '127.0.0.1')),
  728. // multiple forwarded for with remote IPv6 addr trusted
  729. array(array('2620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3,2620:0:1cfe:face:b00c::3', array('1620:0:1cfe:face:b00c::3')),
  730. // multiple forwarded for with remote IPv6 addr and some reverse proxies trusted
  731. array(array('3620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3,2620:0:1cfe:face:b00c::3', array('1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3')),
  732. // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted but in the middle
  733. array(array('2620:0:1cfe:face:b00c::3', '4620:0:1cfe:face:b00c::3'), '1620:0:1cfe:face:b00c::3', '4620:0:1cfe:face:b00c::3,3620:0:1cfe:face:b00c::3,2620:0:1cfe:face:b00c::3', array('1620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3')),
  734. // client IP with port
  735. array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88:12345, 127.0.0.1', array('127.0.0.1')),
  736. // invalid forwarded IP is ignored
  737. array(array('88.88.88.88'), '127.0.0.1', 'unknown,88.88.88.88', array('127.0.0.1')),
  738. );
  739. }
  740. public function testGetContentWorksTwiceInDefaultMode()
  741. {
  742. $req = new Request();
  743. $this->assertEquals('', $req->getContent());
  744. $this->assertEquals('', $req->getContent());
  745. }
  746. public function testGetContentReturnsResource()
  747. {
  748. $req = new Request();
  749. $retval = $req->getContent(true);
  750. $this->assertInternalType('resource', $retval);
  751. $this->assertEquals('', fread($retval, 1));
  752. $this->assertTrue(feof($retval));
  753. }
  754. public function testGetContentReturnsResourceWhenContentSetInConstructor()
  755. {
  756. $req = new Request(array(), array(), array(), array(), array(), array(), 'MyContent');
  757. $resource = $req->getContent(true);
  758. $this->assertTrue(is_resource($resource));
  759. $this->assertEquals('MyContent', stream_get_contents($resource));
  760. }
  761. public function testContentAsResource()
  762. {
  763. $resource = fopen('php://memory', 'r+');
  764. fwrite($resource, 'My other content');
  765. rewind($resource);
  766. $req = new Request(array(), array(), array(), array(), array(), array(), $resource);
  767. $this->assertEquals('My other content', stream_get_contents($req->getContent(true)));
  768. $this->assertEquals('My other content', $req->getContent());
  769. }
  770. /**
  771. * @expectedException \LogicException
  772. * @dataProvider getContentCantBeCalledTwiceWithResourcesProvider
  773. */
  774. public function testGetContentCantBeCalledTwiceWithResources($first, $second)
  775. {
  776. if (PHP_VERSION_ID >= 50600) {
  777. $this->markTestSkipped('PHP >= 5.6 allows to open php://input several times.');
  778. }
  779. $req = new Request();
  780. $req->getContent($first);
  781. $req->getContent($second);
  782. }
  783. /**
  784. * @dataProvider getContentCantBeCalledTwiceWithResourcesProvider
  785. * @requires PHP 5.6
  786. */
  787. public function testGetContentCanBeCalledTwiceWithResources($first, $second)
  788. {
  789. $req = new Request();
  790. $a = $req->getContent($first);
  791. $b = $req->getContent($second);
  792. if ($first) {
  793. $a = stream_get_contents($a);
  794. }
  795. if ($second) {
  796. $b = stream_get_contents($b);
  797. }
  798. $this->assertEquals($a, $b);
  799. }
  800. public function getContentCantBeCalledTwiceWithResourcesProvider()
  801. {
  802. return array(
  803. 'Resource then fetch' => array(true, false),
  804. 'Resource then resource' => array(true, true),
  805. );
  806. }
  807. public function provideOverloadedMethods()
  808. {
  809. return array(
  810. array('PUT'),
  811. array('DELETE'),
  812. array('PATCH'),
  813. array('put'),
  814. array('delete'),
  815. array('patch'),
  816. );
  817. }
  818. /**
  819. * @dataProvider provideOverloadedMethods
  820. */
  821. public function testCreateFromGlobals($method)
  822. {
  823. $normalizedMethod = strtoupper($method);
  824. $_GET['foo1'] = 'bar1';
  825. $_POST['foo2'] = 'bar2';
  826. $_COOKIE['foo3'] = 'bar3';
  827. $_FILES['foo4'] = array('bar4');
  828. $_SERVER['foo5'] = 'bar5';
  829. $request = Request::createFromGlobals();
  830. $this->assertEquals('bar1', $request->query->get('foo1'), '::fromGlobals() uses values from $_GET');
  831. $this->assertEquals('bar2', $request->request->get('foo2'), '::fromGlobals() uses values from $_POST');
  832. $this->assertEquals('bar3', $request->cookies->get('foo3'), '::fromGlobals() uses values from $_COOKIE');
  833. $this->assertEquals(array('bar4'), $request->files->get('foo4'), '::fromGlobals() uses values from $_FILES');
  834. $this->assertEquals('bar5', $request->server->get('foo5'), '::fromGlobals() uses values from $_SERVER');
  835. unset($_GET['foo1'], $_POST['foo2'], $_COOKIE['foo3'], $_FILES['foo4'], $_SERVER['foo5']);
  836. $_SERVER['REQUEST_METHOD'] = $method;
  837. $_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
  838. $request = RequestContentProxy::createFromGlobals();
  839. $this->assertEquals($normalizedMethod, $request->getMethod());
  840. $this->assertEquals('mycontent', $request->request->get('content'));
  841. unset($_SERVER['REQUEST_METHOD'], $_SERVER['CONTENT_TYPE']);
  842. Request::createFromGlobals();
  843. Request::enableHttpMethodParameterOverride();
  844. $_POST['_method'] = $method;
  845. $_POST['foo6'] = 'bar6';
  846. $_SERVER['REQUEST_METHOD'] = 'PoSt';
  847. $request = Request::createFromGlobals();
  848. $this->assertEquals($normalizedMethod, $request->getMethod());
  849. $this->assertEquals('POST', $request->getRealMethod());
  850. $this->assertEquals('bar6', $request->request->get('foo6'));
  851. unset($_POST['_method'], $_POST['foo6'], $_SERVER['REQUEST_METHOD']);
  852. $this->disableHttpMethodParameterOverride();
  853. }
  854. public function testOverrideGlobals()
  855. {
  856. $request = new Request();
  857. $request->initialize(array('foo' => 'bar'));
  858. // as the Request::overrideGlobals really work, it erase $_SERVER, so we must backup it
  859. $server = $_SERVER;
  860. $request->overrideGlobals();
  861. $this->assertEquals(array('foo' => 'bar'), $_GET);
  862. $request->initialize(array(), array('foo' => 'bar'));
  863. $request->overrideGlobals();
  864. $this->assertEquals(array('foo' => 'bar'), $_POST);
  865. $this->assertArrayNotHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER);
  866. $request->headers->set('X_FORWARDED_PROTO', 'https');
  867. Request::setTrustedProxies(array('1.1.1.1'));
  868. $this->assertFalse($request->isSecure());
  869. $request->server->set('REMOTE_ADDR', '1.1.1.1');
  870. $this->assertTrue($request->isSecure());
  871. Request::setTrustedProxies(array());
  872. $request->overrideGlobals();
  873. $this->assertArrayHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER);
  874. $request->headers->set('CONTENT_TYPE', 'multipart/form-data');
  875. $request->headers->set('CONTENT_LENGTH', 12345);
  876. $request->overrideGlobals();
  877. $this->assertArrayHasKey('CONTENT_TYPE', $_SERVER);
  878. $this->assertArrayHasKey('CONTENT_LENGTH', $_SERVER);
  879. $request->initialize(array('foo' => 'bar', 'baz' => 'foo'));
  880. $request->query->remove('baz');
  881. $request->overrideGlobals();
  882. $this->assertEquals(array('foo' => 'bar'), $_GET);
  883. $this->assertEquals('foo=bar', $_SERVER['QUERY_STRING']);
  884. $this->assertEquals('foo=bar', $request->server->get('QUERY_STRING'));
  885. // restore initial $_SERVER array
  886. $_SERVER = $server;
  887. }
  888. public function testGetScriptName()
  889. {
  890. $request = new Request();
  891. $this->assertEquals('', $request->getScriptName());
  892. $server = array();
  893. $server['SCRIPT_NAME'] = '/index.php';
  894. $request->initialize(array(), array(), array(), array(), array(), $server);
  895. $this->assertEquals('/index.php', $request->getScriptName());
  896. $server = array();
  897. $server['ORIG_SCRIPT_NAME'] = '/frontend.php';
  898. $request->initialize(array(), array(), array(), array(), array(), $server);
  899. $this->assertEquals('/frontend.php', $request->getScriptName());
  900. $server = array();
  901. $server['SCRIPT_NAME'] = '/index.php';
  902. $server['ORIG_SCRIPT_NAME'] = '/frontend.php';
  903. $request->initialize(array(), array(), array(), array(), array(), $server);
  904. $this->assertEquals('/index.php', $request->getScriptName());
  905. }
  906. public function testGetBasePath()
  907. {
  908. $request = new Request();
  909. $this->assertEquals('', $request->getBasePath());
  910. $server = array();
  911. $server['SCRIPT_FILENAME'] = '/some/where/index.php';
  912. $request->initialize(array(), array(), array(), array(), array(), $server);
  913. $this->assertEquals('', $request->getBasePath());
  914. $server = array();
  915. $server['SCRIPT_FILENAME'] = '/some/where/index.php';
  916. $server['SCRIPT_NAME'] = '/index.php';
  917. $request->initialize(array(), array(), array(), array(), array(), $server);
  918. $this->assertEquals('', $request->getBasePath());
  919. $server = array();
  920. $server['SCRIPT_FILENAME'] = '/some/where/index.php';
  921. $server['PHP_SELF'] = '/index.php';
  922. $request->initialize(array(), array(), array(), array(), array(), $server);
  923. $this->assertEquals('', $request->getBasePath());
  924. $server = array();
  925. $server['SCRIPT_FILENAME'] = '/some/where/index.php';
  926. $server['ORIG_SCRIPT_NAME'] = '/index.php';
  927. $request->initialize(array(), array(), array(), array(), array(), $server);
  928. $this->assertEquals('', $request->getBasePath());
  929. }
  930. public function testGetPathInfo()
  931. {
  932. $request = new Request();
  933. $this->assertEquals('/', $request->getPathInfo());
  934. $server = array();
  935. $server['REQUEST_URI'] = '/path/info';
  936. $request->initialize(array(), array(), array(), array(), array(), $server);
  937. $this->assertEquals('/path/info', $request->getPathInfo());
  938. $server = array();
  939. $server['REQUEST_URI'] = '/path%20test/info';
  940. $request->initialize(array(), array(), array(), array(), array(), $server);
  941. $this->assertEquals('/path%20test/info', $request->getPathInfo());
  942. }
  943. public function testGetPreferredLanguage()
  944. {
  945. $request = new Request();
  946. $this->assertNull($request->getPreferredLanguage());
  947. $this->assertNull($request->getPreferredLanguage(array()));
  948. $this->assertEquals('fr', $request->getPreferredLanguage(array('fr')));
  949. $this->assertEquals('fr', $request->getPreferredLanguage(array('fr', 'en')));
  950. $this->assertEquals('en', $request->getPreferredLanguage(array('en', 'fr')));
  951. $this->assertEquals('fr-ch', $request->getPreferredLanguage(array('fr-ch', 'fr-fr')));
  952. $request = new Request();
  953. $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
  954. $this->assertEquals('en', $request->getPreferredLanguage(array('en', 'en-us')));
  955. $request = new Request();
  956. $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
  957. $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
  958. $request = new Request();
  959. $request->headers->set('Accept-language', 'zh, en-us; q=0.8');
  960. $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
  961. $request = new Request();
  962. $request->headers->set('Accept-language', 'zh, en-us; q=0.8, fr-fr; q=0.6, fr; q=0.5');
  963. $this->assertEquals('en', $request->getPreferredLanguage(array('fr', 'en')));
  964. }
  965. public function testIsXmlHttpRequest()
  966. {
  967. $request = new Request();
  968. $this->assertFalse($request->isXmlHttpRequest());
  969. $request->headers->set('X-Requested-With', 'XMLHttpRequest');
  970. $this->assertTrue($request->isXmlHttpRequest());
  971. $request->headers->remove('X-Requested-With');
  972. $this->assertFalse($request->isXmlHttpRequest());
  973. }
  974. /**
  975. * @requires extension intl
  976. */
  977. public function testIntlLocale()
  978. {
  979. $request = new Request();
  980. $request->setDefaultLocale('fr');
  981. $this->assertEquals('fr', $request->getLocale());
  982. $this->assertEquals('fr', \Locale::getDefault());
  983. $request->setLocale('en');
  984. $this->assertEquals('en', $request->getLocale());
  985. $this->assertEquals('en', \Locale::getDefault());
  986. $request->setDefaultLocale('de');
  987. $this->assertEquals('en', $request->getLocale());
  988. $this->assertEquals('en', \Locale::getDefault());
  989. }
  990. public function testGetCharsets()
  991. {
  992. $request = new Request();
  993. $this->assertEquals(array(), $request->getCharsets());
  994. $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6');
  995. $this->assertEquals(array(), $request->getCharsets()); // testing caching
  996. $request = new Request();
  997. $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6');
  998. $this->assertEquals(array('ISO-8859-1', 'US-ASCII', 'UTF-8', 'ISO-10646-UCS-2'), $request->getCharsets());
  999. $request = new Request();
  1000. $request->headers->set('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7');
  1001. $this->assertEquals(array('ISO-8859-1', 'utf-8', '*'), $request->getCharsets());
  1002. }
  1003. public function testGetEncodings()
  1004. {
  1005. $request = new Request();
  1006. $this->assertEquals(array(), $request->getEncodings());
  1007. $request->headers->set('Accept-Encoding', 'gzip,deflate,sdch');
  1008. $this->assertEquals(array(), $request->getEncodings()); // testing caching
  1009. $request = new Request();
  1010. $request->headers->set('Accept-Encoding', 'gzip,deflate,sdch');
  1011. $this->assertEquals(array('gzip', 'deflate', 'sdch'), $request->getEncodings());
  1012. $request = new Request();
  1013. $request->headers->set('Accept-Encoding', 'gzip;q=0.4,deflate;q=0.9,compress;q=0.7');
  1014. $this->assertEquals(array('deflate', 'compress', 'gzip'), $request->getEncodings());
  1015. }
  1016. public function testGetAcceptableContentTypes()
  1017. {
  1018. $request = new Request();
  1019. $this->assertEquals(array(), $request->getAcceptableContentTypes());
  1020. $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*');
  1021. $this->assertEquals(array(), $request->getAcceptableContentTypes()); // testing caching
  1022. $request = new Request();
  1023. $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*');
  1024. $this->assertEquals(array('application/vnd.wap.wmlscriptc', 'text/vnd.wap.wml', 'application/vnd.wap.xhtml+xml', 'application/xhtml+xml', 'text/html', 'multipart/mixed', '*/*'), $request->getAcceptableContentTypes());
  1025. }
  1026. public function testGetLanguages()
  1027. {
  1028. $request = new Request();
  1029. $this->assertEquals(array(), $request->getLanguages());
  1030. $request = new Request();
  1031. $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
  1032. $this->assertEquals(array('zh', 'en_US', 'en'), $request->getLanguages());
  1033. $this->assertEquals(array('zh', 'en_US', 'en'), $request->getLanguages());
  1034. $request = new Request();
  1035. $request->headers->set('Accept-language', 'zh, en-us; q=0.6, en; q=0.8');
  1036. $this->assertEquals(array('zh', 'en', 'en_US'), $request->getLanguages()); // Test out of order qvalues
  1037. $request = new Request();
  1038. $request->headers->set('Accept-language', 'zh, en, en-us');
  1039. $this->assertEquals(array('zh', 'en', 'en_US'), $request->getLanguages()); // Test equal weighting without qvalues
  1040. $request = new Request();
  1041. $request->headers->set('Accept-language', 'zh; q=0.6, en, en-us; q=0.6');
  1042. $this->assertEquals(array('en', 'zh', 'en_US'), $request->getLanguages()); // Test equal weighting with qvalues
  1043. $request = new Request();
  1044. $request->headers->set('Accept-language', 'zh, i-cherokee; q=0.6');
  1045. $this->assertEquals(array('zh', 'cherokee'), $request->getLanguages());
  1046. }
  1047. public function testGetRequestFormat()
  1048. {
  1049. $request = new Request();
  1050. $this->assertEquals('html', $request->getRequestFormat());
  1051. $request = new Request();
  1052. $this->assertNull($request->getRequestFormat(null));
  1053. $request = new Request();
  1054. $this->assertNull($request->setRequestFormat('foo'));
  1055. $this->assertEquals('foo', $request->getRequestFormat(null));
  1056. }
  1057. public function testHasSession()
  1058. {
  1059. $request = new Request();
  1060. $this->assertFalse($request->hasSession());
  1061. $request->setSession(new Session(new MockArraySessionStorage()));
  1062. $this->assertTrue($request->hasSession());
  1063. }
  1064. public function testGetSession()
  1065. {
  1066. $request = new Request();
  1067. $request->setSession(new Session(new MockArraySessionStorage()));
  1068. $this->assertTrue($request->hasSession());
  1069. $session = $request->getSession();
  1070. $this->assertObjectHasAttribute('storage', $session);
  1071. $this->assertObjectHasAttribute('flashName', $session);
  1072. $this->assertObjectHasAttribute('attributeName', $session);
  1073. }
  1074. public function testHasPreviousSession()
  1075. {
  1076. $request = new Request();
  1077. $this->assertFalse($request->hasPreviousSession());
  1078. $request->cookies->set('MOCKSESSID', 'foo');
  1079. $this->assertFalse($request->hasPreviousSession());
  1080. $request->setSession(new Session(new MockArraySessionStorage()));
  1081. $this->assertTrue($request->hasPreviousSession());
  1082. }
  1083. public function testToString()
  1084. {
  1085. $request = new Request();
  1086. $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6');
  1087. $this->assertContains('Accept-Language: zh, en-us; q=0.8, en; q=0.6', $request->__toString());
  1088. }
  1089. public function testIsMethod()
  1090. {
  1091. $request = new Request();
  1092. $request->setMethod('POST');
  1093. $this->assertTrue($request->isMethod('POST'));
  1094. $this->assertTrue($request->isMethod('post'));
  1095. $this->assertFalse($request->isMethod('GET'));
  1096. $this->assertFalse($request->isMethod('get'));
  1097. $request->setMethod('GET');
  1098. $this->assertTrue($request->isMethod('GET'));
  1099. $this->assertTrue($request->isMethod('get'));
  1100. $this->assertFalse($request->isMethod('POST'));
  1101. $this->assertFalse($request->isMethod('post'));
  1102. }
  1103. /**
  1104. * @dataProvider getBaseUrlData
  1105. */
  1106. public function testGetBaseUrl($uri, $server, $expectedBaseUrl, $expectedPathInfo)
  1107. {
  1108. $request = Request::create($uri, 'GET', array(), array(), array(), $server);
  1109. $this->assertSame($expectedBaseUrl, $request->getBaseUrl(), 'baseUrl');
  1110. $this->assertSame($expectedPathInfo, $request->getPathInfo(), 'pathInfo');
  1111. }
  1112. public function getBaseUrlData()
  1113. {
  1114. return array(
  1115. array(
  1116. '/fruit/strawberry/1234index.php/blah',
  1117. array(
  1118. 'SCRIPT_FILENAME' => 'E:/Sites/cc-new/public_html/fruit/index.php',
  1119. 'SCRIPT_NAME' => '/fruit/index.php',
  1120. 'PHP_SELF' => '/fruit/index.php',
  1121. ),
  1122. '/fruit',
  1123. '/strawberry/1234index.php/blah',
  1124. ),
  1125. array(
  1126. '/fruit/strawberry/1234index.php/blah',
  1127. array(
  1128. 'SCRIPT_FILENAME' => 'E:/Sites/cc-new/public_html/index.php',
  1129. 'SCRIPT_NAME' => '/index.php',
  1130. 'PHP_SELF' => '/index.php',
  1131. ),
  1132. '',
  1133. '/fruit/strawberry/1234index.php/blah',
  1134. ),
  1135. array(
  1136. '/foo%20bar/',
  1137. array(
  1138. 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
  1139. 'SCRIPT_NAME' => '/foo bar/app.php',
  1140. 'PHP_SELF' => '/foo bar/app.php',
  1141. ),
  1142. '/foo%20bar',
  1143. '/',
  1144. ),
  1145. array(
  1146. '/foo%20bar/home',
  1147. array(
  1148. 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
  1149. 'SCRIPT_NAME' => '/foo bar/app.php',
  1150. 'PHP_SELF' => '/foo bar/app.php',
  1151. ),
  1152. '/foo%20bar',
  1153. '/home',
  1154. ),
  1155. array(
  1156. '/foo%20bar/app.php/home',
  1157. array(
  1158. 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
  1159. 'SCRIPT_NAME' => '/foo bar/app.php',
  1160. 'PHP_SELF' => '/foo bar/app.php',
  1161. ),
  1162. '/foo%20bar/app.php',
  1163. '/home',
  1164. ),
  1165. array(
  1166. '/foo%20bar/app.php/home%3Dbaz',
  1167. array(
  1168. 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php',
  1169. 'SCRIPT_NAME' => '/foo bar/app.php',
  1170. 'PHP_SELF' => '/foo bar/app.php',
  1171. ),
  1172. '/foo%20bar/app.php',
  1173. '/home%3Dbaz',
  1174. ),
  1175. array(
  1176. '/foo/bar+baz',
  1177. array(
  1178. 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo/app.php',
  1179. 'SCRIPT_NAME' => '/foo/app.php',
  1180. 'PHP_SELF' => '/foo/app.php',
  1181. ),
  1182. '/foo',
  1183. '/bar+baz',
  1184. ),
  1185. );
  1186. }
  1187. /**
  1188. * @dataProvider urlencodedStringPrefixData
  1189. */
  1190. public function testUrlencodedStringPrefix($string, $prefix, $expect)
  1191. {
  1192. $request = new Request();
  1193. $me = new \ReflectionMethod($request, 'getUrlencodedPrefix');
  1194. $me->setAccessible(true);
  1195. $this->assertSame($expect, $me->invoke($request, $string, $prefix));
  1196. }
  1197. public function urlencodedStringPrefixData()
  1198. {
  1199. return array(
  1200. array('foo', 'foo', 'foo'),
  1201. array('fo%6f', 'foo', 'fo%6f'),
  1202. array('foo/bar', 'foo', 'foo'),
  1203. array('fo%6f/bar', 'foo', 'fo%6f'),
  1204. array('f%6f%6f/bar', 'foo', 'f%6f%6f'),
  1205. array('%66%6F%6F/bar', 'foo', '%66%6F%6F'),
  1206. array('fo+o/bar', 'fo+o', 'fo+o'),
  1207. array('fo%2Bo/bar', 'fo+o', 'fo%2Bo'),
  1208. );
  1209. }
  1210. private function disableHttpMethodParameterOverride()
  1211. {
  1212. $class = new \ReflectionClass('Symfony\\Component\\HttpFoundation\\Request');
  1213. $property = $class->getProperty('httpMethodParameterOverride');
  1214. $property->setAccessible(true);
  1215. $property->setValue(false);
  1216. }
  1217. private function getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies)
  1218. {
  1219. $request = new Request();
  1220. $server = array('REMOTE_ADDR' => $remoteAddr);
  1221. if (null !== $httpForwardedFor) {
  1222. $server['HTTP_X_FORWARDED_FOR'] = $httpForwardedFor;
  1223. }
  1224. if ($trustedProxies) {
  1225. Request::setTrustedProxies($trustedProxies);
  1226. }
  1227. $request->initialize(array(), array(), array(), array(), array(), $server);
  1228. return $request;
  1229. }
  1230. private function getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies)
  1231. {
  1232. $request = new Request();
  1233. $server = array('REMOTE_ADDR' => $remoteAddr);
  1234. if (null !== $httpForwarded) {
  1235. $server['HTTP_FORWARDED'] = $httpForwarded;
  1236. }
  1237. if ($trustedProxies) {
  1238. Request::setTrustedProxies($trustedProxies);
  1239. }
  1240. $request->initialize(array(), array(), array(), array(), array(), $server);
  1241. return $request;
  1242. }
  1243. public function testTrustedProxies()
  1244. {
  1245. $request = Request::create('http://example.com/');
  1246. $request->server->set('REMOTE_ADDR', '3.3.3.3');
  1247. $request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2');
  1248. $request->headers->set('X_FORWARDED_HOST', 'foo.example.com, real.example.com:8080');
  1249. $request->headers->set('X_FORWARDED_PROTO', 'https');
  1250. $request->headers->set('X_FORWARDED_PORT', 443);
  1251. $request->headers->set('X_MY_FOR', '3.3.3.3, 4.4.4.4');
  1252. $request->headers->set('X_MY_HOST', 'my.example.com');
  1253. $request->headers->set('X_MY_PROTO', 'http');
  1254. $request->headers->set('X_MY_PORT', 81);
  1255. // no trusted proxies
  1256. $this->assertEquals('3.3.3.3', $request->getClientIp());
  1257. $this->assertEquals('example.com', $request->getHost());
  1258. $this->assertEquals(80, $request->getPort());
  1259. $this->assertFalse($request->isSecure());
  1260. // disabling proxy trusting
  1261. Request::setTrustedProxies(array());
  1262. $this->assertEquals('3.3.3.3', $request->getClientIp());
  1263. $this->assertEquals('example.com', $request->getHost());
  1264. $this->assertEquals(80, $request->getPort());
  1265. $this->assertFalse($request->isSecure());
  1266. // trusted proxy via setTrustedProxies()
  1267. Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'));
  1268. $this->assertEquals('1.1.1.1', $request->getClientIp());
  1269. $this->assertEquals('real.example.com', $request->getHost());
  1270. $this->assertEquals(443, $request->getPort());
  1271. $this->assertTrue($request->isSecure());
  1272. // trusted proxy via setTrustedProxies()
  1273. Request::setTrustedProxies(array('3.3.3.4', '2.2.2.2'));
  1274. $this->assertEquals('3.3.3.3', $request->getClientIp());
  1275. $this->assertEquals('example.com', $request->getHost());
  1276. $this->assertEquals(80, $request->getPort());
  1277. $this->assertFalse($request->isSecure());
  1278. // check various X_FORWARDED_PROTO header values
  1279. Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'));
  1280. $request->headers->set('X_FORWARDED_PROTO', 'ssl');
  1281. $this->assertTrue($request->isSecure());
  1282. $request->headers->set('X_FORWARDED_PROTO', 'https, http');
  1283. $this->assertTrue($request->isSecure());
  1284. // custom header names
  1285. Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_MY_FOR');
  1286. Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_MY_HOST');
  1287. Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_MY_PORT');
  1288. Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_MY_PROTO');
  1289. $this->assertEquals('4.4.4.4', $request->getClientIp());
  1290. $this->assertEquals('my.example.com', $request->getHost());
  1291. $this->assertEquals(81, $request->getPort());
  1292. $this->assertFalse($request->isSecure());
  1293. // disabling via empty header names
  1294. Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, null);
  1295. Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, null);
  1296. Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, null);
  1297. Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, null);
  1298. $this->assertEquals('3.3.3.3', $request->getClientIp());
  1299. $this->assertEquals('example.com', $request->getHost());
  1300. $this->assertEquals(80, $request->getPort());
  1301. $this->assertFalse($request->isSecure());
  1302. // reset
  1303. Request::setTrustedProxies(array());
  1304. Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR');
  1305. Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST');
  1306. Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT');
  1307. Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO');
  1308. }
  1309. /**
  1310. * @expectedException \InvalidArgumentException
  1311. */
  1312. public function testSetTrustedProxiesInvalidHeaderName()
  1313. {
  1314. Request::create('http://example.com/');
  1315. Request::setTrustedHeaderName('bogus name', 'X_MY_FOR');
  1316. }
  1317. /**
  1318. * @expectedException \InvalidArgumentException
  1319. */
  1320. public function testGetTrustedProxiesInvalidHeaderName()
  1321. {
  1322. Request::create('http://example.com/');
  1323. Request::getTrustedHeaderName('bogus name');
  1324. }
  1325. /**
  1326. * @dataProvider iisRequestUriProvider
  1327. */
  1328. public function testIISRequestUri($headers, $server, $expectedRequestUri)
  1329. {
  1330. $request = new Request();
  1331. $request->headers->replace($headers);
  1332. $request->server->replace($server);
  1333. $this->assertEquals($expectedRequestUri, $request->getRequestUri(), '->getRequestUri() is correct');
  1334. $subRequestUri = '/bar/foo';
  1335. $subRequest = Request::create($subRequestUri, 'get', array(), array(), array(), $request->server->all());
  1336. $this->assertEquals($subRequestUri, $subRequest->getRequestUri(), '->getRequestUri() is correct in sub request');
  1337. }
  1338. public function iisRequestUriProvider()
  1339. {
  1340. return array(
  1341. array(
  1342. array(
  1343. 'X_ORIGINAL_URL' => '/foo/bar',
  1344. ),
  1345. array(),
  1346. '/foo/bar',
  1347. ),
  1348. array(
  1349. array(
  1350. 'X_REWRITE_URL' => '/foo/bar',
  1351. ),
  1352. array(),
  1353. '/foo/bar',
  1354. ),
  1355. array(
  1356. array(),
  1357. array(
  1358. 'IIS_WasUrlRewritten' => '1',
  1359. 'UNENCODED_URL' => '/foo/bar',
  1360. ),
  1361. '/foo/bar',
  1362. ),
  1363. array(
  1364. array(
  1365. 'X_ORIGINAL_URL' => '/foo/bar',
  1366. ),
  1367. array(
  1368. 'HTTP_X_ORIGINAL_URL' => '/foo/bar',
  1369. ),
  1370. '/foo/bar',
  1371. ),
  1372. array(
  1373. array(
  1374. 'X_ORIGINAL_URL' => '/foo/bar',
  1375. ),
  1376. array(
  1377. 'IIS_WasUrlRewritten' => '1',
  1378. 'UNENCODED_URL' => '/foo/bar',
  1379. ),
  1380. '/foo/bar',
  1381. ),
  1382. array(
  1383. array(
  1384. 'X_ORIGINAL_URL' => '/foo/bar',
  1385. ),
  1386. array(
  1387. 'HTTP_X_ORIGINAL_URL' => '/foo/bar',
  1388. 'IIS_WasUrlRewritten' => '1',
  1389. 'UNENCODED_URL' => '/foo/bar',
  1390. ),
  1391. '/foo/bar',
  1392. ),
  1393. array(
  1394. array(),
  1395. array(
  1396. 'ORIG_PATH_INFO' => '/foo/bar',
  1397. ),
  1398. '/foo/bar',
  1399. ),
  1400. array(
  1401. array(),
  1402. array(
  1403. 'ORIG_PATH_INFO' => '/foo/bar',
  1404. 'QUERY_STRING' => 'foo=bar',
  1405. ),
  1406. '/foo/bar?foo=bar',
  1407. ),
  1408. );
  1409. }
  1410. public function testTrustedHosts()
  1411. {
  1412. // create a request
  1413. $request = Request::create('/');
  1414. // no trusted host set -> no host check
  1415. $request->headers->set('host', 'evil.com');
  1416. $this->assertEquals('evil.com', $request->getHost());
  1417. // add a trusted domain and all its subdomains
  1418. Request::setTrustedHosts(array('^([a-z]{9}\.)?trusted\.com$'));
  1419. // untrusted host
  1420. $request->headers->set('host', 'evil.com');
  1421. try {
  1422. $request->getHost();
  1423. $this->fail('Request::getHost() should throw an exception when host is not trusted.');
  1424. } catch (\UnexpectedValueException $e) {
  1425. $this->assertEquals('Untrusted Host "evil.com"', $e->getMessage());
  1426. }
  1427. // trusted hosts
  1428. $request->headers->set('host', 'trusted.com');
  1429. $this->assertEquals('trusted.com', $request->getHost());
  1430. $this->assertEquals(80, $request->getPort());
  1431. $request->server->set('HTTPS', true);
  1432. $request->headers->set('host', 'trusted.com');
  1433. $this->assertEquals('trusted.com', $request->getHost());
  1434. $this->assertEquals(443, $request->getPort());
  1435. $request->server->set('HTTPS', false);
  1436. $request->headers->set('host', 'trusted.com:8000');
  1437. $this->assertEquals('trusted.com', $request->getHost());
  1438. $this->assertEquals(8000, $request->getPort());
  1439. $request->headers->set('host', 'subdomain.trusted.com');
  1440. $this->assertEquals('subdomain.trusted.com', $request->getHost());
  1441. // reset request for following tests
  1442. Request::setTrustedHosts(array());
  1443. }
  1444. public function testFactory()
  1445. {
  1446. Request::setFactory(function (array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null) {
  1447. return new NewRequest();
  1448. });
  1449. $this->assertEquals('foo', Request::create('/')->getFoo());
  1450. Request::setFactory(null);
  1451. }
  1452. /**
  1453. * @dataProvider getLongHostNames
  1454. */
  1455. public function testVeryLongHosts($host)
  1456. {
  1457. $start = microtime(true);
  1458. $request = Request::create('/');
  1459. $request->headers->set('host', $host);
  1460. $this->assertEquals($host, $request->getHost());
  1461. $this->assertLessThan(3, microtime(true) - $start);
  1462. }
  1463. /**
  1464. * @dataProvider getHostValidities
  1465. */
  1466. public function testHostValidity($host, $isValid, $expectedHost = null, $expectedPort = null)
  1467. {
  1468. $request = Request::create('/');
  1469. $request->headers->set('host', $host);
  1470. if ($isValid) {
  1471. $this->assertSame($expectedHost ?: $host, $request->getHost());
  1472. if ($expectedPort) {
  1473. $this->assertSame($expectedPort, $request->getPort());
  1474. }
  1475. } else {
  1476. $this->setExpectedException('UnexpectedValueException', 'Invalid Host');
  1477. $request->getHost();
  1478. }
  1479. }
  1480. public function getHostValidities()
  1481. {
  1482. return array(
  1483. array('.a', false),
  1484. array('a..', false),
  1485. array('a.', true),
  1486. array("\xE9", false),
  1487. array('[::1]', true),
  1488. array('[::1]:80', true, '[::1]', 80),
  1489. array(str_repeat('.', 101), false),
  1490. );
  1491. }
  1492. public function getLongHostNames()
  1493. {
  1494. return array(
  1495. array('a'.str_repeat('.a', 40000)),
  1496. array(str_repeat(':', 101)),
  1497. );
  1498. }
  1499. }
  1500. class RequestContentProxy extends Request
  1501. {
  1502. public function getContent($asResource = false)
  1503. {
  1504. return http_build_query(array('_method' => 'PUT', 'content' => 'mycontent'));
  1505. }
  1506. }
  1507. class NewRequest extends Request
  1508. {
  1509. public function getFoo()
  1510. {
  1511. return 'foo';
  1512. }
  1513. }