From 59ad99d345eb75ddd0d7e5f70e7f5dccc2a87607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Fri, 30 Dec 2011 12:34:47 +0100 Subject: [PATCH 1/3] [Routing] Added host requirement --- .../Routing/Generator/UrlGenerator.php | 7 ++++++- .../Matcher/Dumper/ApacheMatcherDumper.php | 4 ++++ .../Routing/Matcher/Dumper/PhpMatcherDumper.php | 10 +++++++++- .../Component/Routing/Matcher/UrlMatcher.php | 6 ++++++ .../Routing/Matcher/UrlMatcherTest.php | 17 +++++++++++++++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 535f7bb870e5c..8a47e16400ec9 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -146,10 +146,15 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa if ($this->context->getHost()) { $scheme = $this->context->getScheme(); + $host = $this->context->getHost(); if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme != $req) { $absolute = true; $scheme = $req; } + if (isset($requirements['_host']) && ($req = $requirements['_host']) && $host != $req) { + $absolute = true; + $host = $req; + } if ($absolute) { $port = ''; @@ -159,7 +164,7 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa $port = ':'.$this->context->getHttpsPort(); } - $url = $scheme.'://'.$this->context->getHost().$port.$url; + $url = $scheme.'://'.$host.$port.$url; } } diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php index 0b3836a3a2993..d3ad3b1bcbcea 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php @@ -68,6 +68,10 @@ public function dump(array $options = array()) $rule = array("# $name"); + if($hostreq = $route->getRequirement('_host')) { + $rule[] = "RewriteCond %{HTTP_HOST} $hostreq"; + } + // method mismatch if ($req = $route->getRequirement('_method')) { $methods = explode('|', strtoupper($req)); diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php index d6987caff7a66..500e38920985c 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php @@ -179,6 +179,14 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren if ($conditions) { EOF; + if ($hostreq = $route->getRequirement('_host')) { + $code[] = <<context->getHost() !== '$hostreq') { + goto $gotoname; + } +EOF; + } + if ($req = $route->getRequirement('_method')) { $methods = explode('|', strtoupper($req)); // GET and HEAD are equivalent @@ -239,7 +247,7 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren } $code[] = " }"; - if ($req) { + if ($req || $hostreq) { $code[] = " $gotoname:"; } diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php index 5d30ae9bfbc53..894a25e4a2182 100644 --- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php +++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php @@ -112,6 +112,12 @@ protected function matchCollection($pathinfo, RouteCollection $routes) continue; } + if ($hostreq = $route->getRequirement('_host')) { + if ($hostreq !== $this->context->getHost()) { + continue; + } + } + // check HTTP method requirement if ($req = $route->getRequirement('_method')) { // HEAD and GET are equivalent as per RFC diff --git a/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php b/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php index 3eb13e07fe110..6f983fafa355a 100644 --- a/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php +++ b/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php @@ -29,6 +29,23 @@ public function testNoMethodSoAllowed() $matcher->match('/foo'); } + public function testHostRequirement() + { + $coll = new RouteCollection(); + $coll->add('foo', new Route('/foo', array(), array('_host' => 'example.org'))); + + $matcher = new UrlMatcher($coll, new RequestContext('', 'get', 'example.org')); + $this->assertEquals(array('_route' => 'foo'), $matcher->match( '/foo' ) ); + + + $matcher = new UrlMatcher($coll, new RequestContext('', 'get', 'other.host')); + try { + $matcher->match( '/foo' ); + $this->fail(); + } catch (ResourceNotFoundException $e) {} + + } + public function testMethodNotAllowed() { $coll = new RouteCollection(); From 12bef9ff84391e60d0e982db8e20d4e439f2487a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Fri, 30 Dec 2011 13:07:32 +0100 Subject: [PATCH 2/3] [Routing] Added tests for host requirement --- .../Routing/Matcher/Dumper/PhpMatcherDumper.php | 6 +++--- .../Routing/Fixtures/dumper/url_matcher1.apache | 5 +++++ .../Routing/Fixtures/dumper/url_matcher1.php | 9 +++++++++ .../Routing/Fixtures/dumper/url_matcher2.php | 12 ++++++++++++ .../Component/Routing/Generator/UrlGeneratorTest.php | 8 ++++++++ .../Matcher/Dumper/ApacheMatcherDumperTest.php | 6 ++++++ .../Routing/Matcher/Dumper/PhpMatcherDumperTest.php | 6 ++++++ .../Component/Routing/Matcher/UrlMatcherTest.php | 9 ++++----- 8 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php index 500e38920985c..34695f7c08f2f 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php @@ -181,9 +181,9 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren if ($hostreq = $route->getRequirement('_host')) { $code[] = <<context->getHost() !== '$hostreq') { - goto $gotoname; - } + if(\$this->context->getHost() !== '$hostreq') { + goto $gotoname; + } EOF; } diff --git a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.apache b/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.apache index 9f4a7b49f4486..04dce176507ca 100644 --- a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.apache +++ b/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.apache @@ -6,6 +6,11 @@ RewriteRule .* - [QSA,L] RewriteCond %{REQUEST_URI} ^/foo/(baz|symfony)$ RewriteRule .* app.php [QSA,L,E=_ROUTING__route:foo,E=_ROUTING_bar:%1,E=_ROUTING_def:test] +# hostbar +RewriteCond %{HTTP_HOST} example.org +RewriteCond %{REQUEST_URI} ^/hostbar$ +RewriteRule .* app.php [QSA,L,E=_ROUTING__route:hostbar] + # bar RewriteCond %{REQUEST_URI} ^/bar/([^/]+?)$ RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC] diff --git a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.php b/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.php index 7932944a34506..cae3c0e4f977a 100644 --- a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.php +++ b/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.php @@ -41,6 +41,15 @@ public function match($pathinfo) } not_bar: + // barhost + if ($pathinfo === '/bar/') { + if($this->context->getHost() !== 'example.org') { + goto not_barhost; + } + return array('_route' => 'barhost'); + } + not_barhost: + // barhead if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P[^/]+?)$#xs', $pathinfo, $matches)) { if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) { diff --git a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher2.php b/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher2.php index d0f1e31381804..b0e65098af351 100644 --- a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher2.php +++ b/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher2.php @@ -41,6 +41,18 @@ public function match($pathinfo) } not_bar: + // barhost + if (rtrim($pathinfo, '/') === '/bar') { + if($this->context->getHost() !== 'example.org') { + goto not_barhost; + } + if (substr($pathinfo, -1) !== '/') { + return $this->redirect($pathinfo.'/', 'barhost'); + } + return array('_route' => 'barhost'); + } + not_barhost: + // barhead if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P[^/]+?)$#xs', $pathinfo, $matches)) { if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) { diff --git a/tests/Symfony/Tests/Component/Routing/Generator/UrlGeneratorTest.php b/tests/Symfony/Tests/Component/Routing/Generator/UrlGeneratorTest.php index 17b4d3c3bfcc2..50477103ad4fd 100644 --- a/tests/Symfony/Tests/Component/Routing/Generator/UrlGeneratorTest.php +++ b/tests/Symfony/Tests/Component/Routing/Generator/UrlGeneratorTest.php @@ -18,6 +18,14 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase { + public function testAbsoluteUrlWithHost() + { + $routes = $this->getRoutes('test', new Route( '/testing', array(), array('_host' => 'example.org'))); + $url = $this->getGenerator($routes)->generate('test', array(), true); + + $this->assertEquals('http://example.org/app.php/testing', $url); + } + public function testAbsoluteUrlWithPort80() { $routes = $this->getRoutes('test', new Route('/testing')); diff --git a/tests/Symfony/Tests/Component/Routing/Matcher/Dumper/ApacheMatcherDumperTest.php b/tests/Symfony/Tests/Component/Routing/Matcher/Dumper/ApacheMatcherDumperTest.php index 34be50c96d778..df9d889aab7db 100644 --- a/tests/Symfony/Tests/Component/Routing/Matcher/Dumper/ApacheMatcherDumperTest.php +++ b/tests/Symfony/Tests/Component/Routing/Matcher/Dumper/ApacheMatcherDumperTest.php @@ -34,6 +34,12 @@ public function testDump() array('def' => 'test'), array('bar' => 'baz|symfony') )); + // host requirement + $collection->add('hostbar', new Route( + '/hostbar', + array(), + array('_host' => 'example.org') + )); // method requirement $collection->add('bar', new Route( '/bar/{foo}', diff --git a/tests/Symfony/Tests/Component/Routing/Matcher/Dumper/PhpMatcherDumperTest.php b/tests/Symfony/Tests/Component/Routing/Matcher/Dumper/PhpMatcherDumperTest.php index ec8b6688d64b0..df6b32dc6c8f5 100644 --- a/tests/Symfony/Tests/Component/Routing/Matcher/Dumper/PhpMatcherDumperTest.php +++ b/tests/Symfony/Tests/Component/Routing/Matcher/Dumper/PhpMatcherDumperTest.php @@ -78,6 +78,12 @@ protected function getRouteCollection() array(), array('_method' => 'GET|head') )); + // host requirement + $collection->add('barhost', new Route( + '/bar/', + array(), + array('_host' => 'example.org') + )); // GET method requirement automatically adds HEAD as valid $collection->add('barhead', new Route( '/barhead/{foo}', diff --git a/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php b/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php index 6f983fafa355a..45a78e29e4cd3 100644 --- a/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php +++ b/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php @@ -29,21 +29,20 @@ public function testNoMethodSoAllowed() $matcher->match('/foo'); } - public function testHostRequirement() + public function testHostRequirement() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo', array(), array('_host' => 'example.org'))); $matcher = new UrlMatcher($coll, new RequestContext('', 'get', 'example.org')); - $this->assertEquals(array('_route' => 'foo'), $matcher->match( '/foo' ) ); + $this->assertEquals(array('_route' => 'foo'), $matcher->match('/foo')); + $matcher = new UrlMatcher($coll, new RequestContext('', 'get', 'other.host')); - $matcher = new UrlMatcher($coll, new RequestContext('', 'get', 'other.host')); try { - $matcher->match( '/foo' ); + $matcher->match('/foo'); $this->fail(); } catch (ResourceNotFoundException $e) {} - } public function testMethodNotAllowed() From a7ff989e33f0161e024f373b3232b6e2457ee334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6rl?= Date: Fri, 30 Dec 2011 14:33:29 +0100 Subject: [PATCH 3/3] [Routing] CS fix and structure change --- .../Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php | 2 +- src/Symfony/Component/Routing/Matcher/UrlMatcher.php | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php index d3ad3b1bcbcea..6c68e4fdfa04c 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php @@ -68,7 +68,7 @@ public function dump(array $options = array()) $rule = array("# $name"); - if($hostreq = $route->getRequirement('_host')) { + if ($hostreq = $route->getRequirement('_host')) { $rule[] = "RewriteCond %{HTTP_HOST} $hostreq"; } diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php index 894a25e4a2182..615325c15d61c 100644 --- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php +++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php @@ -112,10 +112,9 @@ protected function matchCollection($pathinfo, RouteCollection $routes) continue; } - if ($hostreq = $route->getRequirement('_host')) { - if ($hostreq !== $this->context->getHost()) { + // check host requirement + if (($req = $route->getRequirement('_host')) && $req !== $this->context->getHost()) { continue; - } } // check HTTP method requirement