HttpKernelTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpKernel\Tests;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\EventDispatcher\EventDispatcher;
  13. use Symfony\Component\HttpFoundation\RedirectResponse;
  14. use Symfony\Component\HttpFoundation\Request;
  15. use Symfony\Component\HttpFoundation\Response;
  16. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  17. use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
  18. use Symfony\Component\HttpKernel\HttpKernel;
  19. use Symfony\Component\HttpKernel\HttpKernelInterface;
  20. use Symfony\Component\HttpKernel\KernelEvents;
  21. class HttpKernelTest extends TestCase
  22. {
  23. /**
  24. * @expectedException \RuntimeException
  25. */
  26. public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrue()
  27. {
  28. $kernel = new HttpKernel(new EventDispatcher(), $this->getResolver(function () { throw new \RuntimeException(); }));
  29. $kernel->handle(new Request(), HttpKernelInterface::MASTER_REQUEST, true);
  30. }
  31. /**
  32. * @expectedException \RuntimeException
  33. */
  34. public function testHandleWhenControllerThrowsAnExceptionAndCatchIsFalseAndNoListenerIsRegistered()
  35. {
  36. $kernel = new HttpKernel(new EventDispatcher(), $this->getResolver(function () { throw new \RuntimeException(); }));
  37. $kernel->handle(new Request(), HttpKernelInterface::MASTER_REQUEST, false);
  38. }
  39. public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrueWithAHandlingListener()
  40. {
  41. $dispatcher = new EventDispatcher();
  42. $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) {
  43. $event->setResponse(new Response($event->getException()->getMessage()));
  44. });
  45. $kernel = new HttpKernel($dispatcher, $this->getResolver(function () { throw new \RuntimeException('foo'); }));
  46. $response = $kernel->handle(new Request(), HttpKernelInterface::MASTER_REQUEST, true);
  47. $this->assertEquals('500', $response->getStatusCode());
  48. $this->assertEquals('foo', $response->getContent());
  49. }
  50. public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrueWithANonHandlingListener()
  51. {
  52. $exception = new \RuntimeException();
  53. $dispatcher = new EventDispatcher();
  54. $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) {
  55. // should set a response, but does not
  56. });
  57. $kernel = new HttpKernel($dispatcher, $this->getResolver(function () use ($exception) { throw $exception; }));
  58. try {
  59. $kernel->handle(new Request(), HttpKernelInterface::MASTER_REQUEST, true);
  60. $this->fail('LogicException expected');
  61. } catch (\RuntimeException $e) {
  62. $this->assertSame($exception, $e);
  63. }
  64. }
  65. public function testHandleExceptionWithARedirectionResponse()
  66. {
  67. $dispatcher = new EventDispatcher();
  68. $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) {
  69. $event->setResponse(new RedirectResponse('/login', 301));
  70. });
  71. $kernel = new HttpKernel($dispatcher, $this->getResolver(function () { throw new AccessDeniedHttpException(); }));
  72. $response = $kernel->handle(new Request());
  73. $this->assertEquals('301', $response->getStatusCode());
  74. $this->assertEquals('/login', $response->headers->get('Location'));
  75. }
  76. public function testHandleHttpException()
  77. {
  78. $dispatcher = new EventDispatcher();
  79. $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) {
  80. $event->setResponse(new Response($event->getException()->getMessage()));
  81. });
  82. $kernel = new HttpKernel($dispatcher, $this->getResolver(function () { throw new MethodNotAllowedHttpException(array('POST')); }));
  83. $response = $kernel->handle(new Request());
  84. $this->assertEquals('405', $response->getStatusCode());
  85. $this->assertEquals('POST', $response->headers->get('Allow'));
  86. }
  87. /**
  88. * @dataProvider getStatusCodes
  89. */
  90. public function testHandleWhenAnExceptionIsHandledWithASpecificStatusCode($responseStatusCode, $expectedStatusCode)
  91. {
  92. $dispatcher = new EventDispatcher();
  93. $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) use ($responseStatusCode, $expectedStatusCode) {
  94. $event->setResponse(new Response('', $responseStatusCode, array('X-Status-Code' => $expectedStatusCode)));
  95. });
  96. $kernel = new HttpKernel($dispatcher, $this->getResolver(function () { throw new \RuntimeException(); }));
  97. $response = $kernel->handle(new Request());
  98. $this->assertEquals($expectedStatusCode, $response->getStatusCode());
  99. $this->assertFalse($response->headers->has('X-Status-Code'));
  100. }
  101. public function getStatusCodes()
  102. {
  103. return array(
  104. array(200, 404),
  105. array(404, 200),
  106. array(301, 200),
  107. array(500, 200),
  108. );
  109. }
  110. public function testHandleWhenAListenerReturnsAResponse()
  111. {
  112. $dispatcher = new EventDispatcher();
  113. $dispatcher->addListener(KernelEvents::REQUEST, function ($event) {
  114. $event->setResponse(new Response('hello'));
  115. });
  116. $kernel = new HttpKernel($dispatcher, $this->getResolver());
  117. $this->assertEquals('hello', $kernel->handle(new Request())->getContent());
  118. }
  119. /**
  120. * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
  121. */
  122. public function testHandleWhenNoControllerIsFound()
  123. {
  124. $dispatcher = new EventDispatcher();
  125. $kernel = new HttpKernel($dispatcher, $this->getResolver(false));
  126. $kernel->handle(new Request());
  127. }
  128. /**
  129. * @expectedException \LogicException
  130. */
  131. public function testHandleWhenTheControllerIsNotACallable()
  132. {
  133. $dispatcher = new EventDispatcher();
  134. $kernel = new HttpKernel($dispatcher, $this->getResolver('foobar'));
  135. $kernel->handle(new Request());
  136. }
  137. public function testHandleWhenTheControllerIsAClosure()
  138. {
  139. $response = new Response('foo');
  140. $dispatcher = new EventDispatcher();
  141. $kernel = new HttpKernel($dispatcher, $this->getResolver(function () use ($response) { return $response; }));
  142. $this->assertSame($response, $kernel->handle(new Request()));
  143. }
  144. public function testHandleWhenTheControllerIsAnObjectWithInvoke()
  145. {
  146. $dispatcher = new EventDispatcher();
  147. $kernel = new HttpKernel($dispatcher, $this->getResolver(new Controller()));
  148. $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));
  149. }
  150. public function testHandleWhenTheControllerIsAFunction()
  151. {
  152. $dispatcher = new EventDispatcher();
  153. $kernel = new HttpKernel($dispatcher, $this->getResolver('Symfony\Component\HttpKernel\Tests\controller_func'));
  154. $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));
  155. }
  156. public function testHandleWhenTheControllerIsAnArray()
  157. {
  158. $dispatcher = new EventDispatcher();
  159. $kernel = new HttpKernel($dispatcher, $this->getResolver(array(new Controller(), 'controller')));
  160. $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));
  161. }
  162. public function testHandleWhenTheControllerIsAStaticArray()
  163. {
  164. $dispatcher = new EventDispatcher();
  165. $kernel = new HttpKernel($dispatcher, $this->getResolver(array('Symfony\Component\HttpKernel\Tests\Controller', 'staticcontroller')));
  166. $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));
  167. }
  168. /**
  169. * @expectedException \LogicException
  170. */
  171. public function testHandleWhenTheControllerDoesNotReturnAResponse()
  172. {
  173. $dispatcher = new EventDispatcher();
  174. $kernel = new HttpKernel($dispatcher, $this->getResolver(function () { return 'foo'; }));
  175. $kernel->handle(new Request());
  176. }
  177. public function testHandleWhenTheControllerDoesNotReturnAResponseButAViewIsRegistered()
  178. {
  179. $dispatcher = new EventDispatcher();
  180. $dispatcher->addListener(KernelEvents::VIEW, function ($event) {
  181. $event->setResponse(new Response($event->getControllerResult()));
  182. });
  183. $kernel = new HttpKernel($dispatcher, $this->getResolver(function () { return 'foo'; }));
  184. $this->assertEquals('foo', $kernel->handle(new Request())->getContent());
  185. }
  186. public function testHandleWithAResponseListener()
  187. {
  188. $dispatcher = new EventDispatcher();
  189. $dispatcher->addListener(KernelEvents::RESPONSE, function ($event) {
  190. $event->setResponse(new Response('foo'));
  191. });
  192. $kernel = new HttpKernel($dispatcher, $this->getResolver());
  193. $this->assertEquals('foo', $kernel->handle(new Request())->getContent());
  194. }
  195. public function testTerminate()
  196. {
  197. $dispatcher = new EventDispatcher();
  198. $kernel = new HttpKernel($dispatcher, $this->getResolver());
  199. $dispatcher->addListener(KernelEvents::TERMINATE, function ($event) use (&$called, &$capturedKernel, &$capturedRequest, &$capturedResponse) {
  200. $called = true;
  201. $capturedKernel = $event->getKernel();
  202. $capturedRequest = $event->getRequest();
  203. $capturedResponse = $event->getResponse();
  204. });
  205. $kernel->terminate($request = Request::create('/'), $response = new Response());
  206. $this->assertTrue($called);
  207. $this->assertEquals($kernel, $capturedKernel);
  208. $this->assertEquals($request, $capturedRequest);
  209. $this->assertEquals($response, $capturedResponse);
  210. }
  211. public function testVerifyRequestStackPushPopDuringHandle()
  212. {
  213. $request = new Request();
  214. $stack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->setMethods(array('push', 'pop'))->getMock();
  215. $stack->expects($this->at(0))->method('push')->with($this->equalTo($request));
  216. $stack->expects($this->at(1))->method('pop');
  217. $dispatcher = new EventDispatcher();
  218. $kernel = new HttpKernel($dispatcher, $this->getResolver(), $stack);
  219. $kernel->handle($request, HttpKernelInterface::MASTER_REQUEST);
  220. }
  221. /**
  222. * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
  223. */
  224. public function testInconsistentClientIpsOnMasterRequests()
  225. {
  226. $dispatcher = new EventDispatcher();
  227. $dispatcher->addListener(KernelEvents::REQUEST, function ($event) {
  228. $event->getRequest()->getClientIp();
  229. });
  230. $kernel = new HttpKernel($dispatcher, $this->getResolver());
  231. $request = new Request();
  232. $request->setTrustedProxies(array('1.1.1.1'));
  233. $request->server->set('REMOTE_ADDR', '1.1.1.1');
  234. $request->headers->set('FORWARDED', 'for=2.2.2.2');
  235. $request->headers->set('X_FORWARDED_FOR', '3.3.3.3');
  236. $kernel->handle($request, $kernel::MASTER_REQUEST, false);
  237. Request::setTrustedProxies(array());
  238. }
  239. protected function getResolver($controller = null)
  240. {
  241. if (null === $controller) {
  242. $controller = function () { return new Response('Hello'); };
  243. }
  244. $resolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface')->getMock();
  245. $resolver->expects($this->any())
  246. ->method('getController')
  247. ->will($this->returnValue($controller));
  248. $resolver->expects($this->any())
  249. ->method('getArguments')
  250. ->will($this->returnValue(array()));
  251. return $resolver;
  252. }
  253. protected function assertResponseEquals(Response $expected, Response $actual)
  254. {
  255. $expected->setDate($actual->getDate());
  256. $this->assertEquals($expected, $actual);
  257. }
  258. }
  259. class Controller
  260. {
  261. public function __invoke()
  262. {
  263. return new Response('foo');
  264. }
  265. public function controller()
  266. {
  267. return new Response('foo');
  268. }
  269. public static function staticController()
  270. {
  271. return new Response('foo');
  272. }
  273. }
  274. function controller_func()
  275. {
  276. return new Response('foo');
  277. }