diff --git a/.travis.php b/.github/travis.php similarity index 82% rename from .travis.php rename to .github/travis.php index f0ec7f3df6..6773a6edcc 100644 --- a/.travis.php +++ b/.github/travis.php @@ -1,19 +1,23 @@ $_SERVER['argc']) { - echo "Usage: branch dir1 dir2 ... dirN\n"; + echo "Usage: branch version dir1 dir2 ... dirN\n"; exit(1); } $dirs = $_SERVER['argv']; array_shift($dirs); $branch = array_shift($dirs); +$version = array_shift($dirs); $packages = array(); $flags = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE : 0; foreach ($dirs as $dir) { - if (!`git diff --name-only $branch...HEAD -- $dir`) { + if (!system("git diff --name-only $branch...HEAD -- $dir", $exitStatus)) { + if ($exitStatus) { + exit($exitStatus); + } continue; } echo "$dir\n"; @@ -32,7 +36,7 @@ foreach ($dirs as $dir) { file_put_contents($dir.'/composer.json', $json); passthru("cd $dir && tar -cf package.tar --exclude='package.tar' *"); - $package->version = 'master' !== $branch ? $branch.'.x-dev' : 'dev-master'; + $package->version = 'master' !== $version ? $version.'.x-dev' : 'dev-master'; $package->dist['type'] = 'tar'; $package->dist['url'] = 'file://'.__DIR__."/$dir/package.tar"; diff --git a/.travis.yml b/.travis.yml index b4595553c3..2833f3e63a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,7 +71,7 @@ before_install: install: - if [[ ! $skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components - - if [[ ! $skip && $deps ]]; then php .travis.php $TRAVIS_BRANCH $COMPONENTS; fi + - if [[ ! $skip && $deps ]]; then git fetch origin $TRAVIS_BRANCH && php .github/travis.php FETCH_HEAD $TRAVIS_BRANCH $COMPONENTS; fi # For the master branch when deps=high, the version before master is checked out and tested with the locally patched components - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//); else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*'); fi - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); ./phpunit install; fi diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml index 9d7b893f20..5c1f78b1c4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml @@ -61,5 +61,9 @@ + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 5c1f43b4d6..db6b040039 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -24,7 +24,7 @@ "symfony/config": "~2.8|~3.0", "symfony/event-dispatcher": "~2.8|~3.0", "symfony/http-foundation": "~3.1", - "symfony/http-kernel": "~3.1", + "symfony/http-kernel": "~3.1.2|~3.2", "symfony/polyfill-mbstring": "~1.0", "symfony/filesystem": "~2.8|~3.0", "symfony/finder": "~2.8|~3.0", diff --git a/src/Symfony/Component/HttpKernel/EventListener/ValidateRequestListener.php b/src/Symfony/Component/HttpKernel/EventListener/ValidateRequestListener.php new file mode 100644 index 0000000000..00096ccf9e --- /dev/null +++ b/src/Symfony/Component/HttpKernel/EventListener/ValidateRequestListener.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; + +/** + * Validates that the headers and other information indicating the + * client IP address of a request are consistent. + * + * @author Magnus Nordlander + */ +class ValidateRequestListener implements EventSubscriberInterface +{ + /** + * Performs the validation. + * + * @param GetResponseEvent $event + */ + public function onKernelRequest(GetResponseEvent $event) + { + if (!$event->isMasterRequest()) { + return; + } + $request = $event->getRequest(); + + if ($request::getTrustedProxies()) { + // This will throw an exception if the headers are inconsistent. + $request->getClientIps(); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array( + KernelEvents::REQUEST => array( + array('onKernelRequest', 256), + ), + ); + } +} diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 573a1e232d..c63a6af832 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -67,6 +67,9 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface try { return $this->handleRaw($request, $type); } catch (\Exception $e) { + if ($e instanceof ConflictingHeadersException) { + $e = new BadRequestHttpException('The request headers contain conflicting information regarding the origin of this request.', $e); + } if (false === $catch) { $this->finishRequest($request, $type); @@ -119,13 +122,6 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface */ private function handleRaw(Request $request, $type = self::MASTER_REQUEST) { - if (self::MASTER_REQUEST === $type && $request::getTrustedProxies()) { - try { - $request->getClientIps(); - } catch (ConflictingHeadersException $e) { - throw new BadRequestHttpException('The request headers contain conflicting information regarding the origin of this request.', $e); - } - } $this->requestStack->push($request); // request diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php new file mode 100644 index 0000000000..842a3869cb --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php @@ -0,0 +1,42 @@ + + * + * 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\EventDispatcher\EventDispatcher; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\EventListener\ValidateRequestListener; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\KernelEvents; + +class ValidateRequestListenerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @expectedException Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException + */ + public function testListenerThrowsWhenMasterRequestHasInconsistentClientIps() + { + $dispatcher = new EventDispatcher(); + $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); + + $request = new Request(); + $request->setTrustedProxies(array('1.1.1.1')); + $request->server->set('REMOTE_ADDR', '1.1.1.1'); + $request->headers->set('FORWARDED', '2.2.2.2'); + $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); + + $dispatcher->addListener(KernelEvents::REQUEST, array(new ValidateRequestListener(), 'onKernelRequest')); + $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + + $dispatcher->dispatch(KernelEvents::REQUEST, $event); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php index 66de833045..8587aa3aae 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php @@ -307,28 +307,21 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase */ public function testInconsistentClientIpsOnMasterRequests() { - $kernel = $this->getHttpKernel(new EventDispatcher()); $request = new Request(); $request->setTrustedProxies(array('1.1.1.1')); $request->server->set('REMOTE_ADDR', '1.1.1.1'); $request->headers->set('FORWARDED', '2.2.2.2'); $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); + $dispatcher = new EventDispatcher(); + $dispatcher->addListener(KernelEvents::REQUEST, function ($event) { + $event->getRequest()->getClientIp(); + }); + + $kernel = $this->getHttpKernel($dispatcher); $kernel->handle($request, $kernel::MASTER_REQUEST, false); } - public function testInconsistentClientIpsOnSubRequests() - { - $kernel = $this->getHttpKernel(new EventDispatcher()); - $request = new Request(); - $request->setTrustedProxies(array('1.1.1.1')); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('FORWARDED', '2.2.2.2'); - $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); - - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $kernel->handle($request, $kernel::SUB_REQUEST, false)); - } - private function getHttpKernel(EventDispatcherInterface $eventDispatcher, $controller = null, RequestStack $requestStack = null, array $arguments = array()) { if (null === $controller) {