PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/ZendTest/Http/ResponseTest.php

https://github.com/venturamatthieu/zf2
PHP | 399 lines | 281 code | 69 blank | 49 comment | 0 complexity | f15df05c6dfd40d6867c0c16f19ba951 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace ZendTest\Http;
  10. use Zend\Http\Response;
  11. class ResponseTest extends \PHPUnit_Framework_TestCase
  12. {
  13. public function testResponseFactoryFromStringCreatesValidResponse()
  14. {
  15. $string = 'HTTP/1.0 200 OK' . "\r\n\r\n" . 'Foo Bar';
  16. $response = Response::fromString($string);
  17. $this->assertEquals(200, $response->getStatusCode());
  18. $this->assertEquals('Foo Bar', $response->getContent());
  19. }
  20. public function testResponseCanRenderStatusLine()
  21. {
  22. $response = new Response;
  23. $response->setVersion(1.1);
  24. $response->setStatusCode(Response::STATUS_CODE_404);
  25. $this->assertEquals('HTTP/1.1 404 Not Found', $response->renderStatusLine());
  26. $response->setReasonPhrase('Foo Bar');
  27. $this->assertEquals('HTTP/1.1 404 Foo Bar', $response->renderStatusLine());
  28. }
  29. public function testResponseUsesHeadersContainerByDefault()
  30. {
  31. $response = new Response();
  32. $this->assertInstanceOf('Zend\Http\Headers', $response->getHeaders());
  33. }
  34. public function testRequestCanSetHeaders()
  35. {
  36. $response = new Response();
  37. $headers = new \Zend\Http\Headers();
  38. $ret = $response->setHeaders($headers);
  39. $this->assertInstanceOf('Zend\Http\Response', $ret);
  40. $this->assertSame($headers, $response->getHeaders());
  41. }
  42. public function testResponseCanSetStatusCode()
  43. {
  44. $response = new Response;
  45. $this->assertEquals(200, $response->getStatusCode());
  46. $response->setStatusCode('303');
  47. $this->assertEquals(303, $response->getStatusCode());
  48. }
  49. public function testResponseSetStatusCodeThrowsExceptionOnInvalidCode()
  50. {
  51. $response = new Response;
  52. $this->setExpectedException('Zend\Http\Exception\InvalidArgumentException', 'Invalid status code');
  53. $response->setStatusCode(606);
  54. }
  55. public function testResponseGetReasonPhraseWillReturnEmptyPhraseAsDefault()
  56. {
  57. $response = new Response;
  58. $response->setCustomStatusCode(998);
  59. $this->assertSame('HTTP/1.1 998' . "\r\n\r\n", (string) $response);
  60. }
  61. public function testResponseCanSetCustomStatusCode()
  62. {
  63. $response = new Response;
  64. $this->assertEquals(200, $response->getStatusCode());
  65. $response->setCustomStatusCode('999');
  66. $this->assertEquals(999, $response->getStatusCode());
  67. }
  68. public function testResponseSetCustomStatusCodeThrowsExceptionOnInvalidCode()
  69. {
  70. $response = new Response;
  71. $this->setExpectedException(
  72. 'Zend\Http\Exception\InvalidArgumentException',
  73. 'Invalid status code provided: "foo"'
  74. );
  75. $response->setStatusCode('foo');
  76. }
  77. public function testResponseEndsAtStatusCode()
  78. {
  79. $string = 'HTTP/1.0 200' . "\r\n\r\n" . 'Foo Bar';
  80. $response = Response::fromString($string);
  81. $this->assertEquals(200, $response->getStatusCode());
  82. $this->assertEquals('Foo Bar', $response->getContent());
  83. }
  84. public function testResponseHasZeroLengthReasonPhrase()
  85. {
  86. // Space after status code is mandatory,
  87. // though, reason phrase can be empty.
  88. // @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
  89. $string = 'HTTP/1.0 200 ' . "\r\n\r\n" . 'Foo Bar';
  90. $response = Response::fromString($string);
  91. $this->assertEquals(200, $response->getStatusCode());
  92. $this->assertEquals('Foo Bar', $response->getContent());
  93. // Reason phrase would fallback to default reason phrase.
  94. $this->assertEquals('OK', $response->getReasonPhrase());
  95. }
  96. public function testGzipResponse()
  97. {
  98. $response_text = file_get_contents(__DIR__ . '/_files/response_gzip');
  99. $res = Response::fromString($response_text);
  100. $this->assertEquals('gzip', $res->getHeaders()->get('Content-encoding')->getFieldValue());
  101. $this->assertEquals('0b13cb193de9450aa70a6403e2c9902f', md5($res->getBody()));
  102. $this->assertEquals('f24dd075ba2ebfb3bf21270e3fdc5303', md5($res->getContent()));
  103. }
  104. public function testDeflateResponse()
  105. {
  106. $response_text = file_get_contents(__DIR__ . '/_files/response_deflate');
  107. $res = Response::fromString($response_text);
  108. $this->assertEquals('deflate', $res->getHeaders()->get('Content-encoding')->getFieldValue());
  109. $this->assertEquals('0b13cb193de9450aa70a6403e2c9902f', md5($res->getBody()));
  110. $this->assertEquals('ad62c21c3aa77b6a6f39600f6dd553b8', md5($res->getContent()));
  111. }
  112. /**
  113. * Make sure wer can handle non-RFC complient "deflate" responses.
  114. *
  115. * Unlike stanrdard 'deflate' response, those do not contain the zlib header
  116. * and trailer. Unfortunately some buggy servers (read: IIS) send those and
  117. * we need to support them.
  118. *
  119. * @link http://framework.zend.com/issues/browse/ZF-6040
  120. */
  121. public function testNonStandardDeflateResponseZF6040()
  122. {
  123. $this->markTestSkipped('Not correctly handling non-RFC complient "deflate" responses');
  124. $response_text = file_get_contents(__DIR__ . '/_files/response_deflate_iis');
  125. $res = Response::fromString($response_text);
  126. $this->assertEquals('deflate', $res->getHeaders()->get('Content-encoding')->getFieldValue());
  127. $this->assertEquals('d82c87e3d5888db0193a3fb12396e616', md5($res->getBody()));
  128. $this->assertEquals('c830dd74bb502443cf12514c185ff174', md5($res->getContent()));
  129. }
  130. public function testChunkedResponse()
  131. {
  132. $response_text = file_get_contents(__DIR__ . '/_files/response_chunked');
  133. $res = Response::fromString($response_text);
  134. $this->assertEquals('chunked', $res->getHeaders()->get('Transfer-encoding')->getFieldValue());
  135. $this->assertEquals('0b13cb193de9450aa70a6403e2c9902f', md5($res->getBody()));
  136. $this->assertEquals('c0cc9d44790fa2a58078059bab1902a9', md5($res->getContent()));
  137. }
  138. public function testChunkedResponseCaseInsensitiveZF5438()
  139. {
  140. $response_text = file_get_contents(__DIR__ . '/_files/response_chunked_case');
  141. $res = Response::fromString($response_text);
  142. $this->assertEquals('chunked', strtolower($res->getHeaders()->get('Transfer-encoding')->getFieldValue()));
  143. $this->assertEquals('0b13cb193de9450aa70a6403e2c9902f', md5($res->getBody()));
  144. $this->assertEquals('c0cc9d44790fa2a58078059bab1902a9', md5($res->getContent()));
  145. }
  146. public function testLineBreaksCompatibility()
  147. {
  148. $response_text_lf = $this->readResponse('response_lfonly');
  149. $res_lf = Response::fromString($response_text_lf);
  150. $response_text_crlf = $this->readResponse('response_crlf');
  151. $res_crlf = Response::fromString($response_text_crlf);
  152. $this->assertEquals($res_lf->getHeaders()->toString(), $res_crlf->getHeaders()->toString(), 'Responses headers do not match');
  153. $this->markTestIncomplete('Something is fishy with the response bodies in the test responses');
  154. $this->assertEquals($res_lf->getBody(), $res_crlf->getBody(), 'Response bodies do not match');
  155. }
  156. public function test404IsClientErrorAndNotFound()
  157. {
  158. $response_text = $this->readResponse('response_404');
  159. $response = Response::fromString($response_text);
  160. $this->assertEquals(404, $response->getStatusCode(), 'Response code is expected to be 404, but it\'s not.');
  161. $this->assertTrue($response->isClientError(), 'Response is an error, but isClientError() returned false');
  162. $this->assertFalse($response->isForbidden(), 'Response is an error, but isForbidden() returned true');
  163. $this->assertFalse($response->isInformational(), 'Response is an error, but isInformational() returned true');
  164. $this->assertTrue($response->isNotFound(), 'Response is an error, but isNotFound() returned false');
  165. $this->assertFalse($response->isOk(), 'Response is an error, but isOk() returned true');
  166. $this->assertFalse($response->isServerError(), 'Response is an error, but isServerError() returned true');
  167. $this->assertFalse($response->isRedirect(), 'Response is an error, but isRedirect() returned true');
  168. $this->assertFalse($response->isSuccess(), 'Response is an error, but isSuccess() returned true');
  169. }
  170. public function test500isError()
  171. {
  172. $response_text = $this->readResponse('response_500');
  173. $response = Response::fromString($response_text);
  174. $this->assertEquals(500, $response->getStatusCode(), 'Response code is expected to be 500, but it\'s not.');
  175. $this->assertFalse($response->isClientError(), 'Response is an error, but isClientError() returned true');
  176. $this->assertFalse($response->isForbidden(), 'Response is an error, but isForbidden() returned true');
  177. $this->assertFalse($response->isInformational(), 'Response is an error, but isInformational() returned true');
  178. $this->assertFalse($response->isNotFound(), 'Response is an error, but isNotFound() returned true');
  179. $this->assertFalse($response->isOk(), 'Response is an error, but isOk() returned true');
  180. $this->assertTrue($response->isServerError(), 'Response is an error, but isServerError() returned false');
  181. $this->assertFalse($response->isRedirect(), 'Response is an error, but isRedirect() returned true');
  182. $this->assertFalse($response->isSuccess(), 'Response is an error, but isSuccess() returned true');
  183. }
  184. /**
  185. * @group ZF-5520
  186. */
  187. public function test302LocationHeaderMatches()
  188. {
  189. $headerName = 'Location';
  190. $headerValue = 'http://www.google.com/ig?hl=en';
  191. $response = Response::fromString($this->readResponse('response_302'));
  192. $responseIis = Response::fromString($this->readResponse('response_302_iis'));
  193. $this->assertEquals($headerValue, $response->getHeaders()->get($headerName)->getFieldValue());
  194. $this->assertEquals($headerValue, $responseIis->getHeaders()->get($headerName)->getFieldValue());
  195. }
  196. public function test300isRedirect()
  197. {
  198. $response = Response::fromString($this->readResponse('response_302'));
  199. $this->assertEquals(302, $response->getStatusCode(), 'Response code is expected to be 302, but it\'s not.');
  200. $this->assertFalse($response->isClientError(), 'Response is an error, but isClientError() returned true');
  201. $this->assertFalse($response->isForbidden(), 'Response is an error, but isForbidden() returned true');
  202. $this->assertFalse($response->isInformational(), 'Response is an error, but isInformational() returned true');
  203. $this->assertFalse($response->isNotFound(), 'Response is an error, but isNotFound() returned true');
  204. $this->assertFalse($response->isOk(), 'Response is an error, but isOk() returned true');
  205. $this->assertFalse($response->isServerError(), 'Response is an error, but isServerError() returned true');
  206. $this->assertTrue($response->isRedirect(), 'Response is an error, but isRedirect() returned false');
  207. $this->assertFalse($response->isSuccess(), 'Response is an error, but isSuccess() returned true');
  208. }
  209. public function test200Ok()
  210. {
  211. $response = Response::fromString($this->readResponse('response_deflate'));
  212. $this->assertEquals(200, $response->getStatusCode(), 'Response code is expected to be 200, but it\'s not.');
  213. $this->assertFalse($response->isClientError(), 'Response is an error, but isClientError() returned true');
  214. $this->assertFalse($response->isForbidden(), 'Response is an error, but isForbidden() returned true');
  215. $this->assertFalse($response->isInformational(), 'Response is an error, but isInformational() returned true');
  216. $this->assertFalse($response->isNotFound(), 'Response is an error, but isNotFound() returned true');
  217. $this->assertTrue($response->isOk(), 'Response is an error, but isOk() returned false');
  218. $this->assertFalse($response->isServerError(), 'Response is an error, but isServerError() returned true');
  219. $this->assertFalse($response->isRedirect(), 'Response is an error, but isRedirect() returned true');
  220. $this->assertTrue($response->isSuccess(), 'Response is an error, but isSuccess() returned false');
  221. }
  222. public function test100Continue()
  223. {
  224. $this->markTestIncomplete();
  225. }
  226. public function testAutoMessageSet()
  227. {
  228. $response = Response::fromString($this->readResponse('response_403_nomessage'));
  229. $this->assertEquals(403, $response->getStatusCode(), 'Response status is expected to be 403, but it isn\'t');
  230. $this->assertEquals('Forbidden', $response->getReasonPhrase(), 'Response is 403, but message is not "Forbidden" as expected');
  231. // While we're here, make sure it's classified as error...
  232. $this->assertTrue($response->isClientError(), 'Response is an error, but isClientError() returned false');
  233. $this->assertTrue($response->isForbidden(), 'Response is an error, but isForbidden() returned false');
  234. $this->assertFalse($response->isInformational(), 'Response is an error, but isInformational() returned true');
  235. $this->assertFalse($response->isNotFound(), 'Response is an error, but isNotFound() returned true');
  236. $this->assertFalse($response->isOk(), 'Response is an error, but isOk() returned true');
  237. $this->assertFalse($response->isServerError(), 'Response is an error, but isServerError() returned true');
  238. $this->assertFalse($response->isRedirect(), 'Response is an error, but isRedirect() returned true');
  239. $this->assertFalse($response->isSuccess(), 'Response is an error, but isSuccess() returned true');
  240. }
  241. public function testToString()
  242. {
  243. $response_str = $this->readResponse('response_404');
  244. $response = Response::fromString($response_str);
  245. $this->assertEquals(strtolower(str_replace("\n", "\r\n", $response_str)), strtolower($response->toString()), 'Response convertion to string does not match original string');
  246. $this->assertEquals(strtolower(str_replace("\n", "\r\n", $response_str)), strtolower((string)$response), 'Response convertion to string does not match original string');
  247. }
  248. public function testToStringGzip()
  249. {
  250. $response_str = $this->readResponse('response_gzip');
  251. $response = Response::fromString($response_str);
  252. $this->assertEquals(strtolower($response_str), strtolower($response->toString()), 'Response convertion to string does not match original string');
  253. $this->assertEquals(strtolower($response_str), strtolower((string)$response), 'Response convertion to string does not match original string');
  254. }
  255. public function testGetHeaders()
  256. {
  257. $response = Response::fromString($this->readResponse('response_deflate'));
  258. $headers = $response->getHeaders();
  259. $this->assertEquals(8, count($headers), 'Header count is not as expected');
  260. $this->assertEquals('Apache', $headers->get('Server')->getFieldValue(), 'Server header is not as expected');
  261. $this->assertEquals('deflate', $headers->get('Content-encoding')->getFieldValue(), 'Content-type header is not as expected');
  262. }
  263. public function testGetVersion()
  264. {
  265. $response = Response::fromString($this->readResponse('response_chunked'));
  266. $this->assertEquals(1.1, $response->getVersion(), 'Version is expected to be 1.1');
  267. }
  268. public function testUnknownCode()
  269. {
  270. $response_str = $this->readResponse('response_unknown');
  271. $this->setExpectedException('InvalidArgumentException', 'Invalid status code provided: "550"');
  272. $response = Response::fromString($response_str);
  273. $this->assertEquals(550, $response->getStatusCode());
  274. }
  275. /**
  276. * @group 5253
  277. */
  278. public function testMultilineHeaderNoSpaces()
  279. {
  280. $response = Response::fromString($this->readResponse('response_multiline_header_nospace'));
  281. // Make sure we got the corrent no. of headers
  282. $this->assertEquals(6, count($response->getHeaders()), 'Header count is expected to be 6');
  283. // Check header integrity
  284. $this->assertRegexp("#timeout=15,\r\n\s+max=100#", $response->getHeaders()->get('keep-alive')->getFieldValue());
  285. $this->assertRegexp("#text/html;\s+charset=iso-8859-1#s", $response->getHeaders()->get('content-type')->getFieldValue());
  286. }
  287. public function testMultilineHeader()
  288. {
  289. $response = Response::fromString($this->readResponse('response_multiline_header'));
  290. // Make sure we got the corrent no. of headers
  291. $this->assertEquals(6, count($response->getHeaders()), 'Header count is expected to be 6');
  292. // Check header integrity
  293. $this->assertRegexp("#timeout=15,\r\n\s+max=100#", $response->getHeaders()->get('keep-alive')->getFieldValue());
  294. $this->assertRegexp("#text/html;\s+charset=iso-8859-1#s", $response->getHeaders()->get('content-type')->getFieldValue());
  295. }
  296. /**
  297. * Make sure a response with some leading whitespace in the response body
  298. * does not get modified (see ZF-1924)
  299. *
  300. */
  301. public function testLeadingWhitespaceBody()
  302. {
  303. $response = Response::fromString($this->readResponse('response_leadingws'));
  304. $this->assertEquals($response->getContent(), "\r\n\t \n\r\tx", 'Extracted body is not identical to expected body');
  305. }
  306. /**
  307. * Test that parsing a multibyte-encoded chunked response works.
  308. *
  309. * This can potentially fail on different PHP environments - for example
  310. * when mbstring.func_overload is set to overload strlen().
  311. *
  312. */
  313. public function testMultibyteChunkedResponse()
  314. {
  315. $this->markTestSkipped('Looks like the headers are split with \n and the body with \r\n');
  316. $md5 = 'ab952f1617d0e28724932401f2d3c6ae';
  317. $response = Response::fromString($this->readResponse('response_multibyte_body'));
  318. $this->assertEquals($md5, md5($response->getBody()));
  319. }
  320. /**
  321. * Helper function: read test response from file
  322. *
  323. * @param string $response
  324. * @return string
  325. */
  326. protected function readResponse($response)
  327. {
  328. return file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . $response);
  329. }
  330. }