Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 087a226

Browse files
[Routing] Account for greediness when merging route patterns
1 parent 2ed6503 commit 087a226

File tree

5 files changed

+89
-121
lines changed

5 files changed

+89
-121
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ public function addRoute(string $prefix, $route, string $staticPrefix = null)
103103
if ($item instanceof self && $this->prefixes[$i] === $commonPrefix) {
104104
// the new route is a child of a previous one, let's nest it
105105
$item->addRoute($prefix, $route, $staticPrefix);
106+
} elseif ($commonPrefix === $prefix && $commonStaticPrefix !== $prefix) {
107+
break;
106108
} else {
107109
// the new route and a previous one have a common prefix, let's merge them
108110
$child = new self($commonPrefix);

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

Lines changed: 37 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -88,41 +88,33 @@ public function match($rawPathinfo)
8888
.'|/([^/]++)(*:57)'
8989
.'|head/([^/]++)(*:77)'
9090
.')'
91-
.'|/test/([^/]++)/(?'
92-
.'|(*:103)'
93-
.')'
94-
.'|/([\']+)(*:119)'
91+
.'|/test/([^/]++)/(*:100)'
92+
.'|/([\']+)(*:115)'
93+
.'|/a/b\'b/([^/]++)(*:138)'
9594
.'|/a/(?'
96-
.'|b\'b/([^/]++)(?'
97-
.'|(*:148)'
98-
.'|(*:156)'
99-
.')'
100-
.'|(.*)(*:169)'
101-
.'|b\'b/([^/]++)(?'
102-
.'|(*:192)'
103-
.'|(*:200)'
104-
.')'
105-
.')'
106-
.'|/multi/hello(?:/([^/]++))?(*:236)'
107-
.'|/([^/]++)/b/([^/]++)(?'
108-
.'|(*:267)'
109-
.'|(*:275)'
95+
.'|b\'b/([^/]++)(*:164)'
96+
.'|(.*)(*:176)'
97+
.'|b\'b/([^/]++)(*:196)'
98+
.'|b\'b/([^/]++)(*:216)'
11099
.')'
111-
.'|/aba/([^/]++)(*:297)'
100+
.'|/multi/hello(?:/([^/]++))?(*:251)'
101+
.'|/([^/]++)/b/([^/]++)(*:279)'
102+
.'|/([^/]++)/b/([^/]++)(*:307)'
103+
.'|/aba/([^/]++)(*:328)'
112104
.')|(?i:([^\\.]++)\\.example\\.com)(?'
113105
.'|/route1(?'
114-
.'|3/([^/]++)(*:357)'
115-
.'|4/([^/]++)(*:375)'
106+
.'|3/([^/]++)(*:388)'
107+
.'|4/([^/]++)(*:406)'
116108
.')'
117109
.')|(?i:c\\.example\\.com)(?'
118-
.'|/route15/([^/]++)(*:425)'
110+
.'|/route15/([^/]++)(*:456)'
119111
.')|[^/]*+(?'
120-
.'|/route16/([^/]++)(*:460)'
112+
.'|/route16/([^/]++)(*:491)'
121113
.'|/a/(?'
122-
.'|a\\.\\.\\.(*:481)'
114+
.'|a\\.\\.\\.(*:512)'
123115
.'|b/(?'
124-
.'|([^/]++)(*:502)'
125-
.'|c/([^/]++)(*:520)'
116+
.'|([^/]++)(*:533)'
117+
.'|c/([^/]++)(*:551)'
126118
.')'
127119
.')'
128120
.')'
@@ -132,7 +124,7 @@ public function match($rawPathinfo)
132124
foreach ($regexList as $offset => $regex) {
133125
while (preg_match($regex, $matchedPathinfo, $matches)) {
134126
switch ($m = (int) $matches['MARK']) {
135-
case 103:
127+
case 100:
136128
$matches = array('foo' => $matches[1] ?? null);
137129

138130
// baz4
@@ -159,28 +151,14 @@ public function match($rawPathinfo)
159151
not_bazbaz6:
160152

161153
break;
162-
case 148:
163-
$matches = array('foo' => $matches[1] ?? null);
164-
165-
// foo1
166-
$ret = $this->mergeDefaults(array('_route' => 'foo1') + $matches, array());
167-
if (!isset(($a = array('PUT' => 0))[$requestMethod])) {
168-
$allow += $a;
169-
goto not_foo1;
170-
}
171-
172-
return $ret;
173-
not_foo1:
174-
175-
break;
176-
case 192:
154+
case 196:
177155
$matches = array('foo1' => $matches[1] ?? null);
178156

179157
// foo2
180158
return $this->mergeDefaults(array('_route' => 'foo2') + $matches, array());
181159

182160
break;
183-
case 267:
161+
case 279:
184162
$matches = array('_locale' => $matches[1] ?? null, 'foo' => $matches[2] ?? null);
185163

186164
// foo3
@@ -192,20 +170,21 @@ public function match($rawPathinfo)
192170
34 => array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null),
193171
57 => array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null),
194172
77 => array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null),
195-
119 => array(array('_route' => 'quoter'), array('quoter'), null, null),
196-
156 => array(array('_route' => 'bar1'), array('bar'), null, null),
197-
169 => array(array('_route' => 'overridden'), array('var'), null, null),
198-
200 => array(array('_route' => 'bar2'), array('bar1'), null, null),
199-
236 => array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null),
200-
275 => array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null),
201-
297 => array(array('_route' => 'foo4'), array('foo'), null, null),
202-
357 => array(array('_route' => 'route13'), array('var1', 'name'), null, null),
203-
375 => array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null),
204-
425 => array(array('_route' => 'route15'), array('name'), null, null),
205-
460 => array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null),
206-
481 => array(array('_route' => 'a'), array(), null, null),
207-
502 => array(array('_route' => 'b'), array('var'), null, null),
208-
520 => array(array('_route' => 'c'), array('var'), null, null),
173+
115 => array(array('_route' => 'quoter'), array('quoter'), null, null),
174+
138 => array(array('_route' => 'foo1'), array('foo'), array('PUT' => 0), null),
175+
164 => array(array('_route' => 'bar1'), array('bar'), null, null),
176+
176 => array(array('_route' => 'overridden'), array('var'), null, null),
177+
216 => array(array('_route' => 'bar2'), array('bar1'), null, null),
178+
251 => array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null),
179+
307 => array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null),
180+
328 => array(array('_route' => 'foo4'), array('foo'), null, null),
181+
388 => array(array('_route' => 'route13'), array('var1', 'name'), null, null),
182+
406 => array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null),
183+
456 => array(array('_route' => 'route15'), array('name'), null, null),
184+
491 => array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null),
185+
512 => array(array('_route' => 'a'), array(), null, null),
186+
533 => array(array('_route' => 'b'), array('var'), null, null),
187+
551 => array(array('_route' => 'c'), array('var'), null, null),
209188
);
210189

