Skip to content

Commit f9ffdf5

Browse files
committed
[Routing] added proper support for the HEAD method
1 parent 9eae7e5 commit f9ffdf5

File tree

8 files changed

+62
-9
lines changed

8 files changed

+62
-9
lines changed

src/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php

+8-3
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,20 @@ public function dump(array $options = array())
6969
$rule = array("# $name");
7070

7171
// method mismatch
72-
if ($req = strtolower($route->getRequirement('_method'))) {
72+
if ($req = $route->getRequirement('_method')) {
73+
$methods = explode('|', strtolower($req));
74+
// GET and HEAD are equivalent
75+
if (in_array('get', $methods) && !in_array('head', $methods)) {
76+
$methods[] = 'head';
77+
}
7378
$allow = array();
74-
foreach (explode('|', $req) as $method) {
79+
foreach ($methods as $method) {
7580
$methodVars[] = $method;
7681
$allow[] = 'E=_ROUTING__allow_'.$method.':1';
7782
}
7883

7984
$rule[] = "RewriteCond %{REQUEST_URI} $regex";
80-
$rule[] = "RewriteCond %{REQUEST_METHOD} !^($req)$ [NC]";
85+
$rule[] = sprintf("RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]", implode('|', $methods));
8186
$rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow));
8287
}
8388

src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ private function compileRoute(Route $route, $name, $supportsRedirections)
137137
EOF;
138138

139139
if ($req = $route->getRequirement('_method')) {
140-
$methods = array_map('strtolower', explode('|', $req));
140+
$methods = explode('|', strtolower($req));
141+
// GET and HEAD are equivalent
142+
if (in_array('get', $methods) && !in_array('head', $methods)) {
143+
$methods[] = 'head';
144+
}
141145
if (1 === count($methods)) {
142146
$code[] = <<<EOF
143147
if (\$this->context->getMethod() != '$methods[0]') {

src/Symfony/Component/Routing/Matcher/UrlMatcher.php

+10-3
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,17 @@ protected function matchCollection($pathinfo, RouteCollection $routes)
110110
}
111111

112112
// check HTTP method requirement
113-
if ($route->getRequirement('_method') && ($req = explode('|', $route->getRequirement('_method'))) && !in_array($this->context->getMethod(), array_map('strtolower', $req))) {
114-
$this->allow = array_merge($this->allow, $req);
113+
if ($req = $route->getRequirement('_method')) {
114+
// HEAD and GET are equivalent as per RFC
115+
if ('head' === $method = $this->context->getMethod()) {
116+
$method = 'get';
117+
}
115118

116-
continue;
119+
if (!in_array($method, $req = explode('|', strtolower($req)))) {
120+
$this->allow = array_merge($this->allow, $req);
121+
122+
continue;
123+
}
117124
}
118125

119126
return array_merge($this->mergeDefaults($matches, $route->getDefaults()), array('_route' => $name));

tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.apache

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ RewriteRule .* app.php [QSA,L,E=_ROUTING__route:bar,E=_ROUTING_foo:%1]
1515

1616
# baragain
1717
RewriteCond %{REQUEST_URI} ^/baragain/([^/]+?)$
18-
RewriteCond %{REQUEST_METHOD} !^(get|post)$ [NC]
19-
RewriteRule .* - [S=1,E=_ROUTING__allow_get:1,E=_ROUTING__allow_post:1]
18+
RewriteCond %{REQUEST_METHOD} !^(get|post|head)$ [NC]
19+
RewriteRule .* - [S=1,E=_ROUTING__allow_get:1,E=_ROUTING__allow_post:1,E=_ROUTING__allow_head:1]
2020
RewriteCond %{REQUEST_URI} ^/baragain/([^/]+?)$
2121
RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baragain,E=_ROUTING_foo:%1]
2222

tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.php

+11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ public function match($pathinfo)
4040
}
4141
not_bar:
4242

43+
// barhead
44+
if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P<foo>[^/]+?)$#x', $pathinfo, $matches)) {
45+
if (!in_array($this->context->getMethod(), array('get', 'head'))) {
46+
$allow = array_merge($allow, array('get', 'head'));
47+
goto not_barhead;
48+
}
49+
$matches['_route'] = 'barhead';
50+
return $matches;
51+
}
52+
not_barhead:
53+
4354
// baz
4455
if ($pathinfo === '/test/baz') {
4556
return array('_route' => 'baz');

tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher2.php

+11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ public function match($pathinfo)
4040
}
4141
not_bar:
4242

43+
// barhead
44+
if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P<foo>[^/]+?)$#x', $pathinfo, $matches)) {
45+
if (!in_array($this->context->getMethod(), array('get', 'head'))) {
46+
$allow = array_merge($allow, array('get', 'head'));
47+
goto not_barhead;
48+
}
49+
$matches['_route'] = 'barhead';
50+
return $matches;
51+
}
52+
not_barhead:
53+
4354
// baz
4455
if ($pathinfo === '/test/baz') {
4556
return array('_route' => 'baz');

tests/Symfony/Tests/Component/Routing/Matcher/Dumper/PhpMatcherDumperTest.php

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ public function testDump()
3434
array(),
3535
array('_method' => 'GET|head')
3636
));
37+
// GET method requirement automatically adds HEAD as valid
38+
$collection->add('barhead', new Route(
39+
'/barhead/{foo}',
40+
array(),
41+
array('_method' => 'GET')
42+
));
3743
// simple
3844
$collection->add('baz', new Route(
3945
'/test/baz'

tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ public function testMethodNotAllowed()
4444
}
4545
}
4646

47+
public function testHeadAllowedWhenRequirementContainsGet()
48+
{
49+
$coll = new RouteCollection();
50+
$coll->add('foo', new Route('/foo', array(), array('_method' => 'get')));
51+
52+
$matcher = new UrlMatcher($coll, new RequestContext('', 'head'));
53+
$matcher->match('/foo');
54+
}
55+
4756
public function testMethodNotAllowedAggregatesAllowedMethods()
4857
{
4958
$coll = new RouteCollection();

0 commit comments

Comments
 (0)