InlineFragmentRendererTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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\Fragment;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\EventDispatcher\EventDispatcher;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\HttpFoundation\RequestStack;
  15. use Symfony\Component\HttpFoundation\Response;
  16. use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
  17. use Symfony\Component\HttpKernel\Controller\ControllerReference;
  18. use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
  19. use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer;
  20. use Symfony\Component\HttpKernel\HttpKernel;
  21. use Symfony\Component\HttpKernel\KernelEvents;
  22. class InlineFragmentRendererTest extends TestCase
  23. {
  24. public function testRender()
  25. {
  26. $strategy = new InlineFragmentRenderer($this->getKernel($this->returnValue(new Response('foo'))));
  27. $this->assertEquals('foo', $strategy->render('/', Request::create('/'))->getContent());
  28. }
  29. public function testRenderWithControllerReference()
  30. {
  31. $strategy = new InlineFragmentRenderer($this->getKernel($this->returnValue(new Response('foo'))));
  32. $this->assertEquals('foo', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent());
  33. }
  34. public function testRenderWithObjectsAsAttributes()
  35. {
  36. $object = new \stdClass();
  37. $subRequest = Request::create('/_fragment?_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dmain_controller');
  38. $subRequest->attributes->replace(['object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en']);
  39. $subRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
  40. $subRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
  41. $subRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
  42. $subRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
  43. $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest));
  44. $this->assertSame('foo', $strategy->render(new ControllerReference('main_controller', ['object' => $object], []), Request::create('/'))->getContent());
  45. }
  46. /**
  47. * @group legacy
  48. */
  49. public function testRenderWithObjectsAsAttributesPassedAsObjectsInTheControllerLegacy()
  50. {
  51. $resolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver')->setMethods(['getController'])->getMock();
  52. $resolver
  53. ->expects($this->once())
  54. ->method('getController')
  55. ->willReturn(function (\stdClass $object, Bar $object1) {
  56. return new Response($object1->getBar());
  57. })
  58. ;
  59. $kernel = new HttpKernel(new EventDispatcher(), $resolver, new RequestStack());
  60. $renderer = new InlineFragmentRenderer($kernel);
  61. $response = $renderer->render(new ControllerReference('main_controller', ['object' => new \stdClass(), 'object1' => new Bar()], []), Request::create('/'));
  62. $this->assertEquals('bar', $response->getContent());
  63. }
  64. /**
  65. * @group legacy
  66. */
  67. public function testRenderWithObjectsAsAttributesPassedAsObjectsInTheController()
  68. {
  69. $resolver = $this->getMockBuilder(ControllerResolverInterface::class)->getMock();
  70. $resolver
  71. ->expects($this->once())
  72. ->method('getController')
  73. ->willReturn(function (\stdClass $object, Bar $object1) {
  74. return new Response($object1->getBar());
  75. })
  76. ;
  77. $kernel = new HttpKernel(new EventDispatcher(), $resolver, new RequestStack(), new ArgumentResolver());
  78. $renderer = new InlineFragmentRenderer($kernel);
  79. $response = $renderer->render(new ControllerReference('main_controller', ['object' => new \stdClass(), 'object1' => new Bar()], []), Request::create('/'));
  80. $this->assertEquals('bar', $response->getContent());
  81. }
  82. public function testRenderWithTrustedHeaderDisabled()
  83. {
  84. Request::setTrustedProxies([], 0);
  85. $expectedSubRequest = Request::create('/');
  86. $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
  87. $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
  88. $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
  89. $this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent());
  90. Request::setTrustedProxies([], -1);
  91. }
  92. /**
  93. * @expectedException \RuntimeException
  94. */
  95. public function testRenderExceptionNoIgnoreErrors()
  96. {
  97. $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
  98. $dispatcher->expects($this->never())->method('dispatch');
  99. $strategy = new InlineFragmentRenderer($this->getKernel($this->throwException(new \RuntimeException('foo'))), $dispatcher);
  100. $this->assertEquals('foo', $strategy->render('/', Request::create('/'))->getContent());
  101. }
  102. public function testRenderExceptionIgnoreErrors()
  103. {
  104. $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
  105. $dispatcher->expects($this->once())->method('dispatch')->with(KernelEvents::EXCEPTION);
  106. $strategy = new InlineFragmentRenderer($this->getKernel($this->throwException(new \RuntimeException('foo'))), $dispatcher);
  107. $this->assertEmpty($strategy->render('/', Request::create('/'), ['ignore_errors' => true])->getContent());
  108. }
  109. public function testRenderExceptionIgnoreErrorsWithAlt()
  110. {
  111. $strategy = new InlineFragmentRenderer($this->getKernel($this->onConsecutiveCalls(
  112. $this->throwException(new \RuntimeException('foo')),
  113. $this->returnValue(new Response('bar'))
  114. )));
  115. $this->assertEquals('bar', $strategy->render('/', Request::create('/'), ['ignore_errors' => true, 'alt' => '/foo'])->getContent());
  116. }
  117. private function getKernel($returnValue)
  118. {
  119. $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
  120. $kernel
  121. ->expects($this->any())
  122. ->method('handle')
  123. ->will($returnValue)
  124. ;
  125. return $kernel;
  126. }
  127. public function testExceptionInSubRequestsDoesNotMangleOutputBuffers()
  128. {
  129. $controllerResolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface')->getMock();
  130. $controllerResolver
  131. ->expects($this->once())
  132. ->method('getController')
  133. ->willReturn(function () {
  134. ob_start();
  135. echo 'bar';
  136. throw new \RuntimeException();
  137. })
  138. ;
  139. $argumentResolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface')->getMock();
  140. $argumentResolver
  141. ->expects($this->once())
  142. ->method('getArguments')
  143. ->willReturn([])
  144. ;
  145. $kernel = new HttpKernel(new EventDispatcher(), $controllerResolver, new RequestStack(), $argumentResolver);
  146. $renderer = new InlineFragmentRenderer($kernel);
  147. // simulate a main request with output buffering
  148. ob_start();
  149. echo 'Foo';
  150. // simulate a sub-request with output buffering and an exception
  151. $renderer->render('/', Request::create('/'), ['ignore_errors' => true]);
  152. $this->assertEquals('Foo', ob_get_clean());
  153. }
  154. public function testLocaleAndFormatAreIsKeptInSubrequest()
  155. {
  156. $expectedSubRequest = Request::create('/');
  157. $expectedSubRequest->attributes->set('_format', 'foo');
  158. $expectedSubRequest->setLocale('fr');
  159. if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
  160. $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
  161. $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
  162. }
  163. $expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
  164. $expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
  165. $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
  166. $request = Request::create('/');
  167. $request->attributes->set('_format', 'foo');
  168. $request->setLocale('fr');
  169. $strategy->render('/', $request);
  170. }
  171. public function testESIHeaderIsKeptInSubrequest()
  172. {
  173. $expectedSubRequest = Request::create('/');
  174. $expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
  175. if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
  176. $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
  177. $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
  178. }
  179. $expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
  180. $expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
  181. $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
  182. $request = Request::create('/');
  183. $request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
  184. $strategy->render('/', $request);
  185. }
  186. public function testESIHeaderIsKeptInSubrequestWithTrustedHeaderDisabled()
  187. {
  188. Request::setTrustedProxies([], Request::HEADER_FORWARDED);
  189. $this->testESIHeaderIsKeptInSubrequest();
  190. Request::setTrustedProxies([], -1);
  191. }
  192. public function testHeadersPossiblyResultingIn304AreNotAssignedToSubrequest()
  193. {
  194. $expectedSubRequest = Request::create('/');
  195. $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
  196. $expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
  197. $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
  198. $expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
  199. $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
  200. $request = Request::create('/', 'GET', [], [], [], ['HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*']);
  201. $strategy->render('/', $request);
  202. }
  203. public function testFirstTrustedProxyIsSetAsRemote()
  204. {
  205. Request::setTrustedProxies(['1.1.1.1'], -1);
  206. $expectedSubRequest = Request::create('/');
  207. $expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
  208. $expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
  209. $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
  210. $expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
  211. $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
  212. $expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
  213. $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
  214. $request = Request::create('/');
  215. $request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
  216. $strategy->render('/', $request);
  217. Request::setTrustedProxies([], -1);
  218. }
  219. public function testIpAddressOfRangedTrustedProxyIsSetAsRemote()
  220. {
  221. $expectedSubRequest = Request::create('/');
  222. $expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
  223. $expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
  224. $expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
  225. $expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
  226. $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
  227. $expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
  228. Request::setTrustedProxies(['1.1.1.1/24'], -1);
  229. $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
  230. $request = Request::create('/');
  231. $request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
  232. $strategy->render('/', $request);
  233. Request::setTrustedProxies([], -1);
  234. }
  235. /**
  236. * Creates a Kernel expecting a request equals to $request
  237. * Allows delta in comparison in case REQUEST_TIME changed by 1 second.
  238. */
  239. private function getKernelExpectingRequest(Request $request, $strict = false)
  240. {
  241. $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
  242. $kernel
  243. ->expects($this->once())
  244. ->method('handle')
  245. ->with($this->equalTo($request, 1))
  246. ->willReturn(new Response('foo'));
  247. return $kernel;
  248. }
  249. }
  250. class Bar
  251. {
  252. public $bar = 'bar';
  253. public function getBar()
  254. {
  255. return $this->bar;
  256. }
  257. }