Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2e74341

Browse filesBrowse files
committed
bug #13567 [Routing] make host matching case-insensitive (Tobion)
This PR was merged into the 2.3 branch. Discussion ---------- [Routing] make host matching case-insensitive | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #9072 | License | MIT | Doc PR | Ignore case in host which means: - When generating URLs we leave the case in the host as specified. - When matching we always return lower-cased versions of parameters (because of https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/Routing/RequestContext.php#L190 ) in the host. This is also what browers do. They lowercase the host before sending the request, i.e. WWW.eXample.org is sent as www.example.org. But when using curl for example it sends the host as-is. So the HttpFoundation Request class can actually have a non-lowercased host because it doesn't have this normalization. Commits ------- 952388c [Routing] make host matching case-insensitive according to RFC 3986
2 parents 051402e + 952388c commit 2e74341
Copy full SHA for 2e74341

File tree

8 files changed

+48
-20
lines changed
Filter options

8 files changed

+48
-20
lines changed

‎src/Symfony/Component/Routing/Generator/UrlGenerator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Generator/UrlGenerator.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa
213213
$routeHost = '';
214214
foreach ($hostTokens as $token) {
215215
if ('variable' === $token[0]) {
216-
if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) {
216+
if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#i', $mergedParams[$token[3]])) {
217217
$message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]);
218218

