ResponseTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  10. * @link https://cakephp.org CakePHP(tm) Project
  11. * @since 3.0.0
  12. * @license https://opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Cake\Test\TestCase\Http\Client;
  15. use Cake\Http\Client\Response;
  16. use Cake\Http\Cookie\CookieCollection;
  17. use Cake\TestSuite\TestCase;
  18. /**
  19. * HTTP response test.
  20. */
  21. class ResponseTest extends TestCase
  22. {
  23. /**
  24. * Test parsing headers and reading with PSR7 methods.
  25. *
  26. * @return void
  27. */
  28. public function testHeaderParsingPsr7()
  29. {
  30. $headers = [
  31. 'HTTP/1.0 200 OK',
  32. 'Content-Type : text/html;charset="UTF-8"',
  33. 'date: Tue, 25 Dec 2012 04:43:47 GMT',
  34. ];
  35. $response = new Response($headers, 'winner!');
  36. $this->assertEquals('1.0', $response->getProtocolVersion());
  37. $this->assertSame(200, $response->getStatusCode());
  38. $this->assertEquals('OK', $response->getReasonPhrase());
  39. $this->assertEquals(
  40. 'text/html;charset="UTF-8"',
  41. $response->getHeaderLine('content-type')
  42. );
  43. $this->assertEquals(
  44. 'Tue, 25 Dec 2012 04:43:47 GMT',
  45. $response->getHeaderLine('Date')
  46. );
  47. $this->assertEquals('winner!', '' . $response->getBody());
  48. }
  49. /**
  50. * Test parsing headers and capturing content
  51. *
  52. * @return void
  53. */
  54. public function testHeaderParsing()
  55. {
  56. $headers = [
  57. 'HTTP/1.0 200 OK',
  58. 'Content-Type : text/html;charset="UTF-8"',
  59. 'date: Tue, 25 Dec 2012 04:43:47 GMT',
  60. ];
  61. $response = new Response($headers, 'ok');
  62. $this->assertSame(200, $response->getStatusCode());
  63. $this->assertEquals('1.0', $response->getProtocolVersion());
  64. $this->assertEquals(
  65. 'text/html;charset="UTF-8"',
  66. $response->getHeaderLine('content-type')
  67. );
  68. $this->assertEquals(
  69. 'Tue, 25 Dec 2012 04:43:47 GMT',
  70. $response->getHeaderLine('Date')
  71. );
  72. $this->assertEquals(
  73. 'text/html;charset="UTF-8"',
  74. $response->getHeaderLine('Content-Type')
  75. );
  76. $headers = [
  77. 'HTTP/1.0 200',
  78. ];
  79. $response = new Response($headers, 'ok');
  80. $this->assertEquals('1.0', $response->getProtocolVersion());
  81. $this->assertSame(200, $response->getStatusCode());
  82. }
  83. /**
  84. * Test body()
  85. *
  86. * @return void
  87. */
  88. public function testBody()
  89. {
  90. $this->deprecated(function () {
  91. $data = [
  92. 'property' => 'value',
  93. ];
  94. $encoded = json_encode($data);
  95. $response = new Response([], $encoded);
  96. $this->assertEquals($encoded, $response->getBody()->getContents());
  97. $this->assertEquals($encoded, $response->body());
  98. $result = $response->body('json_decode');
  99. $this->assertEquals($data['property'], $result->property);
  100. $stream = $response->getBody();
  101. $stream->rewind();
  102. $this->assertEquals($encoded, $stream->getContents());
  103. });
  104. }
  105. /**
  106. * Test getStringBody()
  107. *
  108. * @return void
  109. */
  110. public function getStringBody()
  111. {
  112. $response = new Response([], 'string');
  113. $this->assertEquals('string', $response->getStringBody());
  114. }
  115. /**
  116. * Test accessor for json
  117. *
  118. * @return void
  119. */
  120. public function testBodyJson()
  121. {
  122. $data = [
  123. 'property' => 'value',
  124. ];
  125. $encoded = json_encode($data);
  126. $response = new Response([], $encoded);
  127. $this->assertEquals($data['property'], $response->getJson()['property']);
  128. $data = '';
  129. $response = new Response([], $data);
  130. $this->assertNull($response->getJson());
  131. $data = json_encode([]);
  132. $response = new Response([], $data);
  133. $this->assertInternalType('array', $response->getJson());
  134. $data = json_encode(null);
  135. $response = new Response([], $data);
  136. $this->assertNull($response->getJson());
  137. $data = json_encode(false);
  138. $response = new Response([], $data);
  139. $this->assertFalse($response->getJson());
  140. $data = json_encode('');
  141. $response = new Response([], $data);
  142. $this->assertSame('', $response->getJson());
  143. }
  144. /**
  145. * Test accessor for json when set with PSR7 methods.
  146. *
  147. * @return void
  148. */
  149. public function testBodyJsonPsr7()
  150. {
  151. $data = [
  152. 'property' => 'value',
  153. ];
  154. $encoded = json_encode($data);
  155. $response = new Response([], '');
  156. $response->getBody()->write($encoded);
  157. $this->assertEquals($data, $response->getJson());
  158. }
  159. /**
  160. * Test accessor for xml
  161. *
  162. * @return void
  163. */
  164. public function testBodyXml()
  165. {
  166. $data = <<<XML
  167. <?xml version="1.0" encoding="utf-8"?>
  168. <root>
  169. <test>Test</test>
  170. </root>
  171. XML;
  172. $response = new Response([], $data);
  173. $this->assertEquals('Test', (string)$response->getXml()->test);
  174. $data = '';
  175. $response = new Response([], $data);
  176. $this->assertNull($response->getXml());
  177. }
  178. /**
  179. * Test isOk()
  180. *
  181. * @return void
  182. */
  183. public function testIsOk()
  184. {
  185. $headers = [
  186. 'HTTP/1.1 200 OK',
  187. 'Content-Type: text/html',
  188. ];
  189. $response = new Response($headers, 'ok');
  190. $this->assertTrue($response->isOk());
  191. $headers = [
  192. 'HTTP/1.1 201 Created',
  193. 'Content-Type: text/html',
  194. ];
  195. $response = new Response($headers, 'ok');
  196. $this->assertTrue($response->isOk());
  197. $headers = [
  198. 'HTTP/1.1 202 Accepted',
  199. 'Content-Type: text/html',
  200. ];
  201. $response = new Response($headers, 'ok');
  202. $this->assertTrue($response->isOk());
  203. $headers = [
  204. 'HTTP/1.1 203 Non-Authoritative Information',
  205. 'Content-Type: text/html',
  206. ];
  207. $response = new Response($headers, 'ok');
  208. $this->assertTrue($response->isOk());
  209. $headers = [
  210. 'HTTP/1.1 204 No Content',
  211. 'Content-Type: text/html',
  212. ];
  213. $response = new Response($headers, 'ok');
  214. $this->assertTrue($response->isOk());
  215. $headers = [
  216. 'HTTP/1.1 301 Moved Permanently',
  217. 'Content-Type: text/html',
  218. ];
  219. $response = new Response($headers, '');
  220. $this->assertFalse($response->isOk());
  221. $headers = [
  222. 'HTTP/1.0 404 Not Found',
  223. 'Content-Type: text/html',
  224. ];
  225. $response = new Response($headers, '');
  226. $this->assertFalse($response->isOk());
  227. }
  228. /**
  229. * Test isSuccess()
  230. *
  231. * @return void
  232. */
  233. public function testIsSuccess()
  234. {
  235. $headers = [
  236. 'HTTP/1.1 200 OK',
  237. 'Content-Type: text/html',
  238. ];
  239. $response = new Response($headers, 'ok');
  240. $this->assertTrue($response->isSuccess());
  241. $headers = [
  242. 'HTTP/1.1 201 Created',
  243. 'Content-Type: text/html',
  244. ];
  245. $response = new Response($headers, 'ok');
  246. $this->assertTrue($response->isSuccess());
  247. $headers = [
  248. 'HTTP/1.1 202 Accepted',
  249. 'Content-Type: text/html',
  250. ];
  251. $response = new Response($headers, 'ok');
  252. $this->assertTrue($response->isSuccess());
  253. $headers = [
  254. 'HTTP/1.1 203 Non-Authoritative Information',
  255. 'Content-Type: text/html',
  256. ];
  257. $response = new Response($headers, 'ok');
  258. $this->assertTrue($response->isSuccess());
  259. $headers = [
  260. 'HTTP/1.1 204 No Content',
  261. 'Content-Type: text/html',
  262. ];
  263. $response = new Response($headers);
  264. $this->assertTrue($response->isSuccess());
  265. $headers = [
  266. 'HTTP/1.1 301 Moved Permanently',
  267. 'Content-Type: text/html',
  268. ];
  269. $response = new Response($headers, '');
  270. $this->assertFalse($response->isSuccess());
  271. $headers = [
  272. 'HTTP/1.1 404 Not Found',
  273. 'Content-Type: text/html',
  274. ];
  275. $response = new Response($headers, '');
  276. $this->assertFalse($response->isSuccess());
  277. $headers = [
  278. 'HTTP/1.1 500 Internal Server Error',
  279. 'Content-Type: text/html',
  280. ];
  281. $response = new Response($headers, '');
  282. $this->assertFalse($response->isSuccess());
  283. }
  284. /**
  285. * Test isRedirect()
  286. *
  287. * @return void
  288. */
  289. public function testIsRedirect()
  290. {
  291. $headers = [
  292. 'HTTP/1.1 200 OK',
  293. 'Content-Type: text/html',
  294. ];
  295. $response = new Response($headers, 'ok');
  296. $this->assertFalse($response->isRedirect());
  297. $headers = [
  298. 'HTTP/1.1 301 Moved Permanently',
  299. 'Location: /',
  300. 'Content-Type: text/html',
  301. ];
  302. $response = new Response($headers, '');
  303. $this->assertTrue($response->isRedirect());
  304. $headers = [
  305. 'HTTP/1.0 404 Not Found',
  306. 'Content-Type: text/html',
  307. ];
  308. $response = new Response($headers, '');
  309. $this->assertFalse($response->isRedirect());
  310. }
  311. /**
  312. * Test parsing / getting cookies.
  313. *
  314. * @group deprecated
  315. * @return void
  316. */
  317. public function testCookie()
  318. {
  319. $this->deprecated(function () {
  320. $headers = [
  321. 'HTTP/1.0 200 Ok',
  322. 'Set-Cookie: test=value',
  323. 'Set-Cookie: session=123abc',
  324. 'Set-Cookie: expiring=soon; Expires=Wed, 09-Jun-2021 10:18:14 GMT; Path=/; HttpOnly; Secure;',
  325. ];
  326. $response = new Response($headers, '');
  327. $this->assertEquals('value', $response->cookie('test'));
  328. $this->assertEquals('123abc', $response->cookie('session'));
  329. $this->assertEquals('soon', $response->cookie('expiring'));
  330. $result = $response->cookie('expiring', true);
  331. $this->assertTrue($result['httponly']);
  332. $this->assertTrue($result['secure']);
  333. $this->assertEquals(
  334. 'Wed, 09-Jun-2021 10:18:14 GMT',
  335. $result['expires']
  336. );
  337. $this->assertEquals('/', $result['path']);
  338. $result = $response->header('set-cookie');
  339. $this->assertCount(3, $result, 'Should be an array.');
  340. $this->assertTrue(isset($response->cookies));
  341. $this->assertEquals(
  342. 'soon',
  343. $response->cookies['expiring']['value']
  344. );
  345. });
  346. }
  347. /**
  348. * Test accessing cookies through the PSR7-like methods
  349. *
  350. * @return void
  351. */
  352. public function testGetCookies()
  353. {
  354. $headers = [
  355. 'HTTP/1.0 200 Ok',
  356. 'Set-Cookie: test=value',
  357. 'Set-Cookie: session=123abc',
  358. 'Set-Cookie: expiring=soon; Expires=Wed, 09-Jun-2021 10:18:14 GMT; Path=/; HttpOnly; Secure;',
  359. ];
  360. $response = new Response($headers, '');
  361. $this->assertNull($response->getCookie('undef'));
  362. $this->assertEquals('value', $response->getCookie('test'));
  363. $this->assertEquals('soon', $response->getCookie('expiring'));
  364. $result = $response->getCookieData('expiring');
  365. $this->assertEquals('soon', $result['value']);
  366. $this->assertTrue($result['httponly']);
  367. $this->assertTrue($result['secure']);
  368. $this->assertEquals(
  369. 'Wed, 09-Jun-2021 10:18:14 GMT',
  370. $result['expires']
  371. );
  372. $this->assertEquals('/', $result['path']);
  373. $result = $response->getCookies();
  374. $this->assertCount(3, $result);
  375. $this->assertArrayHasKey('test', $result);
  376. $this->assertArrayHasKey('session', $result);
  377. $this->assertArrayHasKey('expiring', $result);
  378. }
  379. /**
  380. * Test accessing cookie collection
  381. *
  382. * @return void
  383. */
  384. public function testGetCookieCollection()
  385. {
  386. $headers = [
  387. 'HTTP/1.0 200 Ok',
  388. 'Set-Cookie: test=value',
  389. 'Set-Cookie: session=123abc',
  390. 'Set-Cookie: expiring=soon; Expires=Wed, 09-Jun-2021 10:18:14 GMT; Path=/; HttpOnly; Secure;',
  391. ];
  392. $response = new Response($headers, '');
  393. $cookies = $response->getCookieCollection();
  394. $this->assertInstanceOf(CookieCollection::class, $cookies);
  395. $this->assertTrue($cookies->has('test'));
  396. $this->assertTrue($cookies->has('session'));
  397. $this->assertTrue($cookies->has('expiring'));
  398. $this->assertSame('123abc', $cookies->get('session')->getValue());
  399. }
  400. /**
  401. * Test statusCode()
  402. *
  403. * @return void
  404. */
  405. public function testGetStatusCode()
  406. {
  407. $headers = [
  408. 'HTTP/1.0 404 Not Found',
  409. 'Content-Type: text/html',
  410. ];
  411. $response = new Response($headers, '');
  412. $this->assertSame(404, $response->getStatusCode());
  413. $this->deprecated(function () use ($response) {
  414. $this->assertSame(404, $response->code);
  415. $this->assertTrue(isset($response->code));
  416. });
  417. }
  418. /**
  419. * Test statusCode()
  420. *
  421. * @group deprecated
  422. * @return void
  423. */
  424. public function testStatusCode()
  425. {
  426. $this->deprecated(function () {
  427. $headers = [
  428. 'HTTP/1.0 404 Not Found',
  429. 'Content-Type: text/html',
  430. ];
  431. $response = new Response($headers, '');
  432. $this->assertSame(404, $response->statusCode());
  433. $this->assertSame(404, $response->code);
  434. $this->assertTrue(isset($response->code));
  435. });
  436. }
  437. /**
  438. * Test reading the encoding out.
  439. *
  440. * @return void
  441. */
  442. public function testGetEncoding()
  443. {
  444. $headers = [
  445. 'HTTP/1.0 200 Ok',
  446. ];
  447. $response = new Response($headers, '');
  448. $this->assertNull($response->getEncoding());
  449. $headers = [
  450. 'HTTP/1.0 200 Ok',
  451. 'Content-Type: text/html',
  452. ];
  453. $response = new Response($headers, '');
  454. $this->assertNull($response->getEncoding());
  455. $headers = [
  456. 'HTTP/1.0 200 Ok',
  457. 'Content-Type: text/html; charset="UTF-8"',
  458. ];
  459. $response = new Response($headers, '');
  460. $this->assertEquals('UTF-8', $response->getEncoding());
  461. $headers = [
  462. 'HTTP/1.0 200 Ok',
  463. "Content-Type: text/html; charset='ISO-8859-1'",
  464. ];
  465. $response = new Response($headers, '');
  466. $this->assertEquals('ISO-8859-1', $response->getEncoding());
  467. }
  468. /**
  469. * Test reading the encoding out.
  470. *
  471. * @group deprecated
  472. * @return void
  473. */
  474. public function testEncoding()
  475. {
  476. $this->deprecated(function () {
  477. $headers = [
  478. 'HTTP/1.0 200 Ok',
  479. ];
  480. $response = new Response($headers, '');
  481. $this->assertNull($response->encoding());
  482. $headers = [
  483. 'HTTP/1.0 200 Ok',
  484. 'Content-Type: text/html',
  485. ];
  486. $response = new Response($headers, '');
  487. $this->assertNull($response->encoding());
  488. $headers = [
  489. 'HTTP/1.0 200 Ok',
  490. 'Content-Type: text/html; charset="UTF-8"',
  491. ];
  492. $response = new Response($headers, '');
  493. $this->assertEquals('UTF-8', $response->encoding());
  494. $headers = [
  495. 'HTTP/1.0 200 Ok',
  496. "Content-Type: text/html; charset='ISO-8859-1'",
  497. ];
  498. $response = new Response($headers, '');
  499. $this->assertEquals('ISO-8859-1', $response->encoding());
  500. });
  501. }
  502. /**
  503. * Test that gzip responses are automatically decompressed.
  504. *
  505. * @return void
  506. */
  507. public function testAutoDecodeGzipBody()
  508. {
  509. $headers = [
  510. 'HTTP/1.0 200 OK',
  511. 'Content-Encoding: gzip',
  512. 'Content-Length: 32',
  513. 'Content-Type: text/html; charset=UTF-8',
  514. ];
  515. $body = base64_decode('H4sIAAAAAAAAA/NIzcnJVyjPL8pJUQQAlRmFGwwAAAA=');
  516. $response = new Response($headers, $body);
  517. $this->assertEquals('Hello world!', $response->getBody()->getContents());
  518. }
  519. }