ResponseTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2013, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\tests\cases\net\http;
  9. use lithium\net\http\Response;
  10. class ResponseTest extends \lithium\test\Unit {
  11. public function testStatus() {
  12. $response = new Response();
  13. $expected = 'HTTP/1.1 500 Internal Server Error';
  14. $result = $response->status(500);
  15. $this->assertEqual($expected, $result);
  16. $expected = 'HTTP/1.1 500 Internal Server Error';
  17. $result = $response->status('500');
  18. $this->assertEqual($expected, $result);
  19. $expected = 'HTTP/1.1 500 Internal Server Error';
  20. $result = $response->status('Internal Server Error');
  21. $this->assertEqual($expected, $result);
  22. $expected = 500;
  23. $result = $response->status('code', 'Internal Server Error');
  24. $this->assertEqual($expected, $result);
  25. $expected = 'Internal Server Error';
  26. $result = $response->status('message', 500);
  27. $this->assertEqual($expected, $result);
  28. $expected = 'HTTP/1.1 500 Internal Server Error';
  29. $result = $response->status();
  30. $this->assertEqual($expected, $result);
  31. $expected = 'HTTP/1.1 303 See Other';
  32. $result = $response->status('See Other');
  33. $this->assertEqual($expected, $result);
  34. $result = $response->status('foobar');
  35. $this->assertFalse($result);
  36. }
  37. public function testParsingContentTypeWithEncoding() {
  38. $response = new Response(array('headers' => array(
  39. 'Content-Type' => 'text/xml;charset=UTF-8'
  40. )));
  41. $this->assertEqual('xml', $response->type());
  42. $this->assertEqual('UTF-8', $response->encoding);
  43. $response = new Response(array('headers' => array(
  44. 'Content-Type' => 'application/soap+xml; charset=iso-8859-1'
  45. )));
  46. $this->assertEqual('xml', $response->type());
  47. $this->assertEqual('ISO-8859-1', $response->encoding);
  48. // Content type WITHOUT space between type and charset
  49. $response = new Response(array('headers' => array(
  50. 'Content-Type' => 'application/json;charset=iso-8859-1'
  51. )));
  52. $this->assertEqual('json', $response->type());
  53. $this->assertEqual('ISO-8859-1', $response->encoding);
  54. // Content type WITH ONE space between type and charset
  55. $response = new Response(array('headers' => array(
  56. 'Content-Type' => 'application/json; charset=iso-8859-1'
  57. )));
  58. $this->assertEqual('json', $response->type());
  59. $this->assertEqual('ISO-8859-1', $response->encoding);
  60. $response = new Response(array('headers' => array(
  61. 'Content-Type' => 'application/json; charset=iso-8859-1'
  62. )));
  63. $this->assertEqual('json', $response->type());
  64. $this->assertEqual('ISO-8859-1', $response->encoding);
  65. }
  66. public function testParsingContentTypeWithoutEncoding() {
  67. $response = new Response(array('headers' => array(
  68. 'Content-Type' => 'application/json'
  69. )));
  70. $this->assertEqual('json', $response->type());
  71. $this->assertEqual('UTF-8', $response->encoding); //default
  72. }
  73. public function testParsingContentTypeWithVersionNumber() {
  74. $response = new Response(array('headers' => array(
  75. 'Content-Type' => 'application/x-amz-json-1.0'
  76. )));
  77. $this->assertEqual('application/x-amz-json-1.0', $response->type());
  78. }
  79. public function testConstructionWithBody() {
  80. $response = new Response(array('message' => "Content-type: image/jpeg\r\n\r\nimage data"));
  81. $this->assertEqual("image data", $response->body());
  82. $response = new Response(array('body' => "image data"));
  83. $this->assertEqual("image data", $response->body());
  84. }
  85. public function testParseMessage() {
  86. $message = join("\r\n", array(
  87. 'HTTP/1.1 404 Not Found',
  88. 'Header: Value',
  89. 'Connection: close',
  90. 'Content-Type: text/plain;charset=ISO-8859-1',
  91. '',
  92. 'Test!'
  93. ));
  94. $response = new Response(compact('message'));
  95. $this->assertEqual($message, (string) $response);
  96. $this->assertEqual('text', $response->type());
  97. $this->assertEqual('ISO-8859-1', $response->encoding);
  98. $this->assertEqual('404', $response->status['code']);
  99. $this->assertEqual('Not Found', $response->status['message']);
  100. $this->assertEqual('HTTP/1.1 404 Not Found', $response->status());
  101. $body = 'Not a Message';
  102. $expected = join("\r\n", array('HTTP/1.1 200 OK', '', '', 'Not a Message'));
  103. $response = new Response(compact('body'));
  104. $this->assertEqual($expected, (string) $response);
  105. }
  106. public function testParseMessageWithContentTypeHeaderSetsType() {
  107. $response = new Response(array(
  108. 'message' => join("\r\n", array(
  109. 'HTTP/1.1 200 OK',
  110. 'Content-Type: text/x-test-a',
  111. '',
  112. 'foo!'
  113. ))
  114. ));
  115. $this->assertEqual('text/x-test-a', $response->headers('Content-Type'));
  116. }
  117. public function testContentTypeHeaderAndTypePropertyAreSynchronized() {
  118. $response = new Response(array(
  119. 'message' => "Content-type: text/x-test-a\r\n\r\nfoo"
  120. ));
  121. $this->assertEqual($response->type(), $response->headers('Content-Type'));
  122. $response = new Response(array(
  123. 'headers' => array('Content-Type' => 'text/x-test-a')
  124. ));
  125. $this->assertEqual($response->type(), $response->headers('Content-Type'));
  126. $response = new Response(array(
  127. 'type' => 'text/x-test-a'
  128. ));
  129. $this->assertEqual($response->type(), $response->headers('Content-Type'));
  130. }
  131. public function testParseMessageHeadersMerging() {
  132. $response = new Response(array(
  133. 'message' => "Content-type: text/x-test-a\r\nX-Test-A: foo\r\n\r\nfoo",
  134. 'headers' => array(
  135. 'Content-Type' => 'text/x-test-b',
  136. 'X-Test-B' => 'bar'
  137. )
  138. ));
  139. $expected = array(
  140. 'Content-Type: text/x-test-b',
  141. 'X-Test-B: bar',
  142. 'X-Test-A: foo'
  143. );
  144. $this->assertEqual($expected, $response->headers());
  145. }
  146. public function testEmptyResponse() {
  147. $response = new Response(array('message' => "\n"));
  148. $result = trim((string) $response);
  149. $expected = 'HTTP/1.1 200 OK';
  150. $this->assertEqual($expected, $result);
  151. }
  152. public function testToString() {
  153. $expected = join("\r\n", array(
  154. 'HTTP/1.1 200 OK',
  155. 'Header: Value',
  156. 'Connection: close',
  157. 'Content-Type: text/html;charset=UTF-8',
  158. '',
  159. 'Test!'
  160. ));
  161. $config = array(
  162. 'protocol' => 'HTTP/1.1',
  163. 'version' => '1.1',
  164. 'status' => array('code' => '200', 'message' => 'OK'),
  165. 'headers' => array(
  166. 'Header' => 'Value',
  167. 'Connection' => 'close',
  168. 'Content-Type' => 'text/html;charset=UTF-8'
  169. ),
  170. 'type' => 'text/html',
  171. 'encoding' => 'UTF-8',
  172. 'body' => 'Test!'
  173. );
  174. $response = new Response($config);
  175. $this->assertEqual($expected, (string) $response);
  176. }
  177. public function testToStringDoesNotAddContentTypeHeaderOnTextHtml() {
  178. $response = new Response();
  179. $expected = "HTTP/1.1 200 OK\r\n\r\n\r\n";
  180. $result = (string) $response;
  181. $this->assertEqual($expected, $result);
  182. /* Decide what to do with this */
  183. return "Is this test correct?";
  184. $response = new Response();
  185. $response->type('text/html');
  186. $expected = "HTTP/1.1 200 OK\r\n\r\n\r\n";
  187. $result = (string) $response;
  188. $this->assertEqual($expected, $result);
  189. $response = new Response();
  190. $response->type('text/plain');
  191. $expected = "HTTP/1.1 200 OK\r\nContent-Type: text/plain;charset=UTF-8\r\n\r\n";
  192. $result = (string) $response;
  193. $this->assertEqual($expected, $result);
  194. }
  195. public function testToStringTypeAlwaysUsesContentTypeHeader() {
  196. $response = new Response();
  197. $response->headers('Content-Type', 'text/html');
  198. $expected = "HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=UTF-8\r\n\r\n";
  199. $result = (string) $response;
  200. $this->assertEqual($expected, $result);
  201. $response = new Response();
  202. $response->headers('Content-Type', 'text/plain');
  203. $expected = "HTTP/1.1 200 OK\r\nContent-Type: text/plain;charset=UTF-8\r\n\r\n";
  204. $result = (string) $response;
  205. $this->assertEqual($expected, $result);
  206. }
  207. public function testToStringPrefersHeadersContentTypeOverType() {
  208. /* Decide what to do with this */
  209. return "Is this test correct?";
  210. $response = new Response();
  211. $response->headers('Content-Type', 'text/plain');
  212. $response->type('text/html');
  213. $expected = "HTTP/1.1 200 OK\r\nContent-Type: text/plain;charset=UTF-8\r\n\r\n";
  214. $result = (string) $response;
  215. $this->assertEqual($expected, $result);
  216. }
  217. public function testTransferEncodingChunkedDecode() {
  218. $headers = join("\r\n", array(
  219. 'HTTP/1.1 200 OK',
  220. 'Server: CouchDB/0.10.0 (Erlang OTP/R13B)',
  221. 'Etag: "DWGTHR79JLSOGACPLVIZBJUBP"',
  222. 'Date: Wed, 11 Nov 2009 19:49:41 GMT',
  223. 'Content-Type: text/plain;charset=utf-8',
  224. 'Cache-Control: must-revalidate',
  225. 'Transfer-Encoding: chunked',
  226. 'Connection: Keep-alive',
  227. '',
  228. ''
  229. ));
  230. $message = $headers . join("\r\n", array(
  231. 'b7',
  232. '{"total_rows":1,"offset":0,"rows":[',
  233. '{"id":"88989cafcd81b09f81078eb523832e8e","key":"gwoo","value":' .
  234. '{"author":"gwoo","language":"php","preview":"test",' .
  235. '"created":"2009-10-27 12:14:12"}}',
  236. '4',
  237. '',
  238. ']}',
  239. '1',
  240. '',
  241. '',
  242. ''
  243. ));
  244. $response = new Response(compact('message'));
  245. $expected = join("\r\n", array(
  246. '{"total_rows":1,"offset":0,"rows":[',
  247. '{"id":"88989cafcd81b09f81078eb523832e8e","key":"gwoo","value":' .
  248. '{"author":"gwoo","language":"php","preview":"test",' .
  249. '"created":"2009-10-27 12:14:12"}}',
  250. ']}'
  251. ));
  252. $this->assertEqual($expected, $response->body());
  253. $message = $headers . "\r\nbody";
  254. $response = new Response(compact('message'));
  255. $result = $response->body();
  256. $this->assertEqual('body', $result);
  257. $message = join("\r\n", array(
  258. 'HTTP/1.1 200 OK',
  259. 'Header: Value',
  260. 'Connection: close',
  261. 'Content-Type: text/html;charset=UTF-8',
  262. 'Transfer-Encoding: text',
  263. '',
  264. 'Test!'
  265. ));
  266. $expected = 'Test!';
  267. $response = new Response(compact('message'));
  268. $result = $response->body();
  269. $this->assertEqual($expected, $result);
  270. }
  271. public function testTypePriority() {
  272. /* Decide what to do with this */
  273. return "Is this test correct?";
  274. $response = new Response(array(
  275. 'message' => "Content-type: text/x-test-a\r\n\r\nfoo",
  276. 'type' => 'text/x-test-b',
  277. 'headers' => array('Content-Type' => 'text/x-test-c')
  278. ));
  279. $this->assertEqual('text/x-test-c', $response->type());
  280. $response = new Response(array(
  281. 'message' => "Content-type: text/x-test-a\r\n\r\nfoo",
  282. 'type' => 'text/x-test-b'
  283. ));
  284. $this->assertEqual('text/x-test-b', $response->type());
  285. }
  286. public function testTypeHeader() {
  287. $response = new Response(array('type' => 'application/json'));
  288. $result = (string) $response;
  289. $this->assertPattern('/^HTTP\/1\.1 200 OK/', $result);
  290. $this->assertPattern('/Content-Type: application\/json(.*)$/ms', $result);
  291. }
  292. /**
  293. * Creates a chunked gzipped message to test response decoding.
  294. *
  295. * @param string $body Message body.
  296. * @param array $headers Message headers.
  297. * @return string Returns a raw HTTP message with headers and body.
  298. */
  299. protected function _createMessage($body, array $headers = array()) {
  300. $headers += array(
  301. 'Connection: close',
  302. 'Content-Encoding: gzip',
  303. 'Content-Type: text/html; charset=ISO-8859-15',
  304. 'Server: Apache/2.2.16 (Debian) mod_ssl/2.2.16 OpenSSL/0.9.8o',
  305. 'Transfer-Encoding: chunked',
  306. 'Vary: Accept-Encoding'
  307. );
  308. return join("\r\n", $headers) . "\r\n\r\n" . $body;
  309. }
  310. public function testWithoutChunksAndComment() {
  311. $body = "\n<html>\n <head>\n <title>Simple site</title>\n </head>\n";
  312. $body .= "<body>\n <h1>Simple site</h1>\n <p>\n But awesome\n";
  313. $body .= " </p>\n </body>\n</html>\n";
  314. $message = $this->_createMessage($body);
  315. $response = new Response(compact('message'));
  316. $this->assertEqual(trim($body), $response->body());
  317. }
  318. public function testWithoutChunksAndCommentInBody() {
  319. $body = "\n<html>\n <head>\n <title>Simple site</title>\n </head>";
  320. $body .= "\n <body>\n <!-- (c) 1998 - 2012 Tweakers.net B.V. --> ";
  321. $body .= "\n <h1>Simple site</h1>\n <p>\n But awesome";
  322. $body .= "\n </p>\n </body>\n</html>\n";
  323. $message = $this->_createMessage($body);
  324. $response = new Response(compact('message'));
  325. $this->assertEqual(trim($body), $response->body());
  326. }
  327. public function testWithoutChunksAndRandomCommentInHtmlRoot() {
  328. $body = "\n<html><!-- This is some random comment -->\n <head>";
  329. $body .= "\n <title>Simple site</title>\n </head>\n <body>";
  330. $body .= "\n <h1>Simple site</h1>\n <p>\n But awesome";
  331. $body .= "\n </p>\n </body>\n</html>\n";
  332. $message = $this->_createMessage($body);
  333. $response = new Response(compact('message'));
  334. $this->assertEqual(trim($body), $response->body());
  335. }
  336. public function testWithoutChunksAndCommentInHtmlRoot() {
  337. $body = "\n<!doctype html><!-- (c) 1998 - 2012 Tweakers.net B.V. --> \n<html lang=\"nl\"> ";
  338. $body .= "\n <head>\n <title>Simple site</title>\n </head>";
  339. $body .= "\n <body>\n <h1>Simple site</h1>\n <p>\n But awesome";
  340. $body .= "\n </p>\n </body>\n</html>\n";
  341. $message = $this->_createMessage($body);
  342. $response = new Response(compact('message'));
  343. $this->assertEqual(trim($body), $response->body());
  344. }
  345. public function testMessageWithNoHeaders() {
  346. $body = "\n<html>...</html>\n";
  347. $message = "\r\n\r\n{$body}";
  348. $response = new Response(compact('message'));
  349. $this->assertFalse($response->headers());
  350. $this->assertEqual(trim($body), $response->body());
  351. }
  352. public function testDigestParsing() {
  353. $auth = 'Digest realm="app",';
  354. $auth .= 'qop="auth",nonce="4ee1617b8756e",opaque="dd7bcee161192cb8fba765eb595eba87"';
  355. $headers = array("WWW-Authenticate" => $auth);
  356. $response = new Response(compact('headers'));
  357. $expected = array("WWW-Authenticate" => $auth);
  358. $result = $response->headers;
  359. $this->assertEqual($expected, $result);
  360. $expected = array(
  361. 'realm' => 'app', 'qop' => 'auth', 'nonce' => '4ee1617b8756e',
  362. 'opaque' => 'dd7bcee161192cb8fba765eb595eba87'
  363. );
  364. $result = array_filter($response->digest());
  365. $this->assertEqual($expected, $result);
  366. }
  367. public function testMalformedStatus() {
  368. $expected = "HTTP/1.1 304 Not Modified";
  369. $message = join("\r\n", array(
  370. 'HTTP/1.1 304',
  371. 'Header: Value',
  372. 'Connection: close',
  373. 'Content-Type: application/json;charset=iso-8859-1',
  374. '',
  375. 'Test!'
  376. ));
  377. $response = new Response(compact('message'));
  378. $result = $response->status();
  379. $this->assertEqual($expected, $result);
  380. $expected = "HTTP/1.1 500 Internal Server Error";
  381. $message = join("\r\n", array(
  382. 'HTTP/1.1 500',
  383. 'Header: Value',
  384. 'Connection: close',
  385. 'Content-Type: application/json;charset=iso-8859-1',
  386. '',
  387. 'Test!'
  388. ));
  389. $response = new Response(compact('message'));
  390. $result = $response->status();
  391. $this->assertEqual($expected, $result);
  392. }
  393. }
  394. ?>