PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/cases/net/http/ResponseTest.php

http://github.com/UnionOfRAD/lithium
PHP | 621 lines | 512 code | 90 blank | 19 comment | 0 complexity | de29f82c9d064804fa5f0556ddb93b1d MD5 | raw file
  1. <?php
  2. /**
  3. * li₃: the most RAD framework for PHP (http://li3.me)
  4. *
  5. * Copyright 2009, Union of RAD. All rights reserved. This source
  6. * code is distributed under the terms of the BSD 3-Clause License.
  7. * The full license text can be found in the LICENSE.txt file.
  8. */
  9. namespace lithium\tests\cases\net\http;
  10. use lithium\net\http\Response;
  11. class ResponseTest extends \lithium\test\Unit {
  12. public function testStatus() {
  13. $response = new Response();
  14. $expected = 'HTTP/1.1 500 Internal Server Error';
  15. $result = $response->status(500);
  16. $this->assertEqual($expected, $result);
  17. $expected = 'HTTP/1.1 500 Internal Server Error';
  18. $result = $response->status('500');
  19. $this->assertEqual($expected, $result);
  20. $expected = 'HTTP/1.1 500 Internal Server Error';
  21. $result = $response->status('Internal Server Error');
  22. $this->assertEqual($expected, $result);
  23. $expected = 500;
  24. $result = $response->status('code', 'Internal Server Error');
  25. $this->assertEqual($expected, $result);
  26. $expected = 'Internal Server Error';
  27. $result = $response->status('message', 500);
  28. $this->assertEqual($expected, $result);
  29. $expected = 'HTTP/1.1 500 Internal Server Error';
  30. $result = $response->status();
  31. $this->assertEqual($expected, $result);
  32. $expected = 'HTTP/1.1 303 See Other';
  33. $result = $response->status('See Other');
  34. $this->assertEqual($expected, $result);
  35. $result = $response->status('foobar');
  36. $this->assertFalse($result);
  37. }
  38. public function testParsingContentTypeWithEncoding() {
  39. $response = new Response(['headers' => [
  40. 'Content-Type' => 'text/xml;charset=UTF-8'
  41. ]]);
  42. $this->assertEqual('xml', $response->type());
  43. $this->assertEqual('UTF-8', $response->encoding);
  44. $response = new Response(['headers' => [
  45. 'Content-Type' => 'application/soap+xml; charset=iso-8859-1'
  46. ]]);
  47. $this->assertEqual('xml', $response->type());
  48. $this->assertEqual('ISO-8859-1', $response->encoding);
  49. // Content type WITHOUT space between type and charset
  50. $response = new Response(['headers' => [
  51. 'Content-Type' => 'application/json;charset=iso-8859-1'
  52. ]]);
  53. $this->assertEqual('json', $response->type());
  54. $this->assertEqual('ISO-8859-1', $response->encoding);
  55. // Content type WITH ONE space between type and charset
  56. $response = new Response(['headers' => [
  57. 'Content-Type' => 'application/json; charset=iso-8859-1'
  58. ]]);
  59. $this->assertEqual('json', $response->type());
  60. $this->assertEqual('ISO-8859-1', $response->encoding);
  61. $response = new Response(['headers' => [
  62. 'Content-Type' => 'application/json; charset=iso-8859-1'
  63. ]]);
  64. $this->assertEqual('json', $response->type());
  65. $this->assertEqual('ISO-8859-1', $response->encoding);
  66. }
  67. public function testParsingContentTypeWithoutEncoding() {
  68. $response = new Response(['headers' => [
  69. 'Content-Type' => 'application/json'
  70. ]]);
  71. $this->assertEqual('json', $response->type());
  72. $this->assertEqual('UTF-8', $response->encoding); //default
  73. }
  74. public function testParsingContentTypeWithVersionNumber() {
  75. $response = new Response(['headers' => [
  76. 'Content-Type' => 'application/x-amz-json-1.0'
  77. ]]);
  78. $this->assertEqual('application/x-amz-json-1.0', $response->type());
  79. }
  80. public function testConstructionWithBody() {
  81. $response = new Response(['message' => "Content-type: image/jpeg\r\n\r\nimage data"]);
  82. $this->assertEqual("image data", $response->body());
  83. $response = new Response(['body' => "image data"]);
  84. $this->assertEqual("image data", $response->body());
  85. }
  86. public function testParseMessage() {
  87. $message = join("\r\n", [
  88. 'HTTP/1.1 404 Not Found',
  89. 'Header: Value',
  90. 'Connection: close',
  91. 'Content-Type: text/plain;charset=ISO-8859-1',
  92. '',
  93. 'Test!'
  94. ]);
  95. $response = new Response(compact('message'));
  96. $this->assertEqual($message, (string) $response);
  97. $this->assertEqual('text', $response->type());
  98. $this->assertEqual('ISO-8859-1', $response->encoding);
  99. $this->assertEqual('404', $response->status['code']);
  100. $this->assertEqual('Not Found', $response->status['message']);
  101. $this->assertEqual('HTTP/1.1 404 Not Found', $response->status());
  102. $body = 'Not a Message';
  103. $expected = join("\r\n", ['HTTP/1.1 200 OK', '', '', 'Not a Message']);
  104. $response = new Response(compact('body'));
  105. $this->assertEqual($expected, (string) $response);
  106. }
  107. public function testParseMessageWithRepeatingHeaderKeys() {
  108. $message = join("\r\n", [
  109. 'HTTP/1.1 200 OK',
  110. 'Connection: close',
  111. 'Content-Type: text/plain;charset=UTF8',
  112. 'Header: value1',
  113. 'Header: value2',
  114. '',
  115. 'Test!'
  116. ]);
  117. $header = ['value1', 'value2'];
  118. $response = new Response(compact('message'));
  119. $this->assertEqual($header, $response->headers('Header'));
  120. $this->assertEqual($message, (string) $response);
  121. }
  122. public function testParseMessageWithCookies() {
  123. $message = join("\r\n", [
  124. 'HTTP/1.1 200 OK',
  125. 'Connection: close',
  126. 'Content-Type: text/plain;charset=UTF8',
  127. 'Set-Cookie: doctor=who; Path=/tardis; HttpOnly',
  128. 'Set-Cookie: test=foo%20bar; Expires=Tue, 15-Jan-2013 21:47:38 GMT; Secure',
  129. 'Set-Cookie: test=foo%2Bbin; Path=/test; Domain=li3.me',
  130. '',
  131. 'Test!'
  132. ]);
  133. $cookies = [
  134. 'doctor' => ['value' => 'who', 'path' => '/tardis', 'httponly' => true],
  135. 'test' => [
  136. ['value' => 'foo bar', 'expires' => 1358286458, 'secure' => true],
  137. ['value' => 'foo+bin', 'path' => '/test', 'domain' => 'li3.me']
  138. ]
  139. ];
  140. $response = new Response(compact('message'));
  141. $this->assertEqual($cookies, $response->cookies());
  142. $this->assertEqual($message, (string) $response);
  143. }
  144. public function testParseMessageWithContentTypeHeaderSetsType() {
  145. $response = new Response([
  146. 'message' => join("\r\n", [
  147. 'HTTP/1.1 200 OK',
  148. 'Content-Type: text/x-test-a',
  149. '',
  150. 'foo!'
  151. ])
  152. ]);
  153. $this->assertEqual('text/x-test-a', $response->headers('Content-Type'));
  154. }
  155. public function testContentTypeHeaderAndTypePropertyAreSynchronized() {
  156. $response = new Response([
  157. 'message' => "Content-type: text/x-test-a\r\n\r\nfoo"
  158. ]);
  159. $this->assertEqual($response->type(), $response->headers('Content-Type'));
  160. $response = new Response([
  161. 'headers' => ['Content-Type' => 'text/x-test-a']
  162. ]);
  163. $this->assertEqual($response->type(), $response->headers('Content-Type'));
  164. $response = new Response([
  165. 'type' => 'text/x-test-a'
  166. ]);
  167. $this->assertEqual($response->type(), $response->headers('Content-Type'));
  168. }
  169. public function testParseMessageHeadersMerging() {
  170. $response = new Response([
  171. 'message' => "Content-type: text/x-test-a\r\nX-Test-A: foo\r\n\r\nfoo",
  172. 'headers' => [
  173. 'Content-Type' => 'text/x-test-b',
  174. 'X-Test-B' => 'bar'
  175. ]
  176. ]);
  177. $expected = [
  178. 'Content-Type: text/x-test-b',
  179. 'X-Test-B: bar',
  180. 'X-Test-A: foo'
  181. ];
  182. $this->assertEqual($expected, $response->headers());
  183. }
  184. public function testEmptyResponse() {
  185. $response = new Response(['message' => "\n"]);
  186. $result = trim((string) $response);
  187. $expected = 'HTTP/1.1 200 OK';
  188. $this->assertEqual($expected, $result);
  189. }
  190. public function testToString() {
  191. $expected = join("\r\n", [
  192. 'HTTP/1.1 200 OK',
  193. 'Header: Value',
  194. 'Connection: close',
  195. 'Content-Type: text/html;charset=UTF-8',
  196. '',
  197. 'Test!'
  198. ]);
  199. $config = [
  200. 'protocol' => 'HTTP/1.1',
  201. 'version' => '1.1',
  202. 'status' => ['code' => '200', 'message' => 'OK'],
  203. 'headers' => [
  204. 'Header' => 'Value',
  205. 'Connection' => 'close',
  206. 'Content-Type' => 'text/html;charset=UTF-8'
  207. ],
  208. 'type' => 'text/html',
  209. 'encoding' => 'UTF-8',
  210. 'body' => 'Test!'
  211. ];
  212. $response = new Response($config);
  213. $this->assertEqual($expected, (string) $response);
  214. }
  215. public function testToStringWithCookies() {
  216. $expected = join("\r\n", [
  217. 'HTTP/1.1 200 OK',
  218. 'Connection: close',
  219. 'Content-Type: text/html;charset=UTF-8',
  220. 'Set-Cookie: Name=Marty%20McFly; Domain=.hillvalley.us; Secure',
  221. 'Set-Cookie: Destination=The%20Future; Expires=Wed, 21-Oct-2015 23:29:00 GMT',
  222. '',
  223. 'Great Scott!'
  224. ]);
  225. $config = [
  226. 'protocol' => 'HTTP/1.1',
  227. 'version' => '1.1',
  228. 'status' => ['code' => '200', 'message' => 'OK'],
  229. 'headers' => [
  230. 'Connection' => 'close',
  231. 'Content-Type' => 'text/html;charset=UTF-8'
  232. ],
  233. 'cookies' => [
  234. 'Name' => ['value' => 'Marty McFly', 'domain' => '.hillvalley.us', 'secure' => true],
  235. 'Destination' => ['value' => 'The Future', 'expires' => 'Oct 21 2015 4:29 PM PDT']
  236. ],
  237. 'type' => 'text/html',
  238. 'encoding' => 'UTF-8',
  239. 'body' => 'Great Scott!'
  240. ];
  241. $response = new Response($config);
  242. $this->assertEqual($expected, (string) $response);
  243. }
  244. public function testToStringDoesNotAddContentTypeHeaderOnTextHtml() {
  245. $response = new Response();
  246. $expected = "HTTP/1.1 200 OK\r\n\r\n\r\n";
  247. $result = (string) $response;
  248. $this->assertEqual($expected, $result);
  249. /* Decide what to do with this */
  250. return "Is this test correct?";
  251. $response = new Response();
  252. $response->type('text/html');
  253. $expected = "HTTP/1.1 200 OK\r\n\r\n\r\n";
  254. $result = (string) $response;
  255. $this->assertEqual($expected, $result);
  256. $response = new Response();
  257. $response->type('text/plain');
  258. $expected = "HTTP/1.1 200 OK\r\nContent-Type: text/plain;charset=UTF-8\r\n\r\n";
  259. $result = (string) $response;
  260. $this->assertEqual($expected, $result);
  261. }
  262. public function testToStringTypeAlwaysUsesContentTypeHeader() {
  263. $response = new Response();
  264. $response->headers('Content-Type', 'text/html');
  265. $expected = "HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=UTF-8\r\n\r\n";
  266. $result = (string) $response;
  267. $this->assertEqual($expected, $result);
  268. $response = new Response();
  269. $response->headers('Content-Type', 'text/plain');
  270. $expected = "HTTP/1.1 200 OK\r\nContent-Type: text/plain;charset=UTF-8\r\n\r\n";
  271. $result = (string) $response;
  272. $this->assertEqual($expected, $result);
  273. }
  274. public function testToStringPrefersHeadersContentTypeOverType() {
  275. /* Decide what to do with this */
  276. return "Is this test correct?";
  277. $response = new Response();
  278. $response->headers('Content-Type', 'text/plain');
  279. $response->type('text/html');
  280. $expected = "HTTP/1.1 200 OK\r\nContent-Type: text/plain;charset=UTF-8\r\n\r\n";
  281. $result = (string) $response;
  282. $this->assertEqual($expected, $result);
  283. }
  284. public function testTransferEncodingChunkedDecode() {
  285. $headers = join("\r\n", [
  286. 'HTTP/1.1 200 OK',
  287. 'Server: CouchDB/0.10.0 (Erlang OTP/R13B)',
  288. 'Etag: "DWGTHR79JLSOGACPLVIZBJUBP"',
  289. 'Date: Wed, 11 Nov 2009 19:49:41 GMT',
  290. 'Content-Type: text/plain;charset=utf-8',
  291. 'Cache-Control: must-revalidate',
  292. 'Transfer-Encoding: chunked',
  293. 'Connection: Keep-alive',
  294. '',
  295. ''
  296. ]);
  297. $message = $headers . join("\r\n", [
  298. 'b7',
  299. '{"total_rows":1,"offset":0,"rows":[',
  300. '{"id":"88989cafcd81b09f81078eb523832e8e","key":"gwoo","value":' .
  301. '{"author":"gwoo","language":"php","preview":"test",' .
  302. '"created":"2009-10-27 12:14:12"}}',
  303. '4',
  304. '',
  305. ']}',
  306. '1',
  307. '',
  308. '',
  309. ''
  310. ]);
  311. $response = new Response(compact('message'));
  312. $expected = join("\r\n", [
  313. '{"total_rows":1,"offset":0,"rows":[',
  314. '{"id":"88989cafcd81b09f81078eb523832e8e","key":"gwoo","value":' .
  315. '{"author":"gwoo","language":"php","preview":"test",' .
  316. '"created":"2009-10-27 12:14:12"}}',
  317. ']}'
  318. ]);
  319. $this->assertEqual($expected, $response->body());
  320. $message = $headers . "\r\nbody";
  321. $response = new Response(compact('message'));
  322. $result = $response->body();
  323. $this->assertEqual('body', $result);
  324. $message = join("\r\n", [
  325. 'HTTP/1.1 200 OK',
  326. 'Header: Value',
  327. 'Connection: close',
  328. 'Content-Type: text/html;charset=UTF-8',
  329. 'Transfer-Encoding: text',
  330. '',
  331. 'Test!'
  332. ]);
  333. $expected = 'Test!';
  334. $response = new Response(compact('message'));
  335. $result = $response->body();
  336. $this->assertEqual($expected, $result);
  337. $expected = '1+1 is 2, 10%40 is 20.';
  338. $message = $headers . join("\r\n", [
  339. '22',
  340. $expected,
  341. '',
  342. ]);
  343. $response = new Response(compact('message'));
  344. $result = $response->body();
  345. $this->assertEqual($expected, $result);
  346. }
  347. public function testTypePriority() {
  348. /* Decide what to do with this */
  349. return "Is this test correct?";
  350. $response = new Response([
  351. 'message' => "Content-type: text/x-test-a\r\n\r\nfoo",
  352. 'type' => 'text/x-test-b',
  353. 'headers' => ['Content-Type' => 'text/x-test-c']
  354. ]);
  355. $this->assertEqual('text/x-test-c', $response->type());
  356. $response = new Response([
  357. 'message' => "Content-type: text/x-test-a\r\n\r\nfoo",
  358. 'type' => 'text/x-test-b'
  359. ]);
  360. $this->assertEqual('text/x-test-b', $response->type());
  361. }
  362. public function testTypeHeader() {
  363. $response = new Response(['type' => 'application/json']);
  364. $result = (string) $response;
  365. $this->assertPattern('/^HTTP\/1\.1 200 OK/', $result);
  366. $this->assertPattern('/Content-Type: application\/json(.*)$/ms', $result);
  367. }
  368. /**
  369. * Creates a chunked gzipped message to test response decoding.
  370. *
  371. * @param string $body Message body.
  372. * @param array $headers Message headers.
  373. * @return string Returns a raw HTTP message with headers and body.
  374. */
  375. protected function _createMessage($body, array $headers = []) {
  376. $headers += [
  377. 'Connection: close',
  378. 'Content-Encoding: gzip',
  379. 'Content-Type: text/html; charset=ISO-8859-15',
  380. 'Server: Apache/2.2.16 (Debian) mod_ssl/2.2.16 OpenSSL/0.9.8o',
  381. 'Transfer-Encoding: chunked',
  382. 'Vary: Accept-Encoding'
  383. ];
  384. return join("\r\n", $headers) . "\r\n\r\n" . $body;
  385. }
  386. public function testWithoutChunksAndComment() {
  387. $body = "\n<html>\n <head>\n <title>Simple site</title>\n </head>\n";
  388. $body .= "<body>\n <h1>Simple site</h1>\n <p>\n But awesome\n";
  389. $body .= " </p>\n </body>\n</html>\n";
  390. $message = $this->_createMessage($body);
  391. $response = new Response(compact('message'));
  392. $this->assertEqual(trim($body), $response->body());
  393. }
  394. public function testWithoutChunksAndCommentInBody() {
  395. $body = "\n<html>\n <head>\n <title>Simple site</title>\n </head>";
  396. $body .= "\n <body>\n <!-- (c) 1998 - 2012 Tweakers.net B.V. --> ";
  397. $body .= "\n <h1>Simple site</h1>\n <p>\n But awesome";
  398. $body .= "\n </p>\n </body>\n</html>\n";
  399. $message = $this->_createMessage($body);
  400. $response = new Response(compact('message'));
  401. $this->assertEqual(trim($body), $response->body());
  402. }
  403. public function testWithoutChunksAndRandomCommentInHtmlRoot() {
  404. $body = "\n<html><!-- This is some random comment -->\n <head>";
  405. $body .= "\n <title>Simple site</title>\n </head>\n <body>";
  406. $body .= "\n <h1>Simple site</h1>\n <p>\n But awesome";
  407. $body .= "\n </p>\n </body>\n</html>\n";
  408. $message = $this->_createMessage($body);
  409. $response = new Response(compact('message'));
  410. $this->assertEqual(trim($body), $response->body());
  411. }
  412. public function testWithoutChunksAndCommentInHtmlRoot() {
  413. $body = "\n<!doctype html><!-- (c) 1998 - 2012 Tweakers.net B.V. --> \n<html lang=\"nl\"> ";
  414. $body .= "\n <head>\n <title>Simple site</title>\n </head>";
  415. $body .= "\n <body>\n <h1>Simple site</h1>\n <p>\n But awesome";
  416. $body .= "\n </p>\n </body>\n</html>\n";
  417. $message = $this->_createMessage($body);
  418. $response = new Response(compact('message'));
  419. $this->assertEqual(trim($body), $response->body());
  420. }
  421. public function testMessageWithNoHeaders() {
  422. $body = "\n<html>...</html>\n";
  423. $message = "\r\n\r\n{$body}";
  424. $response = new Response(compact('message'));
  425. $this->assertEmpty($response->headers());
  426. $this->assertEqual(trim($body), $response->body());
  427. }
  428. public function testDigestParsing() {
  429. $auth = 'Digest realm="app",';
  430. $auth .= 'qop="auth",nonce="4ee1617b8756e",opaque="dd7bcee161192cb8fba765eb595eba87"';
  431. $headers = ["WWW-Authenticate" => $auth];
  432. $response = new Response(compact('headers'));
  433. $expected = ["WWW-Authenticate" => $auth];
  434. $result = $response->headers;
  435. $this->assertEqual($expected, $result);
  436. $expected = [
  437. 'realm' => 'app', 'qop' => 'auth', 'nonce' => '4ee1617b8756e',
  438. 'opaque' => 'dd7bcee161192cb8fba765eb595eba87'
  439. ];
  440. $result = array_filter($response->digest());
  441. $this->assertEqual($expected, $result);
  442. }
  443. public function testSetCookies() {
  444. $expected = [
  445. 'foo' => ['value' => 'bar'],
  446. 'bin' => ['value' => 'baz', 'path' => '/app', 'domain' => 'li3.me', 'httponly' => true]
  447. ];
  448. $response = new Response();
  449. $response->cookies('foo', 'bar');
  450. $response->cookies('bin', [
  451. 'value' => 'baz', 'path' => '/app', 'domain' => 'li3.me', 'httponly' => true
  452. ]);
  453. $result = $response->cookies;
  454. $this->assertEqual($expected, $result);
  455. $response = new Response();
  456. $response->cookies('foo', 'bar');
  457. $response->cookies([
  458. 'bin' => ['value' => 'baz', 'path' => '/app', 'domain' => 'li3.me', 'httponly' => true]
  459. ]);
  460. $result = $response->cookies;
  461. $this->assertEqual($expected, $result);
  462. $response = new Response();
  463. $response->cookies([
  464. 'foo' => 'bar',
  465. 'bin' => ['value' => 'baz', 'path' => '/app', 'domain' => 'li3.me', 'httponly' => true]
  466. ]);
  467. $result = $response->cookies;
  468. $this->assertEqual($expected, $result);
  469. $result = $response->cookies();
  470. $this->assertEqual($expected, $result);
  471. $expected = ['value' => 'bar'];
  472. $result = $response->cookies('foo');
  473. $this->assertEqual($expected, $result);
  474. $expected = ['value' => 'baz', 'path' => '/app', 'domain' => 'li3.me', 'httponly' => true];
  475. $result = $response->cookies('bin');
  476. $this->assertEqual($expected, $result);
  477. $result = $response->cookies('bla');
  478. $this->assertNull($result);
  479. }
  480. public function testSetCookiesMultipleValues() {
  481. $response = new Response();
  482. $response->cookies(['foo' => 'bar', 'bin' => 'baz']);
  483. $response->cookies('foo', ['value' => 'bin', 'path' => '/foo']);
  484. $expected = [
  485. 'foo' => [
  486. ['value' => 'bar'],
  487. ['value' => 'bin', 'path' => '/foo']
  488. ],
  489. 'bin' => ['value' => 'baz']
  490. ];
  491. $result = $response->cookies;
  492. $this->assertEqual($expected, $result);
  493. $response = new Response();
  494. $response->cookies([
  495. 'foo' => [
  496. 'bar',
  497. ['value' => 'bin', 'path' => '/foo']
  498. ],
  499. 'bin' => 'baz'
  500. ]);
  501. $result = $response->cookies;
  502. $this->assertEqual($expected, $result);
  503. }
  504. public function testMalformedStatus() {
  505. $expected = "HTTP/1.1 304 Not Modified";
  506. $message = join("\r\n", [
  507. 'HTTP/1.1 304',
  508. 'Header: Value',
  509. 'Connection: close',
  510. 'Content-Type: application/json;charset=iso-8859-1',
  511. '',
  512. 'Test!'
  513. ]);
  514. $response = new Response(compact('message'));
  515. $result = $response->status();
  516. $this->assertEqual($expected, $result);
  517. $expected = "HTTP/1.1 500 Internal Server Error";
  518. $message = join("\r\n", [
  519. 'HTTP/1.1 500',
  520. 'Header: Value',
  521. 'Connection: close',
  522. 'Content-Type: application/json;charset=iso-8859-1',
  523. '',
  524. 'Test!'
  525. ]);
  526. $response = new Response(compact('message'));
  527. $result = $response->status();
  528. $this->assertEqual($expected, $result);
  529. }
  530. }
  531. ?>