diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php
index dd6030ea54..182c42d077 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php
@@ -13,7 +13,6 @@ namespace Symfony\Bridge\Twig\Tests\Extension;
use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
use Symfony\Bridge\Twig\Tests\TestCase;
-use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpContentRenderer;
class HttpKernelExtensionTest extends TestCase
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php
index 3d31def579..3bb16f28c7 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php
@@ -14,7 +14,6 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
-use Symfony\Component\DependencyInjection\Exception\LogicException;
/**
* Adds services tagged kernel.content_renderer_strategy as HTTP content rendering strategies.
@@ -31,6 +30,15 @@ class HttpRenderingStrategyPass implements CompilerPassInterface
$definition = $container->getDefinition('http_content_renderer');
foreach (array_keys($container->findTaggedServiceIds('kernel.content_renderer_strategy')) as $id) {
+ // We must assume that the class value has been correctly filled, even if the service is created by a factory
+ $class = $container->getDefinition($id)->getClass();
+
+ $refClass = new \ReflectionClass($class);
+ $interface = 'Symfony\Component\HttpKernel\RenderingStrategy\RenderingStrategyInterface';
+ if (!$refClass->implementsInterface($interface)) {
+ throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
+ }
+
$definition->addMethodCall('addStrategy', array(new Reference($id)));
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
index 3f18da7892..c4caaea4e9 100644
--- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -66,7 +66,7 @@ class FrameworkBundle extends Bundle
$container->addCompilerPass(new AddCacheClearerPass());
$container->addCompilerPass(new TranslationExtractorPass());
$container->addCompilerPass(new TranslationDumperPass());
- $container->addCompilerPass(new HttpRenderingStrategyPass());
+ $container->addCompilerPass(new HttpRenderingStrategyPass(), PassConfig::TYPE_AFTER_REMOVING);
if ($container->getParameter('kernel.debug')) {
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml
index 533e886fb6..332cf0de38 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml
@@ -19,13 +19,12 @@
%kernel.debug%
-
+
-
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml
index 45e9265442..0c4a271863 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml
@@ -18,7 +18,7 @@
-
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/HttpRenderingStrategyPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/HttpRenderingStrategyPassTest.php
new file mode 100644
index 0000000000..4fe461fec4
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/HttpRenderingStrategyPassTest.php
@@ -0,0 +1,105 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\HttpRenderingStrategyPass;
+
+class HttpRenderingStrategyPassTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * Tests that content rendering not implementing RenderingStrategyInterface
+ * trigger an exception.
+ *
+ * @expectedException \InvalidArgumentException
+ */
+ public function testContentRendererWithoutInterface()
+ {
+ // one service, not implementing any interface
+ $services = array(
+ 'my_content_renderer' => array(),
+ );
+
+ $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition');
+ $definition->expects($this->atLeastOnce())
+ ->method('getClass')
+ ->will($this->returnValue('stdClass'));
+
+ $builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
+ $builder->expects($this->any())
+ ->method('hasDefinition')
+ ->will($this->returnValue(true));
+
+ // We don't test kernel.content_renderer_strategy here
+ $builder->expects($this->atLeastOnce())
+ ->method('findTaggedServiceIds')
+ ->will($this->returnValue($services));
+
+ $builder->expects($this->atLeastOnce())
+ ->method('getDefinition')
+ ->will($this->returnValue($definition));
+
+ $pass = new HttpRenderingStrategyPass();
+ $pass->process($builder);
+ }
+
+ public function testValidContentRenderer()
+ {
+ $services = array(
+ 'my_content_renderer' => array(),
+ );
+
+ $renderer = $this->getMock('Symfony\Component\DependencyInjection\Definition');
+ $renderer
+ ->expects($this->once())
+ ->method('addMethodCall')
+ ->with('addStrategy', array(new Reference('my_content_renderer')))
+ ;
+
+ $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition');
+ $definition->expects($this->atLeastOnce())
+ ->method('getClass')
+ ->will($this->returnValue('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\RenderingStrategyService'));
+
+ $builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
+ $builder->expects($this->any())
+ ->method('hasDefinition')
+ ->will($this->returnValue(true));
+
+ // We don't test kernel.content_renderer_strategy here
+ $builder->expects($this->atLeastOnce())
+ ->method('findTaggedServiceIds')
+ ->will($this->returnValue($services));
+
+ $builder->expects($this->atLeastOnce())
+ ->method('getDefinition')
+ ->will($this->onConsecutiveCalls($renderer, $definition));
+
+ $pass = new HttpRenderingStrategyPass();
+ $pass->process($builder);
+ }
+}
+
+class RenderingStrategyService implements \Symfony\Component\HttpKernel\RenderingStrategy\RenderingStrategyInterface
+{
+ public function render($uri, Request $request = null, array $options = array())
+ {
+ }
+
+ public function getName()
+ {
+ return 'test';
+ }
+}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php
index d9555e13e1..3a8f7f41f0 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php
@@ -13,7 +13,6 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\EventListener;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilder;
-use Symfony\Component\Form\FormError;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php
index 9a647c43fc..0bac66ada7 100644
--- a/src/Symfony/Component/HttpFoundation/Request.php
+++ b/src/Symfony/Component/HttpFoundation/Request.php
@@ -926,8 +926,7 @@ class Request
*/
public function getUri()
{
- $qs = $this->getQueryString();
- if (null !== $qs) {
+ if (null !== $qs = $this->getQueryString()) {
$qs = '?'.$qs;
}
diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php
index 05e8717fc0..b88350c20f 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php
@@ -55,7 +55,7 @@ class RouterProxyListener implements EventSubscriberInterface
parse_str($request->query->get('path', ''), $attributes);
$request->attributes->add($attributes);
- $request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params'), $attributes));
+ $request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params', array()), $attributes));
$request->query->remove('path');
}
@@ -76,7 +76,8 @@ class RouterProxyListener implements EventSubscriberInterface
}
// is the Request signed?
- if ($this->signer->check($request->getUri())) {
+ // we cannot use $request->getUri() here as we want to work with the original URI (no query string reordering)
+ if ($this->signer->check($request->getSchemeAndHttpHost().$request->getBaseUrl().$request->getPathInfo().(null !== ($qs = $request->server->get('QUERY_STRING')) ? '?'.$qs : ''))) {
return;
}
diff --git a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php
index 408dffc991..4849b8f6b5 100644
--- a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php
+++ b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php
@@ -90,6 +90,8 @@ class HttpContentRenderer implements EventSubscriberInterface
* @param array $options An array of options
*
* @return string|null The Response content or null when the Response is streamed
+ *
+ * @throws \InvalidArgumentException when the strategy does not exist
*/
public function render($uri, $strategy = 'default', array $options = array())
{
diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php
index 5198c01ba9..c0820b8504 100644
--- a/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php
+++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php
@@ -36,6 +36,10 @@ class DefaultRenderingStrategy extends GeneratorAwareRenderingStrategy
/**
* {@inheritdoc}
+ *
+ * Additional available options:
+ *
+ * * alt: an alternative URI to render in case of an error
*/
public function render($uri, Request $request = null, array $options = array())
{
diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php
index cf9f572079..f77669f484 100644
--- a/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php
+++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php
@@ -56,7 +56,7 @@ class EsiRenderingStrategy extends GeneratorAwareRenderingStrategy
*/
public function render($uri, Request $request = null, array $options = array())
{
- if (!$this->esi->hasSurrogateEsiCapability($request)) {
+ if (null === $request || !$this->esi->hasSurrogateEsiCapability($request)) {
return $this->defaultStrategy->render($uri, $request, $options);
}
@@ -69,7 +69,7 @@ class EsiRenderingStrategy extends GeneratorAwareRenderingStrategy
$alt = $this->generateProxyUri($alt, $request);
}
- return $this->esi->renderIncludeTag($uri, $alt, $options['ignore_errors'], isset($options['comment']) ? $options['comment'] : '');
+ return $this->esi->renderIncludeTag($uri, $alt, isset($options['ignore_errors']) ? $options['ignore_errors'] : false, isset($options['comment']) ? $options['comment'] : '');
}
/**
diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php
index 408d682326..a5ba272f81 100644
--- a/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php
+++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php
@@ -46,6 +46,9 @@ abstract class GeneratorAwareRenderingStrategy implements RenderingStrategyInter
* @param Request $request A Request instance
*
* @return string A proxy URI
+ *
+ * @throws \LogicException when the _proxy route is not available
+ * @throws \LogicException when there is no registered route generator
*/
protected function generateProxyUri(ControllerReference $reference, Request $request = null)
{
@@ -63,7 +66,7 @@ abstract class GeneratorAwareRenderingStrategy implements RenderingStrategyInter
}
try {
- $uri = $this->generator->generate('_proxy', array('_controller' => $reference->controller, '_format' => $format), true);
+ $uri = $this->generator->generate('_proxy', array('_controller' => $reference->controller, '_format' => $format), UrlGeneratorInterface::ABSOLUTE_URL);
} catch (RouteNotFoundException $e) {
throw new \LogicException('Unable to generate a proxy URL as the "_proxy" route is not registered.', 0, $e);
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php
new file mode 100644
index 0000000000..32b750f9ce
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php
@@ -0,0 +1,119 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Tests\EventListener;
+
+use Symfony\Component\HttpKernel\EventListener\RouterProxyListener;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\HttpKernel\UriSigner;
+
+class RouterProxyListenerTest extends \PHPUnit_Framework_TestCase
+{
+ protected function setUp()
+ {
+ if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
+ $this->markTestSkipped('The "EventDispatcher" component is not available');
+ }
+ }
+
+ public function testOnlyTrigerredOnProxyRoute()
+ {
+ $request = Request::create('http://example.com/foo?path=foo%3D=bar');
+
+ $listener = new RouterProxyListener(new UriSigner('foo'));
+ $event = $this->createGetResponseEvent($request, 'foobar');
+
+ $expected = $request->attributes->all();
+
+ $listener->onKernelRequest($event);
+
+ $this->assertEquals($expected, $request->attributes->all());
+ $this->assertTrue($request->query->has('path'));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+ */
+ public function testAccessDeniedWithNonSafeMethods()
+ {
+ $request = Request::create('http://example.com/foo', 'POST');
+
+ $listener = new RouterProxyListener(new UriSigner('foo'));
+ $event = $this->createGetResponseEvent($request);
+
+ $listener->onKernelRequest($event);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+ */
+ public function testAccessDeniedWithNonLocalIps()
+ {
+ $request = Request::create('http://example.com/foo', 'GET', array(), array(), array(), array('REMOTE_ADDR' => '10.0.0.1'));
+
+ $listener = new RouterProxyListener(new UriSigner('foo'));
+ $event = $this->createGetResponseEvent($request);
+
+ $listener->onKernelRequest($event);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+ */
+ public function testAccessDeniedWithWrongSignature()
+ {
+ $request = Request::create('http://example.com/foo', 'GET', array(), array(), array(), array('REMOTE_ADDR' => '10.0.0.1'));
+
+ $listener = new RouterProxyListener(new UriSigner('foo'));
+ $event = $this->createGetResponseEvent($request);
+
+ $listener->onKernelRequest($event);
+ }
+
+ public function testWithSignatureAndNoPath()
+ {
+ $signer = new UriSigner('foo');
+ $request = Request::create($signer->sign('http://example.com/foo'), 'GET', array(), array(), array(), array('REMOTE_ADDR' => '10.0.0.1'));
+
+ $listener = new RouterProxyListener($signer);
+ $event = $this->createGetResponseEvent($request);
+
+ $listener->onKernelRequest($event);
+
+ $this->assertEquals(array('foo' => 'foo'), $request->attributes->get('_route_params'));
+ $this->assertFalse($request->query->has('path'));
+ }
+
+ public function testWithSignatureAndPath()
+ {
+ $signer = new UriSigner('foo');
+ $request = Request::create($signer->sign('http://example.com/foo?path=bar%3Dbar'), 'GET', array(), array(), array(), array('REMOTE_ADDR' => '10.0.0.1'));
+
+ $listener = new RouterProxyListener($signer);
+ $event = $this->createGetResponseEvent($request);
+
+ $listener->onKernelRequest($event);
+
+ $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar'), $request->attributes->get('_route_params'));
+ $this->assertFalse($request->query->has('path'));
+ }
+
+ private function createGetResponseEvent(Request $request, $route = '_proxy')
+ {
+ $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+ $request->attributes->set('_route', $route);
+ $request->attributes->set('_route_params', array('foo' => 'foo'));
+
+ return new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpContentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpContentRendererTest.php
new file mode 100644
index 0000000000..ff0d4cbdb0
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpContentRendererTest.php
@@ -0,0 +1,75 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Tests;
+
+use Symfony\Component\HttpKernel\HttpContentRenderer;
+
+class HttpContentRendererTest extends \PHPUnit_Framework_TestCase
+{
+ protected function setUp()
+ {
+ if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) {
+ $this->markTestSkipped('The "EventDispatcher" component is not available');
+ }
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testRenderWhenStrategyDoesNotExist()
+ {
+ $renderer = new HttpContentRenderer();
+ $renderer->render('/', 'foo');
+ }
+
+ public function testRender()
+ {
+ $strategy = $this->getMock('Symfony\Component\HttpKernel\RenderingStrategy\RenderingStrategyInterface');
+ $strategy
+ ->expects($this->any())
+ ->method('getName')
+ ->will($this->returnValue('foo'))
+ ;
+ $strategy
+ ->expects($this->any())
+ ->method('render')
+ ->with('/', null, array('foo' => 'foo', 'ignore_errors' => true))
+ ->will($this->returnValue('foo'))
+ ;
+
+ $renderer = new HttpContentRenderer();
+ $renderer->addStrategy($strategy);
+
+ $this->assertEquals('foo', $renderer->render('/', 'foo', array('foo' => 'foo')));
+ }
+
+ /**
+ * @dataProvider getFixOptionsData
+ */
+ public function testFixOptions($expected, $options)
+ {
+ $renderer = new HttpContentRenderer();
+
+ set_error_handler(function ($errorNumber, $message, $file, $line, $context) { return $errorNumber & E_USER_DEPRECATED; });
+ $this->assertEquals($expected, $renderer->fixOptions($options));
+ restore_error_handler();
+ }
+
+ public function getFixOptionsData()
+ {
+ return array(
+ array(array('strategy' => 'esi'), array('standalone' => true)),
+ array(array('strategy' => 'esi'), array('standalone' => 'esi')),
+ array(array('strategy' => 'hinclude'), array('standalone' => 'js')),
+ );
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/AbstractRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/AbstractRenderingStrategyTest.php
new file mode 100644
index 0000000000..ae3a07f2cc
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/AbstractRenderingStrategyTest.php
@@ -0,0 +1,29 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy;
+
+abstract class AbstractRenderingStrategyTest extends \PHPUnit_Framework_TestCase
+{
+ protected function getUrlGenerator()
+ {
+ $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
+ $generator
+ ->expects($this->any())
+ ->method('generate')
+ ->will($this->returnCallback(function ($name, $parameters, $referenceType) {
+ return '/'.$parameters['_controller'].'.'.$parameters['_format'];
+ }))
+ ;
+
+ return $generator;
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php
index 48a5451470..3c55c5905c 100644
--- a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php
@@ -9,16 +9,16 @@
* file that was distributed with this source code.
*/
- namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy;
+namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\RenderingStrategy\DefaultRenderingStrategy;
-use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\EventDispatcher\EventDispatcher;
-class DefaultRenderingStrategyTest extends \PHPUnit_Framework_TestCase
+class DefaultRenderingStrategyTest extends AbstractRenderingStrategyTest
{
protected function setUp()
{
@@ -31,6 +31,60 @@ class DefaultRenderingStrategyTest extends \PHPUnit_Framework_TestCase
}
}
+ public function testRender()
+ {
+ $strategy = new DefaultRenderingStrategy($this->getKernel($this->returnValue(new Response('foo'))));
+
+ $this->assertEquals('foo', $strategy->render('/'));
+ }
+
+ public function testRenderWithControllerReference()
+ {
+ $strategy = new DefaultRenderingStrategy($this->getKernel($this->returnValue(new Response('foo'))));
+ $strategy->setUrlGenerator($this->getUrlGenerator());
+
+ $this->assertEquals('foo', $strategy->render(new ControllerReference('main_controller', array(), array())));
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testRenderExceptionNoIgnoreErrors()
+ {
+ $strategy = new DefaultRenderingStrategy($this->getKernel($this->throwException(new \RuntimeException('foo'))));
+
+ $this->assertEquals('foo', $strategy->render('/'));
+ }
+
+ public function testRenderExceptionIgnoreErrors()
+ {
+ $strategy = new DefaultRenderingStrategy($this->getKernel($this->throwException(new \RuntimeException('foo'))));
+
+ $this->assertNull($strategy->render('/', null, array('ignore_errors' => true)));
+ }
+
+ public function testRenderExceptionIgnoreErrorsWithAlt()
+ {
+ $strategy = new DefaultRenderingStrategy($this->getKernel($this->onConsecutiveCalls(
+ $this->throwException(new \RuntimeException('foo')),
+ $this->returnValue(new Response('bar'))
+ )));
+
+ $this->assertEquals('bar', $strategy->render('/', null, array('ignore_errors' => true, 'alt' => '/foo')));
+ }
+
+ private function getKernel($returnValue)
+ {
+ $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+ $kernel
+ ->expects($this->any())
+ ->method('handle')
+ ->will($returnValue)
+ ;
+
+ return $kernel;
+ }
+
public function testExceptionInSubRequestsDoesNotMangleOutputBuffers()
{
$resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface');
diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/EsiRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/EsiRenderingStrategyTest.php
new file mode 100644
index 0000000000..513e30039c
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/EsiRenderingStrategyTest.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy;
+
+use Symfony\Component\HttpKernel\Controller\ControllerReference;
+use Symfony\Component\HttpKernel\RenderingStrategy\EsiRenderingStrategy;
+use Symfony\Component\HttpKernel\HttpCache\Esi;
+use Symfony\Component\HttpFoundation\Request;
+
+class EsiRenderingStrategyTest extends AbstractRenderingStrategyTest
+{
+ protected function setUp()
+ {
+ if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
+ $this->markTestSkipped('The "HttpFoundation" component is not available');
+ }
+
+ if (!interface_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) {
+ $this->markTestSkipped('The "Routing" component is not available');
+ }
+ }
+
+ public function testRenderFallbackToDefaultStrategyIfNoRequest()
+ {
+ $strategy = new EsiRenderingStrategy(new Esi(), $this->getDefaultStrategy(true));
+ $strategy->render('/');
+ }
+
+ public function testRenderFallbackToDefaultStrategyIfEsiNotSupported()
+ {
+ $strategy = new EsiRenderingStrategy(new Esi(), $this->getDefaultStrategy(true));
+ $strategy->render('/', Request::create('/'));
+ }
+
+ public function testRender()
+ {
+ $strategy = new EsiRenderingStrategy(new Esi(), $this->getDefaultStrategy());
+ $strategy->setUrlGenerator($this->getUrlGenerator());
+
+ $request = Request::create('/');
+ $request->headers->set('Surrogate-Capability', 'ESI/1.0');
+
+ $this->assertEquals('', $strategy->render('/', $request));
+ $this->assertEquals("\n", $strategy->render('/', $request, array('comment' => 'This is a comment')));
+ $this->assertEquals('', $strategy->render('/', $request, array('alt' => 'foo')));
+ $this->assertEquals('', $strategy->render(new ControllerReference('main_controller', array(), array()), $request, array('alt' => new ControllerReference('alt_controller', array(), array()))));
+ }
+
+ private function getDefaultStrategy($called = false)
+ {
+ $default = $this->getMockBuilder('Symfony\Component\HttpKernel\RenderingStrategy\DefaultRenderingStrategy')->disableOriginalConstructor()->getMock();
+
+ if ($called) {
+ $default->expects($this->once())->method('render');
+ }
+
+ return $default;
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/GeneratorAwareRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/GeneratorAwareRenderingStrategyTest.php
new file mode 100644
index 0000000000..387ab3e2a0
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/GeneratorAwareRenderingStrategyTest.php
@@ -0,0 +1,101 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Controller\ControllerReference;
+use Symfony\Component\HttpKernel\RenderingStrategy\GeneratorAwareRenderingStrategy;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+
+class GeneratorAwareRenderingStrategyTest extends AbstractRenderingStrategyTest
+{
+ protected function setUp()
+ {
+ if (!interface_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) {
+ $this->markTestSkipped('The "Routing" component is not available');
+ }
+ }
+
+ /**
+ * @expectedException \LogicException
+ */
+ public function testGenerateProxyUriWithNoGenerator()
+ {
+ $strategy = new Strategy();
+ $strategy->doGenerateProxyUri(new ControllerReference('controller', array(), array()));
+ }
+
+ /**
+ * @expectedException \LogicException
+ */
+ public function testGenerateProxyUriWhenRouteNotFound()
+ {
+ $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
+ $generator
+ ->expects($this->once())
+ ->method('generate')
+ ->will($this->throwException(new RouteNotFoundException()))
+ ;
+
+ $strategy = new Strategy();
+ $strategy->setUrlGenerator($generator);
+ $strategy->doGenerateProxyUri(new ControllerReference('controller', array(), array()));
+ }
+
+ /**
+ * @dataProvider getGeneratorProxyUriData
+ */
+ public function testGenerateProxyUri($uri, $controller)
+ {
+ $this->assertEquals($uri, $this->getStrategy()->doGenerateProxyUri($controller));
+ }
+
+ public function getGeneratorProxyUriData()
+ {
+ return array(
+ array('/controller.html', new ControllerReference('controller', array(), array())),
+ array('/controller.xml', new ControllerReference('controller', array('_format' => 'xml'), array())),
+ array('/controller.json?path=foo%3Dfoo', new ControllerReference('controller', array('foo' => 'foo', '_format' => 'json'), array())),
+ array('/controller.html?bar=bar&path=foo%3Dfoo', new ControllerReference('controller', array('foo' => 'foo'), array('bar' => 'bar'))),
+ array('/controller.html?foo=foo', new ControllerReference('controller', array(), array('foo' => 'foo'))),
+ );
+ }
+
+ public function testGenerateProxyUriWithARequest()
+ {
+ $request = Request::create('/');
+ $request->attributes->set('_format', 'json');
+ $controller = new ControllerReference('controller', array(), array());
+
+ $this->assertEquals('/controller.json', $this->getStrategy()->doGenerateProxyUri($controller, $request));
+ }
+
+ private function getStrategy()
+ {
+ $strategy = new Strategy();
+ $strategy->setUrlGenerator($this->getUrlGenerator());
+
+ return $strategy;
+ }
+}
+
+class Strategy extends GeneratorAwareRenderingStrategy
+{
+ public function render($uri, Request $request = null, array $options = array()) {}
+ public function getName() {}
+
+ public function doGenerateProxyUri(ControllerReference $reference, Request $request = null)
+ {
+ return parent::generateProxyUri($reference, $request);
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/HIncludeRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/HIncludeRenderingStrategyTest.php
new file mode 100644
index 0000000000..ecc99665f8
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/HIncludeRenderingStrategyTest.php
@@ -0,0 +1,71 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy;
+
+use Symfony\Component\HttpKernel\Controller\ControllerReference;
+use Symfony\Component\HttpKernel\RenderingStrategy\HIncludeRenderingStrategy;
+use Symfony\Component\HttpKernel\UriSigner;
+use Symfony\Component\HttpFoundation\Request;
+
+class HIncludeRenderingStrategyTest extends AbstractRenderingStrategyTest
+{
+ protected function setUp()
+ {
+ if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
+ $this->markTestSkipped('The "HttpFoundation" component is not available');
+ }
+
+ if (!interface_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) {
+ $this->markTestSkipped('The "Routing" component is not available');
+ }
+ }
+
+ /**
+ * @expectedException \LogicException
+ */
+ public function testRenderExceptionWhenControllerAndNoSigner()
+ {
+ $strategy = new HIncludeRenderingStrategy();
+ $strategy->render(new ControllerReference('main_controller', array(), array()));
+ }
+
+ public function testRenderWithControllerAndSigner()
+ {
+ $strategy = new HIncludeRenderingStrategy(null, new UriSigner('foo'));
+ $strategy->setUrlGenerator($this->getUrlGenerator());
+ $this->assertEquals('', $strategy->render(new ControllerReference('main_controller', array(), array())));
+ }
+
+ public function testRenderWithUri()
+ {
+ $strategy = new HIncludeRenderingStrategy();
+ $this->assertEquals('', $strategy->render('/foo'));
+
+ $strategy = new HIncludeRenderingStrategy(null, new UriSigner('foo'));
+ $this->assertEquals('', $strategy->render('/foo'));
+ }
+
+ public function testRenderWhithDefault()
+ {
+ // only default
+ $strategy = new HIncludeRenderingStrategy();
+ $this->assertEquals('default', $strategy->render('/foo', null, array('default' => 'default')));
+
+ // only global default
+ $strategy = new HIncludeRenderingStrategy(null, null, 'global_default');
+ $this->assertEquals('global_default', $strategy->render('/foo', null, array()));
+
+ // global default and default
+ $strategy = new HIncludeRenderingStrategy(null, null, 'global_default');
+ $this->assertEquals('default', $strategy->render('/foo', null, array('default' => 'default')));
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Tests/UriSignerTest.php b/src/Symfony/Component/HttpKernel/Tests/UriSignerTest.php
new file mode 100644
index 0000000000..8ffc2bfbbd
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/UriSignerTest.php
@@ -0,0 +1,37 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Tests;
+
+use Symfony\Component\HttpKernel\UriSigner;
+
+class UriSignerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testSign()
+ {
+ $signer = new UriSigner('foobar');
+
+ $this->assertContains('?_hash=', $signer->sign('http://example.com/foo'));
+ $this->assertContains('&_hash=', $signer->sign('http://example.com/foo?foo=bar'));
+ }
+
+ public function testCheck()
+ {
+ $signer = new UriSigner('foobar');
+
+ $this->assertFalse($signer->check('http://example.com/foo?_hash=foo'));
+ $this->assertFalse($signer->check('http://example.com/foo?foo=bar&_hash=foo'));
+ $this->assertFalse($signer->check('http://example.com/foo?foo=bar&_hash=foo&bar=foo'));
+
+ $this->assertTrue($signer->check($signer->sign('http://example.com/foo')));
+ $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar')));
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/UriSigner.php b/src/Symfony/Component/HttpKernel/UriSigner.php
index 3530c31a77..45825fe246 100644
--- a/src/Symfony/Component/HttpKernel/UriSigner.php
+++ b/src/Symfony/Component/HttpKernel/UriSigner.php
@@ -48,19 +48,22 @@ class UriSigner
/**
* Checks that a URI contains the correct hash.
*
+ * The _hash query string parameter must be the last one
+ * (as it is generated that way by the sign() method, it should
+ * never be a problem).
+ *
* @param string $uri A signed URI
*
* @return Boolean True if the URI is signed correctly, false otherwise
*/
public function check($uri)
{
- if (!preg_match('/(\?|&)_hash=(.+?)(&|$)/', $uri, $matches, PREG_OFFSET_CAPTURE)) {
+ if (!preg_match('/(\?|&)_hash=(.+?)$/', $uri, $matches, PREG_OFFSET_CAPTURE)) {
return false;
}
// the naked URI is the URI without the _hash parameter (we need to keep the ? if there is some other parameters after)
- $offset = ('?' == $matches[1][0] && '&' != $matches[3][0]) ? 0 : 1;
- $nakedUri = substr($uri, 0, $matches[0][1] + $offset).substr($uri, $matches[0][1] + strlen($matches[0][0]));
+ $nakedUri = substr($uri, 0, $matches[0][1]).substr($uri, $matches[0][1] + strlen($matches[0][0]));
return $this->computeHash($nakedUri) === $matches[2][0];
}