InlineFragmentRendererTest.php 13 KB

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