211190
list($ret, $vars, $requiredMethods, $requiredSchemes) = $routes[$m];
@@ -231,7 +210,7 @@ public function match($rawPathinfo)
231210
return $ret;
232211
}
233212

234-
if (520 === $m) {
213+
if (551 === $m) {
235214
break;
236215
}
237216
$regex = substr_replace($regex, 'F', $m - $offset, 1 + strlen($m));

src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher13.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,15 @@ public function match($rawPathinfo)
3131
$regexList = array(
3232
0 => '{^(?'
3333
.'|(?i:([^\\.]++)\\.exampple\\.com)(?'
34-
.'|/abc([^/]++)(?'
35-
.'|(*:54)'
36-
.')'
34+
.'|/abc([^/]++)(*:51)'
3735
.')'
3836
.')$}sD',
3937
);
4038

4139
foreach ($regexList as $offset => $regex) {
4240
while (preg_match($regex, $matchedPathinfo, $matches)) {
4341
switch ($m = (int) $matches['MARK']) {
44-
case 54:
42+
case 51:
4543
$matches = array('foo' => $matches[1] ?? null, 'foo' => $matches[2] ?? null);
4644

4745
// r1
@@ -53,7 +51,7 @@ public function match($rawPathinfo)
5351
break;
5452
}
5553

56-
if (54 === $m) {
54+
if (51 === $m) {
5755
break;
5856
}
5957
$regex = substr_replace($regex, 'F', $m - $offset, 1 + strlen($m));

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

Lines changed: 37 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -125,41 +125,33 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
125125
.'|/([^/]++)(*:57)'
126126
.'|head/([^/]++)(*:77)'
127127
.')'
128-
.'|/test/([^/]++)/(?'
129-
.'|(*:103)'
130-
.')'
131-
.'|/([\']+)(*:119)'
128+
.'|/test/([^/]++)/(*:100)'
129+
.'|/([\']+)(*:115)'
130+
.'|/a/b\'b/([^/]++)(*:138)'
132131
.'|/a/(?'
133-
.'|b\'b/([^/]++)(?'
134-
.'|(*:148)'
135-
.'|(*:156)'
136-
.')'
137-
.'|(.*)(*:169)'
138-
.'|b\'b/([^/]++)(?'
139-
.'|(*:192)'
140-
.'|(*:200)'
141-
.')'
142-
.')'
143-
.'|/multi/hello(?:/([^/]++))?(*:236)'
144-
.'|/([^/]++)/b/([^/]++)(?'
145-
.'|(*:267)'
146-
.'|(*:275)'
132+
.'|b\'b/([^/]++)(*:164)'
133+
.'|(.*)(*:176)'
134+
.'|b\'b/([^/]++)(*:196)'
135+
.'|b\'b/([^/]++)(*:216)'
147136
.')'
148-
.'|/aba/([^/]++)(*:297)'
137+
.'|/multi/hello(?:/([^/]++))?(*:251)'
138+
.'|/([^/]++)/b/([^/]++)(*:279)'
139+
.'|/([^/]++)/b/([^/]++)(*:307)'
140+
.'|/aba/([^/]++)(*:328)'
149141
.')|(?i:([^\\.]++)\\.example\\.com)(?'
150142
.'|/route1(?'
151-
.'|3/([^/]++)(*:357)'
152-
.'|4/([^/]++)(*:375)'
143+
.'|3/([^/]++)(*:388)'
144+
.'|4/([^/]++)(*:406)'
153145
.')'
154146
.')|(?i:c\\.example\\.com)(?'
155-
.'|/route15/([^/]++)(*:425)'
147+
.'|/route15/([^/]++)(*:456)'
156148
.')|[^/]*+(?'
157-
.'|/route16/([^/]++)(*:460)'
149+
.'|/route16/([^/]++)(*:491)'
158150
.'|/a/(?'
159-
.'|a\\.\\.\\.(*:481)'
151+
.'|a\\.\\.\\.(*:512)'
160152
.'|b/(?'
161-
.'|([^/]++)(*:502)'
162-
.'|c/([^/]++)(*:520)'
153+
.'|([^/]++)(*:533)'
154+
.'|c/([^/]++)(*:551)'
163155
.')'
164156
.')'
165157
.')'
@@ -169,7 +161,7 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
169161
foreach ($regexList as $offset => $regex) {
170162
while (preg_match($regex, $matchedPathinfo, $matches)) {
171163
switch ($m = (int) $matches['MARK']) {
172-
case 103:
164+
case 100:
173165
$matches = array('foo' => $matches[1] ?? null);
174166

175167
// baz4
@@ -196,28 +188,14 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
196188
not_bazbaz6:
197189

198190
break;
199-
case 148:
200-
$matches = array('foo' => $matches[1] ?? null);
201-
202-
// foo1
203-
$ret = $this->mergeDefaults(array('_route' => 'foo1') + $matches, array());
204-
if (!isset(($a = array('PUT' => 0))[$requestMethod])) {
205-
$allow += $a;
206-
goto not_foo1;
207-
}
208-
209-
return $ret;
210-
not_foo1:
211-
212-
break;
213-
case 192:
191+
case 196:
214192
$matches = array('foo1' => $matches[1] ?? null);
215193

216194
// foo2
217195
return $this->mergeDefaults(array('_route' => 'foo2') + $matches, array());
218196

219197
break;
220-
case 267:
198+
case 279:
221199
$matches = array('_locale' => $matches[1] ?? null, 'foo' => $matches[2] ?? null);
222200

223201
// foo3
@@ -229,20 +207,21 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
229207
34 => array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null),
230208
57 => array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null),
231209
77 => array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null),
232-
119 => array(array('_route' => 'quoter'), array('quoter'), null, null),
233-
156 => array(array('_route' => 'bar1'), array('bar'), null, null),
234-
169 => array(array('_route' => 'overridden'), array('var'), null, null),
235-
200 => array(array('_route' => 'bar2'), array('bar1'), null, null),
236-
236 => array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null),
237-
275 => array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null),
238-
297 => array(array('_route' => 'foo4'), array('foo'), null, null),
239-
357 => array(array('_route' => 'route13'), array('var1', 'name'), null, null),
240-
375 => array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null),
241-
425 => array(array('_route' => 'route15'), array('name'), null, null),
242-
460 => array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null),
243-
481 => array(array('_route' => 'a'), array(), null, null),
244-
502 => array(array('_route' => 'b'), array('var'), null, null),
245-
520 => array(array('_route' => 'c'), array('var'), null, null),
210+
115 => array(array('_route' => 'quoter'), array('quoter'), null, null),
211+
138 => array(array('_route' => 'foo1'), array('foo'), array('PUT' => 0), null),
212+
164 => array(array('_route' => 'bar1'), array('bar'), null, null),
213+
176 => array(array('_route' => 'overridden'), array('var'), null, null),
214+
216 => array(array('_route' => 'bar2'), array('bar1'), null, null),
215+
251 => array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null),
216+
307 => array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null),
217+
328 => array(array('_route' => 'foo4'), array('foo'), null, null),
218+
388 => array(array('_route' => 'route13'), array('var1', 'name'), null, null),
219+
406 => array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null),
220+
456 => array(array('_route' => 'route15'), array('name'), null, null),
221+
491 => array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null),
222+
512 => array(array('_route' => 'a'), array(), null, null),
223+
533 => array(array('_route' => 'b'), array('var'), null, null),
224+
551 => array(array('_route' => 'c'), array('var'), null, null),
246225
);
247226

248227
list($ret, $vars, $requiredMethods, $requiredSchemes) = $routes[$m];
@@ -268,7 +247,7 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
268247
return $ret;
269248
}
270249

271-
if (520 === $m) {
250+
if (551 === $m) {
272251
break;
273252
}
274253
$regex = substr_replace($regex, 'F', $m - $offset, 1 + strlen($m));

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,16 @@ public function testRequirementWithCapturingGroup()
611611
$this->assertEquals(array('_route' => 'a', 'a' => 'a', 'b' => 'b'), $matcher->match('/a/b'));
612612
}
613613

614+
public function testDotAllWithCatchAll()
615+
{
616+
$coll = new RouteCollection();
617+
$coll->add('a', new Route('/{id}.html', array(), array('id' => '.+')));
618+
$coll->add('b', new Route('/{all}', array(), array('all' => '.+')));
619+
620+
$matcher = $this->getUrlMatcher($coll);
621+
$this->assertEquals(array('_route' => 'a', 'id' => 'foo/bar'), $matcher->match('/foo/bar.html'));
622+
}
623+
614624
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
615625
{
616626
return new UrlMatcher($routes, $context ?: new RequestContext());

0 commit comments

Comments
 (0)