[Routing] added support for hostname in the apache matcher dumper
This commit is contained in:
parent
562174a822
commit
a8ce6210b3
@ -46,17 +46,55 @@ class ApacheMatcherDumper extends MatcherDumper
|
|||||||
|
|
||||||
$rules = array("# skip \"real\" requests\nRewriteCond %{REQUEST_FILENAME} -f\nRewriteRule .* - [QSA,L]");
|
$rules = array("# skip \"real\" requests\nRewriteCond %{REQUEST_FILENAME} -f\nRewriteRule .* - [QSA,L]");
|
||||||
$methodVars = array();
|
$methodVars = array();
|
||||||
|
$hostnameRegexUnique = 0;
|
||||||
|
$prevHosnameRegex = '';
|
||||||
|
|
||||||
foreach ($this->getRoutes()->all() as $name => $route) {
|
foreach ($this->getRoutes()->all() as $name => $route) {
|
||||||
$rules[] = $this->dumpRoute($name, $route, $options);
|
|
||||||
$methodVars = array_merge($methodVars, $this->getRouteMethods($route));
|
$compiledRoute = $route->compile();
|
||||||
|
$hostnameRegex = $compiledRoute->getHostnameRegex();
|
||||||
|
|
||||||
|
if (null !== $hostnameRegex && $prevHosnameRegex !== $hostnameRegex) {
|
||||||
|
|
||||||
|
$prevHosnameRegex = $hostnameRegex;
|
||||||
|
$hostnameRegexUnique++;
|
||||||
|
|
||||||
|
$rule = array();
|
||||||
|
|
||||||
|
$regex = $this->regexToApacheRegex($hostnameRegex);
|
||||||
|
$regex = self::escape($regex, ' ', '\\');
|
||||||
|
|
||||||
|
$rule[] = sprintf('RewriteCond %%{HTTP:Host} %s', $regex);
|
||||||
|
|
||||||
|
$variables = array();
|
||||||
|
$variables[] = sprintf('E=__ROUTING_hostname_%s:1', $hostnameRegexUnique);
|
||||||
|
|
||||||
|
foreach ($compiledRoute->getHostnameVariables() as $i => $variable) {
|
||||||
|
$variables[] = sprintf('E=__ROUTING_hostname_%s_%s:%%%d', $hostnameRegexUnique, $variable, $i+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$variables = implode(',', $variables);
|
||||||
|
|
||||||
|
$rule[] = sprintf('RewriteRule .? - [%s]', $variables);
|
||||||
|
|
||||||
|
$rules[] = implode("\n", $rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rules[] = $this->dumpRoute($name, $route, $options, $hostnameRegexUnique);
|
||||||
|
|
||||||
|
if ($req = $route->getRequirement('_method')) {
|
||||||
|
$methods = explode('|', strtoupper($req));
|
||||||
|
$methodVars = array_merge($methodVars, $methods);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (0 < count($methodVars)) {
|
if (0 < count($methodVars)) {
|
||||||
$rule = array('# 405 Method Not Allowed');
|
$rule = array('# 405 Method Not Allowed');
|
||||||
$methodVars = array_values(array_unique($methodVars));
|
$methodVars = array_values(array_unique($methodVars));
|
||||||
|
if (in_array('GET', $methodVars) && !in_array('HEAD', $methodVars)) {
|
||||||
|
$methodVars[] = 'HEAD';
|
||||||
|
}
|
||||||
foreach ($methodVars as $i => $methodVar) {
|
foreach ($methodVars as $i => $methodVar) {
|
||||||
$rule[] = sprintf('RewriteCond %%{_ROUTING_allow_%s} !-z%s', $methodVar, isset($methodVars[$i + 1]) ? ' [OR]' : '');
|
$rule[] = sprintf('RewriteCond %%{ENV:_ROUTING__allow_%s} =1%s', $methodVar, isset($methodVars[$i + 1]) ? ' [OR]' : '');
|
||||||
}
|
}
|
||||||
$rule[] = sprintf('RewriteRule .* %s [QSA,L]', $options['script_name']);
|
$rule[] = sprintf('RewriteRule .* %s [QSA,L]', $options['script_name']);
|
||||||
|
|
||||||
@ -66,7 +104,16 @@ class ApacheMatcherDumper extends MatcherDumper
|
|||||||
return implode("\n\n", $rules)."\n";
|
return implode("\n\n", $rules)."\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
private function dumpRoute($name, $route, array $options)
|
/**
|
||||||
|
* Dumps a single route
|
||||||
|
*
|
||||||
|
* @param string $name Route name
|
||||||
|
* @param Route $route The route
|
||||||
|
* @param array $options Options
|
||||||
|
* @param bool $hostnameRegexUnique Unique identifier for the hostname regex
|
||||||
|
* @return string The compiled route
|
||||||
|
*/
|
||||||
|
private function dumpRoute($name, $route, array $options, $hostnameRegexUnique)
|
||||||
{
|
{
|
||||||
$compiledRoute = $route->compile();
|
$compiledRoute = $route->compile();
|
||||||
|
|
||||||
@ -79,7 +126,10 @@ class ApacheMatcherDumper extends MatcherDumper
|
|||||||
$hasTrailingSlash = (!$methods || in_array('HEAD', $methods)) && '/$' === substr($regex, -2) && '^/$' !== $regex;
|
$hasTrailingSlash = (!$methods || in_array('HEAD', $methods)) && '/$' === substr($regex, -2) && '^/$' !== $regex;
|
||||||
|
|
||||||
$variables = array('E=_ROUTING_route:'.$name);
|
$variables = array('E=_ROUTING_route:'.$name);
|
||||||
foreach ($compiledRoute->getVariables() as $i => $variable) {
|
foreach ($compiledRoute->getHostnameVariables() as $variable) {
|
||||||
|
$variables[] = sprintf('E=_ROUTING_param_%s:%%{ENV:__ROUTING_hostname_%s_%s}', $variable, $hostnameRegexUnique, $variable);
|
||||||
|
}
|
||||||
|
foreach ($compiledRoute->getPathVariables() as $i => $variable) {
|
||||||
$variables[] = 'E=_ROUTING_param_'.$variable.':%'.($i + 1);
|
$variables[] = 'E=_ROUTING_param_'.$variable.':%'.($i + 1);
|
||||||
}
|
}
|
||||||
foreach ($route->getDefaults() as $key => $value) {
|
foreach ($route->getDefaults() as $key => $value) {
|
||||||
@ -98,10 +148,13 @@ class ApacheMatcherDumper extends MatcherDumper
|
|||||||
if (0 < count($methods)) {
|
if (0 < count($methods)) {
|
||||||
$allow = array();
|
$allow = array();
|
||||||
foreach ($methods as $method) {
|
foreach ($methods as $method) {
|
||||||
$methodVars[] = $method;
|
|
||||||
$allow[] = 'E=_ROUTING_allow_'.$method.':1';
|
$allow[] = 'E=_ROUTING_allow_'.$method.':1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($hostnameRegex = $compiledRoute->getHostnameRegex()) {
|
||||||
|
$rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_hostname_%s} =1", $hostnameRegexUnique);
|
||||||
|
}
|
||||||
|
|
||||||
$rule[] = "RewriteCond %{REQUEST_URI} $regex";
|
$rule[] = "RewriteCond %{REQUEST_URI} $regex";
|
||||||
$rule[] = sprintf("RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]", implode('|', $methods));
|
$rule[] = sprintf("RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]", implode('|', $methods));
|
||||||
$rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow));
|
$rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow));
|
||||||
@ -109,11 +162,21 @@ class ApacheMatcherDumper extends MatcherDumper
|
|||||||
|
|
||||||
// redirect with trailing slash appended
|
// redirect with trailing slash appended
|
||||||
if ($hasTrailingSlash) {
|
if ($hasTrailingSlash) {
|
||||||
|
|
||||||
|
if ($hostnameRegex = $compiledRoute->getHostnameRegex()) {
|
||||||
|
$rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_hostname_%s} =1", $hostnameRegexUnique);
|
||||||
|
}
|
||||||
|
|
||||||
$rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$';
|
$rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$';
|
||||||
$rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]';
|
$rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]';
|
||||||
}
|
}
|
||||||
|
|
||||||
// the main rule
|
// the main rule
|
||||||
|
|
||||||
|
if ($hostnameRegex = $compiledRoute->getHostnameRegex()) {
|
||||||
|
$rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_hostname_%s} =1", $hostnameRegexUnique);
|
||||||
|
}
|
||||||
|
|
||||||
$rule[] = "RewriteCond %{REQUEST_URI} $regex";
|
$rule[] = "RewriteCond %{REQUEST_URI} $regex";
|
||||||
$rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]";
|
$rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]";
|
||||||
|
|
||||||
|
@ -68,8 +68,96 @@ RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz6,E=_ROUTING_default_foo:bar\
|
|||||||
RewriteCond %{REQUEST_URI} ^/te\ st/baz$
|
RewriteCond %{REQUEST_URI} ^/te\ st/baz$
|
||||||
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz7]
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz7]
|
||||||
|
|
||||||
|
# baz8
|
||||||
|
RewriteCond %{REQUEST_URI} ^/te\\\ st/baz$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz8]
|
||||||
|
|
||||||
|
# baz9
|
||||||
|
RewriteCond %{REQUEST_URI} ^/test/(te\\\ st)$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz9,E=_ROUTING_param_baz:%1]
|
||||||
|
|
||||||
|
RewriteCond %{HTTP:Host} ^a\.example\.com$
|
||||||
|
RewriteRule .? - [E=__ROUTING_hostname_1:1]
|
||||||
|
|
||||||
|
# route1
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_1} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route1$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route1]
|
||||||
|
|
||||||
|
# route2
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_1} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/c2/route2$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route2]
|
||||||
|
|
||||||
|
RewriteCond %{HTTP:Host} ^b\.example\.com$
|
||||||
|
RewriteRule .? - [E=__ROUTING_hostname_2:1]
|
||||||
|
|
||||||
|
# route3
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_2} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/c2/route3$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route3]
|
||||||
|
|
||||||
|
RewriteCond %{HTTP:Host} ^a\.example\.com$
|
||||||
|
RewriteRule .? - [E=__ROUTING_hostname_3:1]
|
||||||
|
|
||||||
|
# route4
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_3} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route4$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route4]
|
||||||
|
|
||||||
|
RewriteCond %{HTTP:Host} ^c\.example\.com$
|
||||||
|
RewriteRule .? - [E=__ROUTING_hostname_4:1]
|
||||||
|
|
||||||
|
# route5
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_4} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route5$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route5]
|
||||||
|
|
||||||
|
# route6
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route6$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route6]
|
||||||
|
|
||||||
|
RewriteCond %{HTTP:Host} ^([^\.]++)\.example\.com$
|
||||||
|
RewriteRule .? - [E=__ROUTING_hostname_5:1,E=__ROUTING_hostname_5_var1:%1]
|
||||||
|
|
||||||
|
# route11
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_5} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route11$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route11,E=_ROUTING_param_var1:%{ENV:__ROUTING_hostname_5_var1}]
|
||||||
|
|
||||||
|
# route12
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_5} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route12$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route12,E=_ROUTING_param_var1:%{ENV:__ROUTING_hostname_5_var1},E=_ROUTING_default_var1:val]
|
||||||
|
|
||||||
|
# route13
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_5} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route13/([^/]++)$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route13,E=_ROUTING_param_var1:%{ENV:__ROUTING_hostname_5_var1},E=_ROUTING_param_name:%1]
|
||||||
|
|
||||||
|
# route14
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_5} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route14/([^/]++)$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route14,E=_ROUTING_param_var1:%{ENV:__ROUTING_hostname_5_var1},E=_ROUTING_param_name:%1,E=_ROUTING_default_var1:val]
|
||||||
|
|
||||||
|
RewriteCond %{HTTP:Host} ^c\.example\.com$
|
||||||
|
RewriteRule .? - [E=__ROUTING_hostname_6:1]
|
||||||
|
|
||||||
|
# route15
|
||||||
|
RewriteCond %{ENV:__ROUTING_hostname_6} =1
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route15/([^/]++)$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route15,E=_ROUTING_param_name:%1]
|
||||||
|
|
||||||
|
# route16
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route16/([^/]++)$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route16,E=_ROUTING_param_name:%1,E=_ROUTING_default_var1:val]
|
||||||
|
|
||||||
|
# route17
|
||||||
|
RewriteCond %{REQUEST_URI} ^/route17$
|
||||||
|
RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route17]
|
||||||
|
|
||||||
# 405 Method Not Allowed
|
# 405 Method Not Allowed
|
||||||
RewriteCond %{_ROUTING_allow_GET} !-z [OR]
|
RewriteCond %{ENV:_ROUTING__allow_GET} =1 [OR]
|
||||||
RewriteCond %{_ROUTING_allow_HEAD} !-z [OR]
|
RewriteCond %{ENV:_ROUTING__allow_HEAD} =1 [OR]
|
||||||
RewriteCond %{_ROUTING_allow_POST} !-z
|
RewriteCond %{ENV:_ROUTING__allow_POST} =1
|
||||||
RewriteRule .* app.php [QSA,L]
|
RewriteRule .* app.php [QSA,L]
|
||||||
|
@ -118,6 +118,20 @@ class ApacheUrlMatcherTest extends \PHPUnit_Framework_TestCase
|
|||||||
'_route' => 'hello',
|
'_route' => 'hello',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'REDIRECT_REDIRECT_ envs',
|
||||||
|
'/hello/world',
|
||||||
|
array(
|
||||||
|
'REDIRECT_REDIRECT__ROUTING_route' => 'hello',
|
||||||
|
'REDIRECT_REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
|
||||||
|
'REDIRECT_REDIRECT__ROUTING_param_name' => 'world',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'_controller' => 'AcmeBundle:Default:index',
|
||||||
|
'name' => 'world',
|
||||||
|
'_route' => 'hello',
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,71 @@ class ApacheMatcherDumperTest extends \PHPUnit_Framework_TestCase
|
|||||||
$collection->add('baz7', new Route(
|
$collection->add('baz7', new Route(
|
||||||
'/te st/baz'
|
'/te st/baz'
|
||||||
));
|
));
|
||||||
|
// space preceded with \ in path
|
||||||
|
$collection->add('baz8', new Route(
|
||||||
|
'/te\\ st/baz'
|
||||||
|
));
|
||||||
|
// space preceded with \ in requirement
|
||||||
|
$collection->add('baz9', new Route(
|
||||||
|
'/test/{baz}',
|
||||||
|
array(),
|
||||||
|
array(
|
||||||
|
'baz' => 'te\\\\ st',
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
$collection1 = new RouteCollection();
|
||||||
|
|
||||||
|
$route1 = new Route('/route1', array(), array(), array(), 'a.example.com');
|
||||||
|
$collection1->add('route1', $route1);
|
||||||
|
|
||||||
|
$collection2 = new RouteCollection();
|
||||||
|
|
||||||
|
$route2 = new Route('/route2', array(), array(), array(), 'a.example.com');
|
||||||
|
$collection2->add('route2', $route2);
|
||||||
|
|
||||||
|
$route3 = new Route('/route3', array(), array(), array(), 'b.example.com');
|
||||||
|
$collection2->add('route3', $route3);
|
||||||
|
|
||||||
|
$collection1->addCollection($collection2, '/c2');
|
||||||
|
|
||||||
|
$route4 = new Route('/route4', array(), array(), array(), 'a.example.com');
|
||||||
|
$collection1->add('route4', $route4);
|
||||||
|
|
||||||
|
$route5 = new Route('/route5', array(), array(), array(), 'c.example.com');
|
||||||
|
$collection1->add('route5', $route5);
|
||||||
|
|
||||||
|
$route6 = new Route('/route6', array(), array(), array(), null);
|
||||||
|
$collection1->add('route6', $route6);
|
||||||
|
|
||||||
|
$collection->addCollection($collection1);
|
||||||
|
|
||||||
|
// hostname and variables
|
||||||
|
|
||||||
|
$collection1 = new RouteCollection();
|
||||||
|
|
||||||
|
$route11 = new Route('/route11', array(), array(), array(), '{var1}.example.com');
|
||||||
|
$collection1->add('route11', $route11);
|
||||||
|
|
||||||
|
$route12 = new Route('/route12', array('var1' => 'val'), array(), array(), '{var1}.example.com');
|
||||||
|
$collection1->add('route12', $route12);
|
||||||
|
|
||||||
|
$route13 = new Route('/route13/{name}', array(), array(), array(), '{var1}.example.com');
|
||||||
|
$collection1->add('route13', $route13);
|
||||||
|
|
||||||
|
$route14 = new Route('/route14/{name}', array('var1' => 'val'), array(), array(), '{var1}.example.com');
|
||||||
|
$collection1->add('route14', $route14);
|
||||||
|
|
||||||
|
$route15 = new Route('/route15/{name}', array(), array(), array(), 'c.example.com');
|
||||||
|
$collection1->add('route15', $route15);
|
||||||
|
|
||||||
|
$route16 = new Route('/route16/{name}', array('var1' => 'val'), array(), array(), null);
|
||||||
|
$collection1->add('route16', $route16);
|
||||||
|
|
||||||
|
$route17 = new Route('/route17', array(), array(), array(), null);
|
||||||
|
$collection1->add('route17', $route17);
|
||||||
|
|
||||||
|
$collection->addCollection($collection1);
|
||||||
|
|
||||||
return $collection;
|
return $collection;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user