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