added some unit tests (and fixed some bugs)

This commit is contained in:
Fabien Potencier 2013-01-10 16:08:44 +01:00
parent f17f5867a8
commit f7da1f0eb8
22 changed files with 697 additions and 21 deletions

View File

@ -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

View File

@ -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)));
}
}

View File

@ -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);

View File

@ -19,13 +19,12 @@
<argument>%kernel.debug%</argument>
</service>
<service id="http_content_renderer.strategy.default" class="%http_content_renderer.strategy.default.class%" public="false">
<service id="http_content_renderer.strategy.default" class="%http_content_renderer.strategy.default.class%">
<tag name="kernel.content_renderer_strategy" />
<argument type="service" id="http_kernel" />
<call method="setUrlGenerator"><argument type="service" id="router" /></call>
</service>
<!-- FIXME: this service should be private but it cannot due to a bug in PhpDumper -->
<service id="http_content_renderer.strategy.hinclude" class="%http_content_renderer.strategy.hinclude.class%">
<tag name="kernel.content_renderer_strategy" />
<argument type="service" id="templating" on-invalid="null" />

View File

@ -18,7 +18,7 @@
<argument type="service" id="esi" on-invalid="ignore" />
</service>
<service id="http_content_renderer.strategy.esi" class="%http_content_renderer.strategy.esi.class%" public="false">
<service id="http_content_renderer.strategy.esi" class="%http_content_renderer.strategy.esi.class%">
<tag name="kernel.content_renderer_strategy" />
<argument type="service" id="esi" />
<argument type="service" id="http_content_renderer.strategy.default" />

View File

@ -0,0 +1,105 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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';
}
}

View File

@ -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;

View File

@ -926,8 +926,7 @@ class Request
*/
public function getUri()
{
$qs = $this->getQueryString();
if (null !== $qs) {
if (null !== $qs = $this->getQueryString()) {
$qs = '?'.$qs;
}

View File

@ -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;
}

View File

@ -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())
{

View File

@ -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())
{

View File

@ -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'] : '');
}
/**

View File

@ -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);
}

View File

@ -0,0 +1,119 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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);
}
}

View File

@ -0,0 +1,75 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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')),
);
}
}

View File

@ -0,0 +1,29 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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;
}
}

View File

@ -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');

View File

@ -0,0 +1,68 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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('<esi:include src="/" />', $strategy->render('/', $request));
$this->assertEquals("<esi:comment text=\"This is a comment\" />\n<esi:include src=\"/\" />", $strategy->render('/', $request, array('comment' => 'This is a comment')));
$this->assertEquals('<esi:include src="/" alt="foo" />', $strategy->render('/', $request, array('alt' => 'foo')));
$this->assertEquals('<esi:include src="/main_controller.html" alt="/alt_controller.html" />', $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;
}
}

View File

@ -0,0 +1,101 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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);
}
}

View File

@ -0,0 +1,71 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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('<hx:include src="/main_controller.html?_hash=6MuxpWUHcqIddMMmoN36uPsEjws%3D"></hx:include>', $strategy->render(new ControllerReference('main_controller', array(), array())));
}
public function testRenderWithUri()
{
$strategy = new HIncludeRenderingStrategy();
$this->assertEquals('<hx:include src="/foo"></hx:include>', $strategy->render('/foo'));
$strategy = new HIncludeRenderingStrategy(null, new UriSigner('foo'));
$this->assertEquals('<hx:include src="/foo"></hx:include>', $strategy->render('/foo'));
}
public function testRenderWhithDefault()
{
// only default
$strategy = new HIncludeRenderingStrategy();
$this->assertEquals('<hx:include src="/foo">default</hx:include>', $strategy->render('/foo', null, array('default' => 'default')));
// only global default
$strategy = new HIncludeRenderingStrategy(null, null, 'global_default');
$this->assertEquals('<hx:include src="/foo">global_default</hx:include>', $strategy->render('/foo', null, array()));
// global default and default
$strategy = new HIncludeRenderingStrategy(null, null, 'global_default');
$this->assertEquals('<hx:include src="/foo">default</hx:include>', $strategy->render('/foo', null, array('default' => 'default')));
}
}

View File

@ -0,0 +1,37 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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')));
}
}

View File

@ -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];
}