219219
if ($this->strictRequirements) {

‎src/Symfony/Component/Routing/RouteCompiler.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/RouteCompiler.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public static function compile(Route $route)
4646
$result = self::compilePattern($route, $host, true);
4747

4848
$hostVariables = $result['variables'];
49-
$variables = array_merge($variables, $hostVariables);
49+
$variables = $hostVariables;
5050

5151
$hostTokens = $result['tokens'];
5252
$hostRegex = $result['regex'];
@@ -163,7 +163,7 @@ private static function compilePattern(Route $route, $pattern, $isHost)
163163

164164
return array(
165165
'staticPrefix' => 'text' === $tokens[0][0] ? $tokens[0][1] : '',
166-
'regex' => self::REGEX_DELIMITER.'^'.$regexp.'$'.self::REGEX_DELIMITER.'s',
166+
'regex' => self::REGEX_DELIMITER.'^'.$regexp.'$'.self::REGEX_DELIMITER.'s'.($isHost ? 'i' : ''),
167167
'tokens' => array_reverse($tokens),
168168
'variables' => $variables,
169169
);

‎src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
+6-6Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ public function match($pathinfo)
195195

196196
$host = $this->context->getHost();
197197

198-
if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
198+
if (preg_match('#^a\\.example\\.com$#si', $host, $hostMatches)) {
199199
// route1
200200
if ($pathinfo === '/route1') {
201201
return array('_route' => 'route1');
@@ -208,23 +208,23 @@ public function match($pathinfo)
208208

209209
}
210210

211-
if (preg_match('#^b\\.example\\.com$#s', $host, $hostMatches)) {
211+
if (preg_match('#^b\\.example\\.com$#si', $host, $hostMatches)) {
212212
// route3
213213
if ($pathinfo === '/c2/route3') {
214214
return array('_route' => 'route3');
215215
}
216216

217217
}
218218

219-
if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
219+
if (preg_match('#^a\\.example\\.com$#si', $host, $hostMatches)) {
220220
// route4
221221
if ($pathinfo === '/route4') {
222222
return array('_route' => 'route4');
223223
}
224224

225225
}
226226

227-
if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
227+
if (preg_match('#^c\\.example\\.com$#si', $host, $hostMatches)) {
228228
// route5
229229
if ($pathinfo === '/route5') {
230230
return array('_route' => 'route5');
@@ -237,7 +237,7 @@ public function match($pathinfo)
237237
return array('_route' => 'route6');
238238
}
239239

240-
if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#s', $host, $hostMatches)) {
240+
if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#si', $host, $hostMatches)) {
241241
if (0 === strpos($pathinfo, '/route1')) {
242242
// route11
243243
if ($pathinfo === '/route11') {
@@ -263,7 +263,7 @@ public function match($pathinfo)
263263

264264
}
265265

266-
if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
266+
if (preg_match('#^c\\.example\\.com$#si', $host, $hostMatches)) {
267267
// route15
268268
if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
269269
return $this->mergeDefaults(array_replace($matches, array('_route' => 'route15')), array ());

‎src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
+6-6Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ public function match($pathinfo)
207207

208208
$host = $this->context->getHost();
209209

210-
if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
210+
if (preg_match('#^a\\.example\\.com$#si', $host, $hostMatches)) {
211211
// route1
212212
if ($pathinfo === '/route1') {
213213
return array('_route' => 'route1');
@@ -220,23 +220,23 @@ public function match($pathinfo)
220220

221221
}
222222

223-
if (preg_match('#^b\\.example\\.com$#s', $host, $hostMatches)) {
223+
if (preg_match('#^b\\.example\\.com$#si', $host, $hostMatches)) {
224224
// route3
225225
if ($pathinfo === '/c2/route3') {
226226
return array('_route' => 'route3');
227227
}
228228

229229
}
230230

231-
if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
231+
if (preg_match('#^a\\.example\\.com$#si', $host, $hostMatches)) {
232232
// route4
233233
if ($pathinfo === '/route4') {
234234
return array('_route' => 'route4');
235235
}
236236

237237
}
238238

239-
if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
239+
if (preg_match('#^c\\.example\\.com$#si', $host, $hostMatches)) {
240240
// route5
241241
if ($pathinfo === '/route5') {
242242
return array('_route' => 'route5');
@@ -249,7 +249,7 @@ public function match($pathinfo)
249249
return array('_route' => 'route6');
250250
}
251251

252-
if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#s', $host, $hostMatches)) {
252+
if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#si', $host, $hostMatches)) {
253253
if (0 === strpos($pathinfo, '/route1')) {
254254
// route11
255255
if ($pathinfo === '/route11') {
@@ -275,7 +275,7 @@ public function match($pathinfo)
275275

276276
}
277277

278-
if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
278+
if (preg_match('#^c\\.example\\.com$#si', $host, $hostMatches)) {
279279
// route15
280280
if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
281281
return $this->mergeDefaults(array_replace($matches, array('_route' => 'route15')), array ());

‎src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,13 @@ public function testUrlWithInvalidParameterInHostInNonStrictMode()
443443
$this->assertNull($generator->generate('test', array('foo' => 'baz'), false));
444444
}
445445

446+
public function testHostIsCaseInsensitive()
447+
{
448+
$routes = $this->getRoutes('test', new Route('/', array(), array('locale' => 'en|de|fr'), array(), '{locale}.FooBar.com'));
449+
$generator = $this->getGenerator($routes);
450+
$this->assertSame('//EN.FooBar.com/app.php/', $generator->generate('test', array('locale' => 'EN'), UrlGeneratorInterface::NETWORK_PATH));
451+
}
452+
446453
public function testGenerateNetworkPath()
447454
{
448455
$routes = $this->getRoutes('test', new Route('/{name}', array(), array('_scheme' => 'http'), array(), '{locale}.example.com'));

‎src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,4 +382,25 @@ public function testWithOutHostHostDoesNotMatch()
382382
$matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'example.com'));
383383
$matcher->match('/foo/bar');
384384
}
385+
386+
/**
387+
* @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
388+
*/
389+
public function testPathIsCaseSensitive()
390+
{
391+
$coll = new RouteCollection();
392+
$coll->add('foo', new Route('/locale', array(), array('locale' => 'EN|FR|DE')));
393+
394+
$matcher = new UrlMatcher($coll, new RequestContext());
395+
$matcher->match('/en');
396+
}
397+
398+
public function testHostIsCaseInsensitive()
399+
{
400+
$coll = new RouteCollection();
401+
$coll->add('foo', new Route('/', array(), array('locale' => 'EN|FR|DE'), array(), '{locale}.example.com'));
402+
403+
$matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
404+
$this->assertEquals(array('_route' => 'foo', 'locale' => 'en'), $matcher->match('/'));
405+
}
385406
}

‎src/Symfony/Component/Routing/Tests/RouteCompilerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/RouteCompilerTest.php
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ public function provideCompileWithHostData()
208208
'/hello', '#^/hello$#s', array(), array(), array(
209209
array('text', '/hello'),
210210
),
211-
'#^www\.example\.com$#s', array(), array(
211+
'#^www\.example\.com$#si', array(), array(
212212
array('text', 'www.example.com'),
213213
),
214214
),
@@ -219,7 +219,7 @@ public function provideCompileWithHostData()
219219
array('variable', '/', '[^/]++', 'name'),
220220
array('text', '/hello'),
221221
),
222-
'#^www\.example\.(?P<tld>[^\.]++)$#s', array('tld'), array(
222+
'#^www\.example\.(?P<tld>[^\.]++)$#si', array('tld'), array(
223223
array('variable', '.', '[^\.]++', 'tld'),
224224
array('text', 'www.example'),
225225
),
@@ -230,7 +230,7 @@ public function provideCompileWithHostData()
230230
'/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
231231
array('text', '/hello'),
232232
),
233-
'#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#s', array('locale', 'tld'), array(
233+
'#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#si', array('locale', 'tld'), array(
234234
array('variable', '.', '[^\.]++', 'tld'),
235235
array('text', '.example'),
236236
array('variable', '', '[^\.]++', 'locale'),
@@ -242,7 +242,7 @@ public function provideCompileWithHostData()
242242
'/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
243243
array('text', '/hello'),
244244
),
245-
'#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#s', array('locale', 'tld'), array(
245+
'#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#si', array('locale', 'tld'), array(
246246
array('variable', '.', '[^\.]++', 'tld'),
247247
array('text', '.example'),
248248
array('variable', '', '[^\.]++', 'locale'),

‎src/Symfony/Component/Routing/Tests/RouteTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/RouteTest.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ public function testSerializeWhenCompiled()
247247
*/
248248
public function testSerializedRepresentationKeepsWorking()
249249
{
250-
$serialized = 'C:31:"Symfony\Component\Routing\Route":933:{a:8:{s:4:"path";s:13:"/prefix/{foo}";s:4:"host";s:20:"{locale}.example.net";s:8:"defaults";a:1:{s:3:"foo";s:7:"default";}s:12:"requirements";a:1:{s:3:"foo";s:3:"\d+";}s:7:"options";a:1:{s:14:"compiler_class";s:39:"Symfony\Component\Routing\RouteCompiler";}s:7:"schemes";a:0:{}s:7:"methods";a:0:{}s:8:"compiled";C:39:"Symfony\Component\Routing\CompiledRoute":568:{a:8:{s:4:"vars";a:2:{i:0;s:6:"locale";i:1;s:3:"foo";}s:11:"path_prefix";s:7:"/prefix";s:10:"path_regex";s:30:"#^/prefix(?:/(?P<foo>\d+))?$#s";s:11:"path_tokens";a:2:{i:0;a:4:{i:0;s:8:"variable";i:1;s:1:"/";i:2;s:3:"\d+";i:3;s:3:"foo";}i:1;a:2:{i:0;s:4:"text";i:1;s:7:"/prefix";}}s:9:"path_vars";a:1:{i:0;s:3:"foo";}s:10:"host_regex";s:38:"#^(?P<locale>[^\.]++)\.example\.net$#s";s:11:"host_tokens";a:2:{i:0;a:2:{i:0;s:4:"text";i:1;s:12:".example.net";}i:1;a:4:{i:0;s:8:"variable";i:1;s:0:"";i:2;s:7:"[^\.]++";i:3;s:6:"locale";}}s:9:"host_vars";a:1:{i:0;s:6:"locale";}}}}}';
250+
$serialized = 'C:31:"Symfony\Component\Routing\Route":934:{a:8:{s:4:"path";s:13:"/prefix/{foo}";s:4:"host";s:20:"{locale}.example.net";s:8:"defaults";a:1:{s:3:"foo";s:7:"default";}s:12:"requirements";a:1:{s:3:"foo";s:3:"\d+";}s:7:"options";a:1:{s:14:"compiler_class";s:39:"Symfony\Component\Routing\RouteCompiler";}s:7:"schemes";a:0:{}s:7:"methods";a:0:{}s:8:"compiled";C:39:"Symfony\Component\Routing\CompiledRoute":569:{a:8:{s:4:"vars";a:2:{i:0;s:6:"locale";i:1;s:3:"foo";}s:11:"path_prefix";s:7:"/prefix";s:10:"path_regex";s:30:"#^/prefix(?:/(?P<foo>\d+))?$#s";s:11:"path_tokens";a:2:{i:0;a:4:{i:0;s:8:"variable";i:1;s:1:"/";i:2;s:3:"\d+";i:3;s:3:"foo";}i:1;a:2:{i:0;s:4:"text";i:1;s:7:"/prefix";}}s:9:"path_vars";a:1:{i:0;s:3:"foo";}s:10:"host_regex";s:39:"#^(?P<locale>[^\.]++)\.example\.net$#si";s:11:"host_tokens";a:2:{i:0;a:2:{i:0;s:4:"text";i:1;s:12:".example.net";}i:1;a:4:{i:0;s:8:"variable";i:1;s:0:"";i:2;s:7:"[^\.]++";i:3;s:6:"locale";}}s:9:"host_vars";a:1:{i:0;s:6:"locale";}}}}}';
251251
$unserialized = unserialize($serialized);
252252

253253
$route = new Route('/prefix/{foo}', array('foo' => 'default'), array('foo' => '\d+'));

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.