ServerRequestTest.php 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP(tm) Project
  13. * @since 2.0.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\Http;
  17. use BadMethodCallException;
  18. use Cake\Core\Configure;
  19. use Cake\Http\Cookie\Cookie;
  20. use Cake\Http\Cookie\CookieCollection;
  21. use Cake\Http\Exception\MethodNotAllowedException;
  22. use Cake\Http\FlashMessage;
  23. use Cake\Http\ServerRequest;
  24. use Cake\Http\Session;
  25. use Cake\TestSuite\TestCase;
  26. use InvalidArgumentException;
  27. use Laminas\Diactoros\UploadedFile;
  28. use Laminas\Diactoros\Uri;
  29. /**
  30. * ServerRequest Test
  31. */
  32. class ServerRequestTest extends TestCase
  33. {
  34. /**
  35. * Test custom detector with extra arguments.
  36. */
  37. public function testCustomArgsDetector(): void
  38. {
  39. $request = new ServerRequest();
  40. $request->addDetector('controller', function ($request, $name) {
  41. return $request->getParam('controller') === $name;
  42. });
  43. $request = $request->withParam('controller', 'cake');
  44. $this->assertTrue($request->is('controller', 'cake'));
  45. $this->assertFalse($request->is('controller', 'nonExistingController'));
  46. $this->assertTrue($request->isController('cake'));
  47. $this->assertFalse($request->isController('nonExistingController'));
  48. }
  49. /**
  50. * Test the header detector.
  51. */
  52. public function testHeaderDetector(): void
  53. {
  54. $request = new ServerRequest();
  55. $request->addDetector('host', ['header' => ['host' => 'cakephp.org']]);
  56. $request = $request->withEnv('HTTP_HOST', 'cakephp.org');
  57. $this->assertTrue($request->is('host'));
  58. $request = $request->withEnv('HTTP_HOST', 'php.net');
  59. $this->assertFalse($request->is('host'));
  60. }
  61. /**
  62. * Test the accept header detector.
  63. */
  64. public function testExtensionDetector(): void
  65. {
  66. $request = new ServerRequest();
  67. $request = $request->withParam('_ext', 'json');
  68. $this->assertTrue($request->is('json'));
  69. $request = new ServerRequest();
  70. $request = $request->withParam('_ext', 'xml');
  71. $this->assertFalse($request->is('json'));
  72. }
  73. /**
  74. * Test the accept header detector.
  75. */
  76. public function testAcceptHeaderDetector(): void
  77. {
  78. $request = new ServerRequest();
  79. $request = $request->withEnv('HTTP_ACCEPT', 'application/json, text/plain, */*');
  80. $this->assertTrue($request->is('json'));
  81. $request = new ServerRequest();
  82. $request = $request->withEnv('HTTP_ACCEPT', 'text/plain, */*');
  83. $this->assertFalse($request->is('json'));
  84. }
  85. public function testConstructor(): void
  86. {
  87. $request = new ServerRequest();
  88. $this->assertInstanceOf(FlashMessage::class, $request->getAttribute('flash'));
  89. }
  90. /**
  91. * Test construction with query data
  92. */
  93. public function testConstructionQueryData(): void
  94. {
  95. $data = [
  96. 'query' => [
  97. 'one' => 'param',
  98. 'two' => 'banana',
  99. ],
  100. 'url' => 'some/path',
  101. ];
  102. $request = new ServerRequest($data);
  103. $this->assertSame('param', $request->getQuery('one'));
  104. $this->assertEquals($data['query'], $request->getQueryParams());
  105. $this->assertSame('/some/path', $request->getRequestTarget());
  106. }
  107. /**
  108. * Test constructing with a string url.
  109. */
  110. public function testConstructStringUrlIgnoreServer(): void
  111. {
  112. $request = new ServerRequest([
  113. 'url' => '/articles/view/1',
  114. 'environment' => ['REQUEST_URI' => '/some/other/path'],
  115. ]);
  116. $this->assertSame('/articles/view/1', $request->getUri()->getPath());
  117. $request = new ServerRequest(['url' => '/']);
  118. $this->assertSame('/', $request->getUri()->getPath());
  119. }
  120. /**
  121. * Test that querystring args provided in the URL string are parsed.
  122. */
  123. public function testQueryStringParsingFromInputUrl(): void
  124. {
  125. $request = new ServerRequest(['url' => 'some/path?one=something&two=else']);
  126. $expected = ['one' => 'something', 'two' => 'else'];
  127. $this->assertEquals($expected, $request->getQueryParams());
  128. $this->assertSame('/some/path', $request->getUri()->getPath());
  129. $this->assertSame('one=something&two=else', $request->getUri()->getQuery());
  130. }
  131. /**
  132. * Test that querystrings are handled correctly.
  133. */
  134. public function testQueryStringAndNamedParams(): void
  135. {
  136. $config = ['environment' => ['REQUEST_URI' => '/tasks/index?ts=123456']];
  137. $request = new ServerRequest($config);
  138. $this->assertSame('/tasks/index', $request->getRequestTarget());
  139. $config = ['environment' => ['REQUEST_URI' => '/some/path?url=http://cakephp.org']];
  140. $request = new ServerRequest($config);
  141. $this->assertSame('/some/path', $request->getRequestTarget());
  142. $config = ['environment' => [
  143. 'REQUEST_URI' => Configure::read('App.fullBaseUrl') . '/other/path?url=http://cakephp.org',
  144. ]];
  145. $request = new ServerRequest($config);
  146. $this->assertSame('/other/path', $request->getRequestTarget());
  147. }
  148. /**
  149. * Test that URL in path is handled correctly.
  150. */
  151. public function testUrlInPath(): void
  152. {
  153. $config = ['environment' => ['REQUEST_URI' => '/jump/http://cakephp.org']];
  154. $request = new ServerRequest($config);
  155. $this->assertSame('/jump/http://cakephp.org', $request->getRequestTarget());
  156. $config = ['environment' => [
  157. 'REQUEST_URI' => Configure::read('App.fullBaseUrl') . '/jump/http://cakephp.org',
  158. ]];
  159. $request = new ServerRequest($config);
  160. $this->assertSame('/jump/http://cakephp.org', $request->getRequestTarget());
  161. }
  162. /**
  163. * Test getPath().
  164. */
  165. public function testGetPath(): void
  166. {
  167. $request = new ServerRequest(['url' => '']);
  168. $this->assertSame('/', $request->getPath());
  169. $request = new ServerRequest(['url' => 'some/path?one=something&two=else']);
  170. $this->assertSame('/some/path', $request->getPath());
  171. $request = $request->withRequestTarget('/foo/bar?x=y');
  172. $this->assertSame('/foo/bar', $request->getPath());
  173. }
  174. /**
  175. * Test parsing POST data into the object.
  176. */
  177. public function testPostParsing(): void
  178. {
  179. $post = [
  180. 'Article' => ['title'],
  181. ];
  182. $request = new ServerRequest(compact('post'));
  183. $this->assertEquals($post, $request->getData());
  184. $post = ['one' => 1, 'two' => 'three'];
  185. $request = new ServerRequest(compact('post'));
  186. $this->assertEquals($post, $request->getData());
  187. $post = [
  188. 'Article' => ['title' => 'Testing'],
  189. 'action' => 'update',
  190. ];
  191. $request = new ServerRequest(compact('post'));
  192. $this->assertEquals($post, $request->getData());
  193. }
  194. /**
  195. * Test that the constructor uses uploaded file objects
  196. * if they are present. This could happen in test scenarios.
  197. */
  198. public function testFilesObject(): void
  199. {
  200. $file = new UploadedFile(
  201. __FILE__,
  202. 123,
  203. UPLOAD_ERR_OK,
  204. 'test.php',
  205. 'text/plain'
  206. );
  207. $request = new ServerRequest(['files' => ['avatar' => $file]]);
  208. $this->assertSame(['avatar' => $file], $request->getUploadedFiles());
  209. }
  210. /**
  211. * Test passing an empty files list.
  212. */
  213. public function testFilesWithEmptyList(): void
  214. {
  215. $request = new ServerRequest([
  216. 'files' => [],
  217. ]);
  218. $this->assertEmpty($request->getData());
  219. $this->assertEmpty($request->getUploadedFiles());
  220. }
  221. /**
  222. * Test replacing files.
  223. */
  224. public function testWithUploadedFiles(): void
  225. {
  226. $file = new UploadedFile(
  227. __FILE__,
  228. 123,
  229. UPLOAD_ERR_OK,
  230. 'test.php',
  231. 'text/plain'
  232. );
  233. $request = new ServerRequest();
  234. $new = $request->withUploadedFiles(['picture' => $file]);
  235. $this->assertSame([], $request->getUploadedFiles());
  236. $this->assertNotSame($new, $request);
  237. $this->assertSame(['picture' => $file], $new->getUploadedFiles());
  238. }
  239. /**
  240. * Test getting a single file
  241. */
  242. public function testGetUploadedFile(): void
  243. {
  244. $file = new UploadedFile(
  245. __FILE__,
  246. 123,
  247. UPLOAD_ERR_OK,
  248. 'test.php',
  249. 'text/plain'
  250. );
  251. $request = new ServerRequest();
  252. $new = $request->withUploadedFiles(['picture' => $file]);
  253. $this->assertNull($new->getUploadedFile(''));
  254. $this->assertSame($file, $new->getUploadedFile('picture'));
  255. $new = $request->withUploadedFiles([
  256. 'pictures' => [
  257. [
  258. 'image' => $file,
  259. ],
  260. ],
  261. ]);
  262. $this->assertNull($new->getUploadedFile('pictures'));
  263. $this->assertNull($new->getUploadedFile('pictures.0'));
  264. $this->assertNull($new->getUploadedFile('pictures.1'));
  265. $this->assertSame($file, $new->getUploadedFile('pictures.0.image'));
  266. }
  267. /**
  268. * Test replacing files with an invalid file
  269. */
  270. public function testWithUploadedFilesInvalidFile(): void
  271. {
  272. $this->expectException(InvalidArgumentException::class);
  273. $this->expectExceptionMessage('Invalid file at \'avatar\'');
  274. $request = new ServerRequest();
  275. $request->withUploadedFiles(['avatar' => 'not a file']);
  276. }
  277. /**
  278. * Test replacing files with an invalid file
  279. */
  280. public function testWithUploadedFilesInvalidFileNested(): void
  281. {
  282. $this->expectException(InvalidArgumentException::class);
  283. $this->expectExceptionMessage('Invalid file at \'user.avatar\'');
  284. $request = new ServerRequest();
  285. $request->withUploadedFiles(['user' => ['avatar' => 'not a file']]);
  286. }
  287. /**
  288. * Test the clientIp method.
  289. */
  290. public function testClientIp(): void
  291. {
  292. $request = new ServerRequest(['environment' => [
  293. 'HTTP_X_FORWARDED_FOR' => '192.168.1.5, 10.0.1.1, proxy.com, real.ip',
  294. 'HTTP_X_REAL_IP' => '192.168.1.1',
  295. 'HTTP_CLIENT_IP' => '192.168.1.2',
  296. 'REMOTE_ADDR' => '192.168.1.3',
  297. ]]);
  298. $request->trustProxy = true;
  299. $this->assertSame('real.ip', $request->clientIp());
  300. $request = $request->withEnv('HTTP_X_FORWARDED_FOR', '');
  301. $this->assertSame('192.168.1.1', $request->clientIp());
  302. $request = $request->withEnv('HTTP_X_REAL_IP', '');
  303. $this->assertSame('192.168.1.2', $request->clientIp());
  304. $request->trustProxy = false;
  305. $this->assertSame('192.168.1.3', $request->clientIp());
  306. $request = $request->withEnv('HTTP_X_FORWARDED_FOR', '');
  307. $this->assertSame('192.168.1.3', $request->clientIp());
  308. $request = $request->withEnv('HTTP_CLIENT_IP', '');
  309. $this->assertSame('192.168.1.3', $request->clientIp());
  310. }
  311. /**
  312. * test clientIp method with trusted proxies
  313. */
  314. public function testClientIpWithTrustedProxies(): void
  315. {
  316. $request = new ServerRequest(['environment' => [
  317. 'HTTP_X_FORWARDED_FOR' => 'real.ip, 192.168.1.0, 192.168.1.2, 192.168.1.3',
  318. 'HTTP_X_REAL_IP' => '192.168.1.1',
  319. 'HTTP_CLIENT_IP' => '192.168.1.2',
  320. 'REMOTE_ADDR' => '192.168.1.4',
  321. ]]);
  322. $request->setTrustedProxies([
  323. '192.168.1.0',
  324. '192.168.1.1',
  325. '192.168.1.2',
  326. '192.168.1.3',
  327. ]);
  328. $this->assertSame('real.ip', $request->clientIp());
  329. $request = $request->withEnv(
  330. 'HTTP_X_FORWARDED_FOR',
  331. 'spoof.fake.ip, real.ip, 192.168.1.0, 192.168.1.2, 192.168.1.3'
  332. );
  333. $this->assertSame('192.168.1.3', $request->clientIp());
  334. $request = $request->withEnv('HTTP_X_FORWARDED_FOR', '');
  335. $this->assertSame('192.168.1.1', $request->clientIp());
  336. $request->trustProxy = false;
  337. $this->assertSame('192.168.1.4', $request->clientIp());
  338. }
  339. /**
  340. * Test the referrer function.
  341. */
  342. public function testReferer(): void
  343. {
  344. $request = new ServerRequest(['webroot' => '/']);
  345. $request = $request->withEnv('HTTP_REFERER', 'http://cakephp.org');
  346. $result = $request->referer(false);
  347. $this->assertSame('http://cakephp.org', $result);
  348. $request = $request->withEnv('HTTP_REFERER', '');
  349. $result = $request->referer(true);
  350. $this->assertNull($result);
  351. $result = $request->referer(false);
  352. $this->assertNull($result);
  353. $request = $request->withEnv('HTTP_REFERER', Configure::read('App.fullBaseUrl') . '/some/path');
  354. $result = $request->referer();
  355. $this->assertSame('/some/path', $result);
  356. $request = $request->withEnv('HTTP_REFERER', Configure::read('App.fullBaseUrl') . '///cakephp.org/');
  357. $result = $request->referer();
  358. $this->assertSame('/', $result); // Avoid returning scheme-relative URLs.
  359. $request = $request->withEnv('HTTP_REFERER', Configure::read('App.fullBaseUrl') . '/0');
  360. $result = $request->referer();
  361. $this->assertSame('/0', $result);
  362. $request = $request->withEnv('HTTP_REFERER', Configure::read('App.fullBaseUrl') . '/');
  363. $result = $request->referer();
  364. $this->assertSame('/', $result);
  365. $request = $request->withEnv('HTTP_REFERER', Configure::read('App.fullBaseUrl') . '/some/path');
  366. $result = $request->referer(false);
  367. $this->assertSame(Configure::read('App.fullBaseUrl') . '/some/path', $result);
  368. }
  369. /**
  370. * Test referer() with a base path that duplicates the
  371. * first segment.
  372. */
  373. public function testRefererBasePath(): void
  374. {
  375. $request = new ServerRequest([
  376. 'url' => '/waves/users/login',
  377. 'webroot' => '/waves/',
  378. 'base' => '/waves',
  379. ]);
  380. $request = $request->withEnv('HTTP_REFERER', Configure::read('App.fullBaseUrl') . '/waves/waves/add');
  381. $result = $request->referer();
  382. $this->assertSame('/waves/add', $result);
  383. }
  384. /**
  385. * test the simple uses of is()
  386. */
  387. public function testIsHttpMethods(): void
  388. {
  389. $request = new ServerRequest();
  390. $this->assertFalse($request->is('undefined-behavior'));
  391. $request = $request->withEnv('REQUEST_METHOD', 'GET');
  392. $this->assertTrue($request->is('get'));
  393. $request = $request->withEnv('REQUEST_METHOD', 'POST');
  394. $this->assertTrue($request->is('POST'));
  395. $request = $request->withEnv('REQUEST_METHOD', 'PUT');
  396. $this->assertTrue($request->is('put'));
  397. $this->assertFalse($request->is('get'));
  398. $request = $request->withEnv('REQUEST_METHOD', 'DELETE');
  399. $this->assertTrue($request->is('delete'));
  400. $this->assertTrue($request->isDelete());
  401. $request = $request->withEnv('REQUEST_METHOD', 'delete');
  402. $this->assertFalse($request->is('delete'));
  403. }
  404. /**
  405. * Test is() with JSON and XML.
  406. */
  407. public function testIsJsonAndXml(): void
  408. {
  409. $request = new ServerRequest();
  410. $request = $request->withEnv('HTTP_ACCEPT', 'application/json, text/plain, */*');
  411. $this->assertTrue($request->is('json'));
  412. $request = new ServerRequest();
  413. $request = $request->withEnv('HTTP_ACCEPT', 'application/xml, text/plain, */*');
  414. $this->assertTrue($request->is('xml'));
  415. $request = new ServerRequest();
  416. $request = $request->withEnv('HTTP_ACCEPT', 'text/xml, */*');
  417. $this->assertTrue($request->is('xml'));
  418. }
  419. /**
  420. * Test is() with multiple types.
  421. */
  422. public function testIsMultiple(): void
  423. {
  424. $request = new ServerRequest();
  425. $request = $request->withEnv('REQUEST_METHOD', 'GET');
  426. $this->assertTrue($request->is(['get', 'post']));
  427. $request = $request->withEnv('REQUEST_METHOD', 'POST');
  428. $this->assertTrue($request->is(['get', 'post']));
  429. $request = $request->withEnv('REQUEST_METHOD', 'PUT');
  430. $this->assertFalse($request->is(['get', 'post']));
  431. }
  432. /**
  433. * Test isAll()
  434. */
  435. public function testIsAll(): void
  436. {
  437. $request = new ServerRequest();
  438. $request = $request->withEnv('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
  439. $request = $request->withEnv('REQUEST_METHOD', 'GET');
  440. $this->assertTrue($request->isAll(['ajax', 'get']));
  441. $this->assertFalse($request->isAll(['post', 'get']));
  442. $this->assertFalse($request->isAll(['ajax', 'post']));
  443. }
  444. /**
  445. * Test getMethod()
  446. */
  447. public function testGetMethod(): void
  448. {
  449. $request = new ServerRequest([
  450. 'environment' => ['REQUEST_METHOD' => 'delete'],
  451. ]);
  452. $this->assertSame('delete', $request->getMethod());
  453. }
  454. /**
  455. * Test withMethod()
  456. */
  457. public function testWithMethod(): void
  458. {
  459. $request = new ServerRequest([
  460. 'environment' => ['REQUEST_METHOD' => 'delete'],
  461. ]);
  462. $new = $request->withMethod('put');
  463. $this->assertNotSame($new, $request);
  464. $this->assertSame('delete', $request->getMethod());
  465. $this->assertSame('put', $new->getMethod());
  466. }
  467. /**
  468. * Test withMethod() and invalid data
  469. */
  470. public function testWithMethodInvalid(): void
  471. {
  472. $this->expectException(InvalidArgumentException::class);
  473. $this->expectExceptionMessage('Unsupported HTTP method "no good" provided');
  474. $request = new ServerRequest([
  475. 'environment' => ['REQUEST_METHOD' => 'delete'],
  476. ]);
  477. $request->withMethod('no good');
  478. }
  479. /**
  480. * Test getProtocolVersion()
  481. */
  482. public function testGetProtocolVersion(): void
  483. {
  484. $request = new ServerRequest();
  485. $this->assertSame('1.1', $request->getProtocolVersion());
  486. // SERVER var.
  487. $request = new ServerRequest([
  488. 'environment' => ['SERVER_PROTOCOL' => 'HTTP/1.0'],
  489. ]);
  490. $this->assertSame('1.0', $request->getProtocolVersion());
  491. }
  492. /**
  493. * Test withProtocolVersion()
  494. */
  495. public function testWithProtocolVersion(): void
  496. {
  497. $request = new ServerRequest();
  498. $new = $request->withProtocolVersion('1.0');
  499. $this->assertNotSame($new, $request);
  500. $this->assertSame('1.1', $request->getProtocolVersion());
  501. $this->assertSame('1.0', $new->getProtocolVersion());
  502. }
  503. /**
  504. * Test withProtocolVersion() and invalid data
  505. */
  506. public function testWithProtocolVersionInvalid(): void
  507. {
  508. $this->expectException(InvalidArgumentException::class);
  509. $this->expectExceptionMessage('Unsupported protocol version \'no good\' provided');
  510. $request = new ServerRequest();
  511. $request->withProtocolVersion('no good');
  512. }
  513. /**
  514. * Test host retrieval.
  515. */
  516. public function testHost(): void
  517. {
  518. $request = new ServerRequest(['environment' => [
  519. 'HTTP_HOST' => 'localhost',
  520. 'HTTP_X_FORWARDED_HOST' => 'cakephp.org',
  521. ]]);
  522. $this->assertSame('localhost', $request->host());
  523. $request->trustProxy = true;
  524. $this->assertSame('cakephp.org', $request->host());
  525. }
  526. /**
  527. * test port retrieval.
  528. */
  529. public function testPort(): void
  530. {
  531. $request = new ServerRequest(['environment' => ['SERVER_PORT' => '80']]);
  532. $this->assertSame('80', $request->port());
  533. $request = $request->withEnv('SERVER_PORT', '443');
  534. $request = $request->withEnv('HTTP_X_FORWARDED_PORT', '80');
  535. $this->assertSame('443', $request->port());
  536. $request->trustProxy = true;
  537. $this->assertSame('80', $request->port());
  538. }
  539. /**
  540. * test domain retrieval.
  541. */
  542. public function testDomain(): void
  543. {
  544. $request = new ServerRequest(['environment' => ['HTTP_HOST' => 'something.example.com']]);
  545. $this->assertSame('example.com', $request->domain());
  546. $request = $request->withEnv('HTTP_HOST', 'something.example.co.uk');
  547. $this->assertSame('example.co.uk', $request->domain(2));
  548. }
  549. /**
  550. * Test scheme() method.
  551. */
  552. public function testScheme(): void
  553. {
  554. $request = new ServerRequest(['environment' => ['HTTPS' => 'on']]);
  555. $this->assertSame('https', $request->scheme());
  556. $request = $request->withEnv('HTTPS', '');
  557. $this->assertSame('http', $request->scheme());
  558. $request = $request->withEnv('HTTP_X_FORWARDED_PROTO', 'https');
  559. $request->trustProxy = true;
  560. $this->assertSame('https', $request->scheme());
  561. }
  562. /**
  563. * test getting subdomains for a host.
  564. */
  565. public function testSubdomain(): void
  566. {
  567. $request = new ServerRequest(['environment' => ['HTTP_HOST' => 'something.example.com']]);
  568. $this->assertEquals(['something'], $request->subdomains());
  569. $request = $request->withEnv('HTTP_HOST', 'www.something.example.com');
  570. $this->assertEquals(['www', 'something'], $request->subdomains());
  571. $request = $request->withEnv('HTTP_HOST', 'www.something.example.co.uk');
  572. $this->assertEquals(['www', 'something'], $request->subdomains(2));
  573. $request = $request->withEnv('HTTP_HOST', 'example.co.uk');
  574. $this->assertEquals([], $request->subdomains(2));
  575. }
  576. /**
  577. * Test AJAX, flash and friends
  578. */
  579. public function testisAjax(): void
  580. {
  581. $request = new ServerRequest();
  582. $request = $request->withEnv('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
  583. $this->assertTrue($request->is('ajax'));
  584. $request = $request->withEnv('HTTP_X_REQUESTED_WITH', 'XMLHTTPREQUEST');
  585. $this->assertFalse($request->is('ajax'));
  586. $this->assertFalse($request->isAjax());
  587. }
  588. /**
  589. * Test __call exceptions
  590. */
  591. public function testMagicCallExceptionOnUnknownMethod(): void
  592. {
  593. $this->expectException(BadMethodCallException::class);
  594. $request = new ServerRequest();
  595. $request->IamABanana();
  596. }
  597. /**
  598. * Test is(ssl)
  599. */
  600. public function testIsSsl(): void
  601. {
  602. $request = new ServerRequest();
  603. $request = $request->withEnv('HTTPS', 'on');
  604. $this->assertTrue($request->is('ssl'));
  605. $request = $request->withEnv('HTTPS', '1');
  606. $this->assertTrue($request->is('ssl'));
  607. $request = $request->withEnv('HTTPS', 'I am not empty');
  608. $this->assertFalse($request->is('ssl'));
  609. $request = $request->withEnv('HTTPS', 'off');
  610. $this->assertFalse($request->is('ssl'));
  611. $request = $request->withEnv('HTTPS', '');
  612. $this->assertFalse($request->is('ssl'));
  613. }
  614. /**
  615. * Test adding detectors and having them work.
  616. */
  617. public function testAddDetector(): void
  618. {
  619. $request = new ServerRequest();
  620. ServerRequest::addDetector('closure', function ($request) {
  621. return true;
  622. });
  623. $this->assertTrue($request->is('closure'));
  624. ServerRequest::addDetector('get', function ($request) {
  625. return $request->getEnv('REQUEST_METHOD') === 'GET';
  626. });
  627. $request = $request->withEnv('REQUEST_METHOD', 'GET');
  628. $this->assertTrue($request->is('get'));
  629. ServerRequest::addDetector('compare', ['env' => 'TEST_VAR', 'value' => 'something']);
  630. $request = $request->withEnv('TEST_VAR', 'something');
  631. $this->assertTrue($request->is('compare'), 'Value match failed.');
  632. $request = $request->withEnv('TEST_VAR', 'wrong');
  633. $this->assertFalse($request->is('compare'), 'Value mis-match failed.');
  634. ServerRequest::addDetector('compareCamelCase', ['env' => 'TEST_VAR', 'value' => 'foo']);
  635. $request = $request->withEnv('TEST_VAR', 'foo');
  636. $this->assertTrue($request->is('compareCamelCase'), 'Value match failed.');
  637. $this->assertTrue($request->is('comparecamelcase'), 'detectors should be case insensitive');
  638. $this->assertTrue($request->is('COMPARECAMELCASE'), 'detectors should be case insensitive');
  639. $request = $request->withEnv('TEST_VAR', 'not foo');
  640. $this->assertFalse($request->is('compareCamelCase'), 'Value match failed.');
  641. $this->assertFalse($request->is('comparecamelcase'), 'detectors should be case insensitive');
  642. $this->assertFalse($request->is('COMPARECAMELCASE'), 'detectors should be case insensitive');
  643. ServerRequest::addDetector('banana', ['env' => 'TEST_VAR', 'pattern' => '/^ban.*$/']);
  644. $request = $request->withEnv('TEST_VAR', 'banana');
  645. $this->assertTrue($request->isBanana());
  646. $request = $request->withEnv('TEST_VAR', 'wrong value');
  647. $this->assertFalse($request->isBanana());
  648. ServerRequest::addDetector('mobile', ['env' => 'HTTP_USER_AGENT', 'options' => ['Imagination']]);
  649. $request = $request->withEnv('HTTP_USER_AGENT', 'Imagination land');
  650. $this->assertTrue($request->isMobile());
  651. ServerRequest::addDetector('index', ['param' => 'action', 'value' => 'index']);
  652. $request = $request->withParam('action', 'index');
  653. $request->clearDetectorCache();
  654. $this->assertTrue($request->isIndex());
  655. $request = $request->withParam('action', 'add');
  656. $request->clearDetectorCache();
  657. $this->assertFalse($request->isIndex());
  658. ServerRequest::addDetector('withParams', function ($request, array $params) {
  659. foreach ($params as $name => $value) {
  660. if ($request->getParam($name) != $value) {
  661. return false;
  662. }
  663. }
  664. return true;
  665. });
  666. $request = $request->withParam('controller', 'Pages')->withParam('action', 'index');
  667. $request->clearDetectorCache();
  668. $this->assertTrue($request->isWithParams(['controller' => 'Pages', 'action' => 'index']));
  669. $request = $request->withParam('controller', 'Posts');
  670. $request->clearDetectorCache();
  671. $this->assertFalse($request->isWithParams(['controller' => 'Pages', 'action' => 'index']));
  672. ServerRequest::addDetector('callme', function ($request) {
  673. return $request->getAttribute('return');
  674. });
  675. $request = $request->withAttribute('return', true);
  676. $request->clearDetectorCache();
  677. $this->assertTrue($request->isCallMe());
  678. ServerRequest::addDetector('extension', ['param' => '_ext', 'options' => ['pdf', 'png', 'txt']]);
  679. $request = $request->withParam('_ext', 'pdf');
  680. $request->clearDetectorCache();
  681. $this->assertTrue($request->is('extension'));
  682. $request = $request->withParam('_ext', 'exe');
  683. $request->clearDetectorCache();
  684. $this->assertFalse($request->isExtension());
  685. }
  686. /**
  687. * Test getting headers
  688. */
  689. public function testHeader(): void
  690. {
  691. $request = new ServerRequest(['environment' => [
  692. 'HTTP_HOST' => 'localhost',
  693. 'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-ca) AppleWebKit/534.8+ (KHTML, like Gecko) Version/5.0 Safari/533.16',
  694. 'CONTENT_TYPE' => 'application/json',
  695. 'CONTENT_LENGTH' => '1337',
  696. 'HTTP_CONTENT_MD5' => 'abc123',
  697. ]]);
  698. $this->assertEquals($request->getEnv('HTTP_HOST'), $request->getHeaderLine('host'));
  699. $this->assertEquals($request->getEnv('HTTP_USER_AGENT'), $request->getHeaderLine('User-Agent'));
  700. $this->assertEquals($request->getEnv('CONTENT_LENGTH'), $request->getHeaderLine('content-length'));
  701. $this->assertEquals($request->getEnv('CONTENT_TYPE'), $request->getHeaderLine('content-type'));
  702. $this->assertEquals($request->getEnv('HTTP_CONTENT_MD5'), $request->getHeaderLine('content-md5'));
  703. }
  704. /**
  705. * Test getting headers with psr7 methods
  706. */
  707. public function testGetHeaders(): void
  708. {
  709. $request = new ServerRequest(['environment' => [
  710. 'HTTP_HOST' => 'localhost',
  711. 'CONTENT_TYPE' => 'application/json',
  712. 'CONTENT_LENGTH' => 1337,
  713. 'HTTP_CONTENT_MD5' => 'abc123',
  714. 'HTTP_DOUBLE' => ['a', 'b'],
  715. ]]);
  716. $headers = $request->getHeaders();
  717. $expected = [
  718. 'Host' => ['localhost'],
  719. 'Content-Type' => ['application/json'],
  720. 'Content-Length' => [1337],
  721. 'Content-Md5' => ['abc123'],
  722. 'Double' => ['a', 'b'],
  723. ];
  724. $this->assertEquals($expected, $headers);
  725. }
  726. /**
  727. * Test hasHeader
  728. */
  729. public function testHasHeader(): void
  730. {
  731. $request = new ServerRequest(['environment' => [
  732. 'HTTP_HOST' => 'localhost',
  733. 'CONTENT_TYPE' => 'application/json',
  734. 'CONTENT_LENGTH' => 1337,
  735. 'HTTP_CONTENT_MD5' => 'abc123',
  736. 'HTTP_DOUBLE' => ['a', 'b'],
  737. ]]);
  738. $this->assertTrue($request->hasHeader('Host'));
  739. $this->assertTrue($request->hasHeader('Content-Type'));
  740. $this->assertTrue($request->hasHeader('Content-MD5'));
  741. $this->assertTrue($request->hasHeader('Double'));
  742. $this->assertFalse($request->hasHeader('Authorization'));
  743. }
  744. /**
  745. * Test getting headers with psr7 methods
  746. */
  747. public function testGetHeader(): void
  748. {
  749. $request = new ServerRequest(['environment' => [
  750. 'HTTP_HOST' => 'localhost',
  751. 'CONTENT_TYPE' => 'application/json',
  752. 'CONTENT_LENGTH' => 1337,
  753. 'HTTP_CONTENT_MD5' => 'abc123',
  754. 'HTTP_DOUBLE' => ['a', 'b'],
  755. ]]);
  756. $this->assertEquals([], $request->getHeader('Not-there'));
  757. $expected = [$request->getEnv('HTTP_HOST')];
  758. $this->assertEquals($expected, $request->getHeader('Host'));
  759. $this->assertEquals($expected, $request->getHeader('host'));
  760. $this->assertEquals($expected, $request->getHeader('HOST'));
  761. $this->assertEquals(['a', 'b'], $request->getHeader('Double'));
  762. }
  763. /**
  764. * Test getting headers with psr7 methods
  765. */
  766. public function testGetHeaderLine(): void
  767. {
  768. $request = new ServerRequest(['environment' => [
  769. 'HTTP_HOST' => 'localhost',
  770. 'CONTENT_TYPE' => 'application/json',
  771. 'CONTENT_LENGTH' => '1337',
  772. 'HTTP_CONTENT_MD5' => 'abc123',
  773. 'HTTP_DOUBLE' => ['a', 'b'],
  774. ]]);
  775. $this->assertSame('', $request->getHeaderLine('Authorization'));
  776. $expected = $request->getEnv('CONTENT_LENGTH');
  777. $this->assertEquals($expected, $request->getHeaderLine('Content-Length'));
  778. $this->assertEquals($expected, $request->getHeaderLine('content-Length'));
  779. $this->assertEquals($expected, $request->getHeaderLine('ConTent-LenGth'));
  780. $this->assertSame('a, b', $request->getHeaderLine('Double'));
  781. }
  782. /**
  783. * Test setting a header.
  784. */
  785. public function testWithHeader(): void
  786. {
  787. $request = new ServerRequest(['environment' => [
  788. 'HTTP_HOST' => 'localhost',
  789. 'CONTENT_TYPE' => 'application/json',
  790. 'CONTENT_LENGTH' => '1337',
  791. 'HTTP_CONTENT_MD5' => 'abc123',
  792. 'HTTP_DOUBLE' => ['a', 'b'],
  793. ]]);
  794. $new = $request->withHeader('Content-Length', '999');
  795. $this->assertNotSame($new, $request);
  796. $this->assertSame('1337', $request->getHeaderLine('Content-length'), 'old request is unchanged');
  797. $this->assertSame('999', $new->getHeaderLine('Content-length'), 'new request is correct');
  798. $new = $request->withHeader('Double', ['a']);
  799. $this->assertEquals(['a'], $new->getHeader('Double'), 'List values are overwritten');
  800. }
  801. /**
  802. * Test adding a header.
  803. */
  804. public function testWithAddedHeader(): void
  805. {
  806. $request = new ServerRequest(['environment' => [
  807. 'HTTP_HOST' => 'localhost',
  808. 'CONTENT_TYPE' => 'application/json',
  809. 'CONTENT_LENGTH' => 1337,
  810. 'HTTP_CONTENT_MD5' => 'abc123',
  811. 'HTTP_DOUBLE' => ['a', 'b'],
  812. ]]);
  813. $new = $request->withAddedHeader('Double', 'c');
  814. $this->assertNotSame($new, $request);
  815. $this->assertSame('a, b', $request->getHeaderLine('Double'), 'old request is unchanged');
  816. $this->assertSame('a, b, c', $new->getHeaderLine('Double'), 'new request is correct');
  817. $new = $request->withAddedHeader('Content-Length', 777);
  818. $this->assertEquals([1337, 777], $new->getHeader('Content-Length'), 'scalar values are appended');
  819. $new = $request->withAddedHeader('Content-Length', [123, 456]);
  820. $this->assertEquals([1337, 123, 456], $new->getHeader('Content-Length'), 'List values are merged');
  821. }
  822. /**
  823. * Test removing a header.
  824. */
  825. public function testWithoutHeader(): void
  826. {
  827. $request = new ServerRequest(['environment' => [
  828. 'HTTP_HOST' => 'localhost',
  829. 'CONTENT_TYPE' => 'application/json',
  830. 'CONTENT_LENGTH' => 1337,
  831. 'HTTP_CONTENT_MD5' => 'abc123',
  832. 'HTTP_DOUBLE' => ['a', 'b'],
  833. ]]);
  834. $new = $request->withoutHeader('Content-Length');
  835. $this->assertNotSame($new, $request);
  836. $this->assertSame('1337', $request->getHeaderLine('Content-length'), 'old request is unchanged');
  837. $this->assertSame('', $new->getHeaderLine('Content-length'), 'new request is correct');
  838. }
  839. /**
  840. * Test accepts() with and without parameters
  841. */
  842. public function testAccepts(): void
  843. {
  844. $request = new ServerRequest(['environment' => [
  845. 'HTTP_ACCEPT' => 'text/xml,application/xml;q=0.9,application/xhtml+xml,text/html,text/plain,image/png',
  846. ]]);
  847. $result = $request->accepts();
  848. $expected = [
  849. 'text/xml', 'application/xhtml+xml', 'text/html', 'text/plain', 'image/png', 'application/xml',
  850. ];
  851. $this->assertEquals($expected, $result, 'Content types differ.');
  852. $result = $request->accepts('text/html');
  853. $this->assertTrue($result);
  854. $result = $request->accepts('image/gif');
  855. $this->assertFalse($result);
  856. }
  857. /**
  858. * Test that accept header types are trimmed for comparisons.
  859. */
  860. public function testAcceptWithWhitespace(): void
  861. {
  862. $request = new ServerRequest(['environment' => [
  863. 'HTTP_ACCEPT' => 'text/xml , text/html , text/plain,image/png',
  864. ]]);
  865. $result = $request->accepts();
  866. $expected = [
  867. 'text/xml', 'text/html', 'text/plain', 'image/png',
  868. ];
  869. $this->assertEquals($expected, $result, 'Content types differ.');
  870. $this->assertTrue($request->accepts('text/html'));
  871. }
  872. /**
  873. * Content types from accepts() should respect the client's q preference values.
  874. */
  875. public function testAcceptWithQvalueSorting(): void
  876. {
  877. $request = new ServerRequest(['environment' => [
  878. 'HTTP_ACCEPT' => 'text/html;q=0.8,application/json;q=0.7,application/xml;q=1.0',
  879. ]]);
  880. $result = $request->accepts();
  881. $expected = ['application/xml', 'text/html', 'application/json'];
  882. $this->assertEquals($expected, $result);
  883. }
  884. /**
  885. * Test the raw parsing of accept headers into the q value formatting.
  886. */
  887. public function testParseAcceptWithQValue(): void
  888. {
  889. $request = new ServerRequest(['environment' => [
  890. 'HTTP_ACCEPT' => 'text/html;q=0.8,application/json;q=0.7,application/xml;q=1.0,image/png',
  891. ]]);
  892. $result = $request->parseAccept();
  893. $expected = [
  894. '1.0' => ['application/xml', 'image/png'],
  895. '0.8' => ['text/html'],
  896. '0.7' => ['application/json'],
  897. ];
  898. $this->assertEquals($expected, $result);
  899. }
  900. /**
  901. * Test parsing accept with a confusing accept value.
  902. */
  903. public function testParseAcceptNoQValues(): void
  904. {
  905. $request = new ServerRequest(['environment' => [
  906. 'HTTP_ACCEPT' => 'application/json, text/plain, */*',
  907. ]]);
  908. $result = $request->parseAccept();
  909. $expected = [
  910. '1.0' => ['application/json', 'text/plain', '*/*'],
  911. ];
  912. $this->assertEquals($expected, $result);
  913. }
  914. /**
  915. * Test parsing accept ignores index param
  916. */
  917. public function testParseAcceptIgnoreAcceptExtensions(): void
  918. {
  919. $request = new ServerRequest(['environment' => [
  920. 'url' => '/',
  921. 'HTTP_ACCEPT' => 'application/json;level=1, text/plain, */*',
  922. ]]);
  923. $result = $request->parseAccept();
  924. $expected = [
  925. '1.0' => ['application/json', 'text/plain', '*/*'],
  926. ];
  927. $this->assertEquals($expected, $result);
  928. }
  929. /**
  930. * Test that parsing accept headers with invalid syntax works.
  931. *
  932. * The header used is missing a q value for application/xml.
  933. */
  934. public function testParseAcceptInvalidSyntax(): void
  935. {
  936. $request = new ServerRequest(['environment' => [
  937. 'url' => '/',
  938. 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;image/png,image/jpeg,image/*;q=0.9,*/*;q=0.8',
  939. ]]);
  940. $result = $request->parseAccept();
  941. $expected = [
  942. '1.0' => ['text/html', 'application/xhtml+xml', 'application/xml', 'image/jpeg'],
  943. '0.9' => ['image/*'],
  944. '0.8' => ['*/*'],
  945. ];
  946. $this->assertEquals($expected, $result);
  947. }
  948. /**
  949. * Test the getQuery() method
  950. */
  951. public function testGetQuery(): void
  952. {
  953. $array = [
  954. 'query' => [
  955. 'foo' => 'bar',
  956. 'zero' => '0',
  957. 'test' => [
  958. 'foo', 'bar',
  959. ],
  960. ],
  961. ];
  962. $request = new ServerRequest($array);
  963. $this->assertEquals([
  964. 'foo' => 'bar',
  965. 'zero' => '0',
  966. 'test' => [
  967. 'foo', 'bar',
  968. ],
  969. ], $request->getQuery());
  970. $this->assertSame('bar', $request->getQuery('foo'));
  971. $this->assertSame('0', $request->getQuery('zero'));
  972. $this->assertNull($request->getQuery('imaginary'));
  973. $this->assertSame('default', $request->getQuery('imaginary', 'default'));
  974. $this->assertFalse($request->getQuery('imaginary', false));
  975. $this->assertSame(['foo', 'bar'], $request->getQuery('test'));
  976. $this->assertSame('bar', $request->getQuery('test.1'));
  977. $this->assertNull($request->getQuery('test.2'));
  978. $this->assertSame('default', $request->getQuery('test.2', 'default'));
  979. }
  980. /**
  981. * Test getQueryParams
  982. */
  983. public function testGetQueryParams(): void
  984. {
  985. $get = [
  986. 'test' => ['foo', 'bar'],
  987. 'key' => 'value',
  988. ];
  989. $request = new ServerRequest([
  990. 'query' => $get,
  991. ]);
  992. $this->assertSame($get, $request->getQueryParams());
  993. }
  994. /**
  995. * Test withQueryParams and immutability
  996. */
  997. public function testWithQueryParams(): void
  998. {
  999. $get = [
  1000. 'test' => ['foo', 'bar'],
  1001. 'key' => 'value',
  1002. ];
  1003. $request = new ServerRequest([
  1004. 'query' => $get,
  1005. ]);
  1006. $new = $request->withQueryParams(['new' => 'data']);
  1007. $this->assertSame($get, $request->getQueryParams());
  1008. $this->assertSame(['new' => 'data'], $new->getQueryParams());
  1009. }
  1010. /**
  1011. * Test using param()
  1012. */
  1013. public function testReadingParams(): void
  1014. {
  1015. $request = new ServerRequest([
  1016. 'params' => [
  1017. 'controller' => 'Posts',
  1018. 'admin' => true,
  1019. 'truthy' => 1,
  1020. 'zero' => '0',
  1021. ],
  1022. ]);
  1023. $this->assertNull($request->getParam('not_set'));
  1024. $this->assertTrue($request->getParam('admin'));
  1025. $this->assertSame(1, $request->getParam('truthy'));
  1026. $this->assertSame('Posts', $request->getParam('controller'));
  1027. $this->assertSame('0', $request->getParam('zero'));
  1028. }
  1029. /**
  1030. * Test the data() method reading
  1031. */
  1032. public function testGetData(): void
  1033. {
  1034. $post = [
  1035. 'Model' => [
  1036. 'field' => 'value',
  1037. ],
  1038. ];
  1039. $request = new ServerRequest(compact('post'));
  1040. $this->assertEquals($post['Model'], $request->getData('Model'));
  1041. $this->assertEquals($post, $request->getData());
  1042. $this->assertNull($request->getData('Model.imaginary'));
  1043. $this->assertSame('value', $request->getData('Model.field', 'default'));
  1044. $this->assertSame('default', $request->getData('Model.imaginary', 'default'));
  1045. }
  1046. /**
  1047. * Test setting post data to a string throws exception.
  1048. */
  1049. public function testInvalidStringData(): void
  1050. {
  1051. $this->expectException(InvalidArgumentException::class);
  1052. $this->expectExceptionMessage('`post` key must be an array, object or null. Got `string` instead.');
  1053. $post = 'strange, but could happen';
  1054. $request = new ServerRequest(compact('post'));
  1055. }
  1056. /**
  1057. * Test writing falsey values.
  1058. */
  1059. public function testDataWritingFalsey(): void
  1060. {
  1061. $request = new ServerRequest();
  1062. $request = $request->withData('Post.null', null);
  1063. $this->assertNull($request->getData('Post.null'));
  1064. $request = $request->withData('Post.false', false);
  1065. $this->assertFalse($request->getData('Post.false'));
  1066. $request = $request->withData('Post.zero', 0);
  1067. $this->assertSame(0, $request->getData('Post.zero'));
  1068. $request = $request->withData('Post.empty', '');
  1069. $this->assertSame('', $request->getData('Post.empty'));
  1070. }
  1071. /**
  1072. * Test reading params
  1073. *
  1074. * @dataProvider paramReadingDataProvider
  1075. * @param mixed $expected
  1076. */
  1077. public function testGetParam(string $toRead, $expected): void
  1078. {
  1079. $request = new ServerRequest([
  1080. 'url' => '/',
  1081. 'params' => [
  1082. 'action' => 'index',
  1083. 'foo' => 'bar',
  1084. 'baz' => [
  1085. 'a' => [
  1086. 'b' => 'c',
  1087. ],
  1088. ],
  1089. 'admin' => true,
  1090. 'truthy' => 1,
  1091. 'zero' => '0',
  1092. ],
  1093. ]);
  1094. $this->assertSame($expected, $request->getParam($toRead));
  1095. }
  1096. /**
  1097. * Test getParam returning a default value.
  1098. */
  1099. public function testGetParamDefault(): void
  1100. {
  1101. $request = new ServerRequest([
  1102. 'params' => [
  1103. 'controller' => 'Articles',
  1104. 'null' => null,
  1105. ],
  1106. ]);
  1107. $this->assertSame('Articles', $request->getParam('controller', 'default'));
  1108. $this->assertSame('default', $request->getParam('null', 'default'));
  1109. $this->assertFalse($request->getParam('unset', false));
  1110. $this->assertNull($request->getParam('unset'));
  1111. }
  1112. /**
  1113. * Data provider for testing reading values with ServerRequest::getParam()
  1114. *
  1115. * @return array
  1116. */
  1117. public function paramReadingDataProvider(): array
  1118. {
  1119. return [
  1120. [
  1121. 'action',
  1122. 'index',
  1123. ],
  1124. [
  1125. 'baz',
  1126. [
  1127. 'a' => [
  1128. 'b' => 'c',
  1129. ],
  1130. ],
  1131. ],
  1132. [
  1133. 'baz.a.b',
  1134. 'c',
  1135. ],
  1136. [
  1137. 'does_not_exist',
  1138. null,
  1139. ],
  1140. [
  1141. 'admin',
  1142. true,
  1143. ],
  1144. [
  1145. 'truthy',
  1146. 1,
  1147. ],
  1148. [
  1149. 'zero',
  1150. '0',
  1151. ],
  1152. ];
  1153. }
  1154. /**
  1155. * test writing request params with param()
  1156. */
  1157. public function testParamWriting(): void
  1158. {
  1159. $request = new ServerRequest(['url' => '/']);
  1160. $request = $request->withParam('action', 'index');
  1161. $this->assertInstanceOf(
  1162. 'Cake\Http\ServerRequest',
  1163. $request->withParam('some', 'thing'),
  1164. 'Method has not returned $this'
  1165. );
  1166. $request = $request->withParam('Post.null', null);
  1167. $this->assertNull($request->getParam('Post.null'), 'default value should be used.');
  1168. $request = $request->withParam('Post.false', false);
  1169. $this->assertFalse($request->getParam('Post.false'));
  1170. $request = $request->withParam('Post.zero', 0);
  1171. $this->assertSame(0, $request->getParam('Post.zero'));
  1172. $request = $request->withParam('Post.empty', '');
  1173. $this->assertSame('', $request->getParam('Post.empty'));
  1174. $this->assertSame('index', $request->getParam('action'));
  1175. $request = $request->withParam('action', 'edit');
  1176. $this->assertSame('edit', $request->getParam('action'));
  1177. }
  1178. /**
  1179. * Test accept language
  1180. */
  1181. public function testAcceptLanguage(): void
  1182. {
  1183. $request = new ServerRequest();
  1184. // Weird language
  1185. $request = $request->withEnv('HTTP_ACCEPT_LANGUAGE', 'inexistent,en-ca');
  1186. $result = $request->acceptLanguage();
  1187. $this->assertEquals(['inexistent', 'en-ca'], $result, 'Languages do not match');
  1188. // No qualifier
  1189. $request = $request->withEnv('HTTP_ACCEPT_LANGUAGE', 'es_mx,en_ca');
  1190. $result = $request->acceptLanguage();
  1191. $this->assertEquals(['es-mx', 'en-ca'], $result, 'Languages do not match');
  1192. // With qualifier
  1193. $request = $request->withEnv('HTTP_ACCEPT_LANGUAGE', 'en-US,en;q=0.8,pt-BR;q=0.6,pt;q=0.4');
  1194. $result = $request->acceptLanguage();
  1195. $this->assertEquals(['en-us', 'en', 'pt-br', 'pt'], $result, 'Languages do not match');
  1196. // With spaces
  1197. $request = $request->withEnv('HTTP_ACCEPT_LANGUAGE', 'da, en-gb;q=0.8, en;q=0.7');
  1198. $result = $request->acceptLanguage();
  1199. $this->assertEquals(['da', 'en-gb', 'en'], $result, 'Languages do not match');
  1200. // Checking if requested
  1201. $request = $request->withEnv('HTTP_ACCEPT_LANGUAGE', 'es_mx,en_ca');
  1202. $result = $request->acceptLanguage('en-ca');
  1203. $this->assertTrue($result);
  1204. $result = $request->acceptLanguage('en-CA');
  1205. $this->assertTrue($result);
  1206. $result = $request->acceptLanguage('en-us');
  1207. $this->assertFalse($result);
  1208. $result = $request->acceptLanguage('en-US');
  1209. $this->assertFalse($result);
  1210. }
  1211. /**
  1212. * Test getBody
  1213. */
  1214. public function testGetBody(): void
  1215. {
  1216. $request = new ServerRequest([
  1217. 'input' => 'key=val&some=data',
  1218. ]);
  1219. $result = $request->getBody();
  1220. $this->assertInstanceOf('Psr\Http\Message\StreamInterface', $result);
  1221. $this->assertSame('key=val&some=data', $result->getContents());
  1222. }
  1223. /**
  1224. * Test withBody
  1225. */
  1226. public function testWithBody(): void
  1227. {
  1228. $request = new ServerRequest([
  1229. 'input' => 'key=val&some=data',
  1230. ]);
  1231. $body = $this->getMockBuilder('Psr\Http\Message\StreamInterface')->getMock();
  1232. $new = $request->withBody($body);
  1233. $this->assertNotSame($new, $request);
  1234. $this->assertNotSame($body, $request->getBody());
  1235. $this->assertSame($body, $new->getBody());
  1236. }
  1237. /**
  1238. * Test getUri
  1239. */
  1240. public function testGetUri(): void
  1241. {
  1242. $request = new ServerRequest(['url' => 'articles/view/3']);
  1243. $result = $request->getUri();
  1244. $this->assertInstanceOf('Psr\Http\Message\UriInterface', $result);
  1245. $this->assertSame('/articles/view/3', $result->getPath());
  1246. }
  1247. /**
  1248. * Test withUri
  1249. */
  1250. public function testWithUri(): void
  1251. {
  1252. $request = new ServerRequest([
  1253. 'environment' => [
  1254. 'HTTP_HOST' => 'example.com',
  1255. ],
  1256. 'url' => 'articles/view/3',
  1257. ]);
  1258. $uri = $this->getMockBuilder('Psr\Http\Message\UriInterface')->getMock();
  1259. $new = $request->withUri($uri);
  1260. $this->assertNotSame($new, $request);
  1261. $this->assertNotSame($uri, $request->getUri());
  1262. $this->assertSame($uri, $new->getUri());
  1263. }
  1264. /**
  1265. * Test withUri() and preserveHost
  1266. */
  1267. public function testWithUriPreserveHost(): void
  1268. {
  1269. $request = new ServerRequest([
  1270. 'environment' => [
  1271. 'HTTP_HOST' => 'localhost',
  1272. ],
  1273. 'url' => 'articles/view/3',
  1274. ]);
  1275. $uri = new Uri();
  1276. $uri = $uri->withHost('example.com')
  1277. ->withPort(123)
  1278. ->withPath('articles/view/3');
  1279. $new = $request->withUri($uri, false);
  1280. $this->assertNotSame($new, $request);
  1281. $this->assertSame('example.com:123', $new->getHeaderLine('Host'));
  1282. }
  1283. /**
  1284. * Test withUri() and preserveHost missing the host header
  1285. */
  1286. public function testWithUriPreserveHostNoHostHeader(): void
  1287. {
  1288. $request = new ServerRequest([
  1289. 'url' => 'articles/view/3',
  1290. ]);
  1291. $uri = new Uri();
  1292. $uri = $uri->withHost('example.com')
  1293. ->withPort(123)
  1294. ->withPath('articles/view/3');
  1295. $new = $request->withUri($uri, false);
  1296. $this->assertSame('example.com:123', $new->getHeaderLine('Host'));
  1297. }
  1298. /**
  1299. * Test the cookie() method.
  1300. */
  1301. public function testGetCookie(): void
  1302. {
  1303. $request = new ServerRequest([
  1304. 'cookies' => [
  1305. 'testing' => 'A value in the cookie',
  1306. 'user' => [
  1307. 'remember' => '1',
  1308. ],
  1309. ],
  1310. ]);
  1311. $this->assertSame('A value in the cookie', $request->getCookie('testing'));
  1312. $this->assertNull($request->getCookie('not there'));
  1313. $this->assertSame('default', $request->getCookie('not there', 'default'));
  1314. $this->assertSame('1', $request->getCookie('user.remember'));
  1315. $this->assertSame('1', $request->getCookie('user.remember', 'default'));
  1316. $this->assertSame('default', $request->getCookie('user.not there', 'default'));
  1317. }
  1318. /**
  1319. * Test getCookieParams()
  1320. */
  1321. public function testGetCookieParams(): void
  1322. {
  1323. $cookies = [
  1324. 'testing' => 'A value in the cookie',
  1325. ];
  1326. $request = new ServerRequest(['cookies' => $cookies]);
  1327. $this->assertSame($cookies, $request->getCookieParams());
  1328. }
  1329. /**
  1330. * Test withCookieParams()
  1331. */
  1332. public function testWithCookieParams(): void
  1333. {
  1334. $cookies = [
  1335. 'testing' => 'A value in the cookie',
  1336. ];
  1337. $request = new ServerRequest(['cookies' => $cookies]);
  1338. $new = $request->withCookieParams(['remember_me' => 1]);
  1339. $this->assertNotSame($new, $request);
  1340. $this->assertSame($cookies, $request->getCookieParams());
  1341. $this->assertSame(['remember_me' => 1], $new->getCookieParams());
  1342. }
  1343. /**
  1344. * Test getting a cookie collection from a request.
  1345. */
  1346. public function testGetCookieCollection(): void
  1347. {
  1348. $cookies = [
  1349. 'remember_me' => 1,
  1350. 'color' => 'blue',
  1351. ];
  1352. $request = new ServerRequest(['cookies' => $cookies]);
  1353. $cookies = $request->getCookieCollection();
  1354. $this->assertInstanceOf(CookieCollection::class, $cookies);
  1355. $this->assertCount(2, $cookies);
  1356. $this->assertSame('1', $cookies->get('remember_me')->getValue());
  1357. $this->assertSame('blue', $cookies->get('color')->getValue());
  1358. }
  1359. /**
  1360. * Test replacing cookies from a collection
  1361. */
  1362. public function testWithCookieCollection(): void
  1363. {
  1364. $cookies = new CookieCollection([new Cookie('remember_me', 1), new Cookie('color', 'red')]);
  1365. $request = new ServerRequest(['cookies' => ['bad' => 'goaway']]);
  1366. $new = $request->withCookieCollection($cookies);
  1367. $this->assertNotSame($new, $request, 'Should clone');
  1368. $this->assertSame(['bad' => 'goaway'], $request->getCookieParams());
  1369. $this->assertSame(['remember_me' => '1', 'color' => 'red'], $new->getCookieParams());
  1370. $cookies = $new->getCookieCollection();
  1371. $this->assertCount(2, $cookies);
  1372. $this->assertSame('red', $cookies->get('color')->getValue());
  1373. }
  1374. /**
  1375. * TestAllowMethod
  1376. */
  1377. public function testAllowMethod(): void
  1378. {
  1379. $request = new ServerRequest(['environment' => [
  1380. 'url' => '/posts/edit/1',
  1381. 'REQUEST_METHOD' => 'PUT',
  1382. ]]);
  1383. $this->assertTrue($request->allowMethod('put'));
  1384. $request = $request->withEnv('REQUEST_METHOD', 'DELETE');
  1385. $this->assertTrue($request->allowMethod(['post', 'delete']));
  1386. }
  1387. /**
  1388. * Test allowMethod throwing exception
  1389. */
  1390. public function testAllowMethodException(): void
  1391. {
  1392. $request = new ServerRequest([
  1393. 'url' => '/posts/edit/1',
  1394. 'environment' => ['REQUEST_METHOD' => 'PUT'],
  1395. ]);
  1396. try {
  1397. $request->allowMethod(['POST', 'DELETE']);
  1398. $this->fail('An expected exception has not been raised.');
  1399. } catch (MethodNotAllowedException $e) {
  1400. $this->assertEquals(['Allow' => 'POST, DELETE'], $e->getHeaders());
  1401. }
  1402. $this->expectException(MethodNotAllowedException::class);
  1403. $request->allowMethod('POST');
  1404. }
  1405. /**
  1406. * Tests getting the session from the request
  1407. */
  1408. public function testGetSession(): void
  1409. {
  1410. $session = new Session();
  1411. $request = new ServerRequest(['session' => $session]);
  1412. $this->assertSame($session, $request->getSession());
  1413. $request = new ServerRequest();
  1414. $this->assertEquals($session, $request->getSession());
  1415. }
  1416. public function testGetFlash(): void
  1417. {
  1418. $request = new ServerRequest();
  1419. $this->assertInstanceOf(FlashMessage::class, $request->getFlash());
  1420. }
  1421. /**
  1422. * Test the content type method.
  1423. */
  1424. public function testContentType(): void
  1425. {
  1426. $request = new ServerRequest([
  1427. 'environment' => ['HTTP_CONTENT_TYPE' => 'application/json'],
  1428. ]);
  1429. $this->assertSame('application/json', $request->contentType());
  1430. $request = new ServerRequest([
  1431. 'environment' => ['HTTP_CONTENT_TYPE' => 'application/xml'],
  1432. ]);
  1433. $this->assertSame('application/xml', $request->contentType(), 'prefer non http header.');
  1434. }
  1435. /**
  1436. * Test updating params in a psr7 fashion.
  1437. */
  1438. public function testWithParam(): void
  1439. {
  1440. $request = new ServerRequest([
  1441. 'params' => ['controller' => 'Articles'],
  1442. ]);
  1443. $result = $request->withParam('action', 'view');
  1444. $this->assertNotSame($result, $request, 'New instance should be made');
  1445. $this->assertNull($request->getParam('action'), 'No side-effect on original');
  1446. $this->assertSame('view', $result->getParam('action'));
  1447. $result = $request->withParam('action', 'index')
  1448. ->withParam('plugin', 'DebugKit')
  1449. ->withParam('prefix', 'Admin');
  1450. $this->assertNotSame($result, $request, 'New instance should be made');
  1451. $this->assertNull($request->getParam('action'), 'No side-effect on original');
  1452. $this->assertSame('index', $result->getParam('action'));
  1453. $this->assertSame('DebugKit', $result->getParam('plugin'));
  1454. $this->assertSame('Admin', $result->getParam('prefix'));
  1455. }
  1456. /**
  1457. * Test getting the parsed body parameters.
  1458. */
  1459. public function testGetParsedBody(): void
  1460. {
  1461. $data = ['title' => 'First', 'body' => 'Best Article!'];
  1462. $request = new ServerRequest(['post' => $data]);
  1463. $this->assertSame($data, $request->getParsedBody());
  1464. $request = new ServerRequest();
  1465. $this->assertSame([], $request->getParsedBody());
  1466. }
  1467. /**
  1468. * Test replacing the parsed body parameters.
  1469. */
  1470. public function testWithParsedBody(): void
  1471. {
  1472. $data = ['title' => 'First', 'body' => 'Best Article!'];
  1473. $request = new ServerRequest([]);
  1474. $new = $request->withParsedBody($data);
  1475. $this->assertNotSame($request, $new);
  1476. $this->assertSame([], $request->getParsedBody());
  1477. $this->assertSame($data, $new->getParsedBody());
  1478. }
  1479. /**
  1480. * Test updating POST data in a psr7 fashion.
  1481. */
  1482. public function testWithData(): void
  1483. {
  1484. $request = new ServerRequest([
  1485. 'post' => [
  1486. 'Model' => [
  1487. 'field' => 'value',
  1488. ],
  1489. ],
  1490. ]);
  1491. $result = $request->withData('Model.new_value', 'new value');
  1492. $this->assertNull($request->getData('Model.new_value'), 'Original request should not change.');
  1493. $this->assertNotSame($result, $request);
  1494. $this->assertSame('new value', $result->getData('Model.new_value'));
  1495. $this->assertSame('new value', $result->getData()['Model']['new_value']);
  1496. $this->assertSame('value', $result->getData('Model.field'));
  1497. }
  1498. /**
  1499. * Test removing data from a request
  1500. */
  1501. public function testWithoutData(): void
  1502. {
  1503. $request = new ServerRequest([
  1504. 'post' => [
  1505. 'Model' => [
  1506. 'id' => 1,
  1507. 'field' => 'value',
  1508. ],
  1509. ],
  1510. ]);
  1511. $updated = $request->withoutData('Model.field');
  1512. $this->assertNotSame($updated, $request);
  1513. $this->assertSame('value', $request->getData('Model.field'), 'Original request should not change.');
  1514. $this->assertNull($updated->getData('Model.field'), 'data removed from updated request');
  1515. $this->assertFalse(isset($updated->getData()['Model']['field']), 'data removed from updated request');
  1516. }
  1517. /**
  1518. * Test updating POST data when keys don't exist
  1519. */
  1520. public function testWithDataMissingIntermediaryKeys(): void
  1521. {
  1522. $request = new ServerRequest([
  1523. 'post' => [
  1524. 'Model' => [
  1525. 'field' => 'value',
  1526. ],
  1527. ],
  1528. ]);
  1529. $result = $request->withData('Model.field.new_value', 'new value');
  1530. $this->assertSame(
  1531. 'new value',
  1532. $result->getData('Model.field.new_value')
  1533. );
  1534. $this->assertSame(
  1535. 'new value',
  1536. $result->getData()['Model']['field']['new_value']
  1537. );
  1538. }
  1539. /**
  1540. * Test updating POST data with falsey values
  1541. */
  1542. public function testWithDataFalseyValues(): void
  1543. {
  1544. $request = new ServerRequest([
  1545. 'post' => [],
  1546. ]);
  1547. $result = $request->withData('false', false)
  1548. ->withData('null', null)
  1549. ->withData('empty_string', '')
  1550. ->withData('zero', 0)
  1551. ->withData('zero_string', '0');
  1552. $expected = [
  1553. 'false' => false,
  1554. 'null' => null,
  1555. 'empty_string' => '',
  1556. 'zero' => 0,
  1557. 'zero_string' => '0',
  1558. ];
  1559. $this->assertSame($expected, $result->getData());
  1560. }
  1561. /**
  1562. * Test setting attributes.
  1563. */
  1564. public function testWithAttribute(): void
  1565. {
  1566. $request = new ServerRequest([]);
  1567. $this->assertNull($request->getAttribute('key'));
  1568. $this->assertSame('default', $request->getAttribute('key', 'default'));
  1569. $new = $request->withAttribute('key', 'value');
  1570. $this->assertNotEquals($new, $request, 'Should be different');
  1571. $this->assertNull($request->getAttribute('key'), 'Old instance not modified');
  1572. $this->assertSame('value', $new->getAttribute('key'));
  1573. $update = $new->withAttribute('key', ['complex']);
  1574. $this->assertNotEquals($update, $new, 'Should be different');
  1575. $this->assertSame(['complex'], $update->getAttribute('key'));
  1576. }
  1577. /**
  1578. * Test that replacing the session can be done via withAttribute()
  1579. */
  1580. public function testWithAttributeSession(): void
  1581. {
  1582. $request = new ServerRequest([]);
  1583. $request->getSession()->write('attrKey', 'session-value');
  1584. $update = $request->withAttribute('session', Session::create());
  1585. $this->assertSame('session-value', $request->getAttribute('session')->read('attrKey'));
  1586. $this->assertNotSame($request->getAttribute('session'), $update->getAttribute('session'));
  1587. $this->assertNotSame($request->getSession()->read('attrKey'), $update->getSession()->read('attrKey'));
  1588. }
  1589. /**
  1590. * Test getting all attributes.
  1591. */
  1592. public function testGetAttributes(): void
  1593. {
  1594. $request = new ServerRequest([]);
  1595. $new = $request->withAttribute('key', 'value')
  1596. ->withAttribute('nully', null)
  1597. ->withAttribute('falsey', false);
  1598. $this->assertFalse($new->getAttribute('falsey'));
  1599. $this->assertNull($new->getAttribute('nully'));
  1600. $expected = [
  1601. 'key' => 'value',
  1602. 'nully' => null,
  1603. 'falsey' => false,
  1604. 'params' => [
  1605. 'plugin' => null,
  1606. 'controller' => null,
  1607. 'action' => null,
  1608. '_ext' => null,
  1609. 'pass' => [],
  1610. ],
  1611. 'webroot' => '',
  1612. 'base' => '',
  1613. 'here' => '/',
  1614. ];
  1615. $this->assertEquals($expected, $new->getAttributes());
  1616. }
  1617. /**
  1618. * Test unsetting attributes.
  1619. */
  1620. public function testWithoutAttribute(): void
  1621. {
  1622. $request = new ServerRequest([]);
  1623. $new = $request->withAttribute('key', 'value');
  1624. $update = $request->withoutAttribute('key');
  1625. $this->assertNotEquals($update, $new, 'Should be different');
  1626. $this->assertNull($update->getAttribute('key'));
  1627. }
  1628. /**
  1629. * Test that withoutAttribute() cannot remove emulatedAttributes properties.
  1630. *
  1631. * @dataProvider emulatedPropertyProvider
  1632. */
  1633. public function testWithoutAttributesDenyEmulatedProperties(string $prop): void
  1634. {
  1635. $this->expectException(InvalidArgumentException::class);
  1636. $request = new ServerRequest([]);
  1637. $request->withoutAttribute($prop);
  1638. }
  1639. /**
  1640. * Test the requestTarget methods.
  1641. */
  1642. public function testWithRequestTarget(): void
  1643. {
  1644. $request = new ServerRequest([
  1645. 'environment' => [
  1646. 'REQUEST_URI' => '/articles/view/1',
  1647. 'QUERY_STRING' => 'comments=1&open=0',
  1648. ],
  1649. 'base' => '/basedir',
  1650. ]);
  1651. $this->assertSame(
  1652. '/articles/view/1?comments=1&open=0',
  1653. $request->getRequestTarget(),
  1654. 'Should not include basedir.'
  1655. );
  1656. $new = $request->withRequestTarget('/articles/view/3');
  1657. $this->assertNotSame($new, $request);
  1658. $this->assertSame(
  1659. '/articles/view/1?comments=1&open=0',
  1660. $request->getRequestTarget(),
  1661. 'should be unchanged.'
  1662. );
  1663. $this->assertSame('/articles/view/3', $new->getRequestTarget(), 'reflects method call');
  1664. }
  1665. /**
  1666. * Test withEnv()
  1667. */
  1668. public function testWithEnv(): void
  1669. {
  1670. $request = new ServerRequest();
  1671. $newRequest = $request->withEnv('HTTP_HOST', 'cakephp.org');
  1672. $this->assertNotSame($request, $newRequest);
  1673. $this->assertSame('cakephp.org', $newRequest->getEnv('HTTP_HOST'));
  1674. }
  1675. /**
  1676. * Test getEnv()
  1677. */
  1678. public function testGetEnv(): void
  1679. {
  1680. $request = new ServerRequest([
  1681. 'environment' => ['TEST' => 'ing'],
  1682. ]);
  1683. //Test default null
  1684. $this->assertNull($request->getEnv('Foo'));
  1685. //Test default set
  1686. $this->assertSame('Bar', $request->getEnv('Foo', 'Bar'));
  1687. //Test env() fallback
  1688. $this->assertSame('ing', $request->getEnv('test'));
  1689. }
  1690. /**
  1691. * Data provider for emulated property tests.
  1692. *
  1693. * @return array
  1694. */
  1695. public function emulatedPropertyProvider(): array
  1696. {
  1697. return [
  1698. ['here'],
  1699. ['params'],
  1700. ['base'],
  1701. ['webroot'],
  1702. ['session'],
  1703. ];
  1704. }
  1705. }