Loading core/lib/Drupal/Core/Routing/UrlGenerator.php +9 −6 Original line number Diff line number Diff line Loading @@ -331,14 +331,17 @@ public function generateFromRoute(string $name, array $parameters = [], array $o // them as they are not used for this purpose here otherwise we would // generate a URI that, when followed by a user agent (e.g. browser), does // not match this route. $path = strtr($path, ['/../' => '/%2E%2E/', '/./' => '/%2E/']); if (str_ends_with($path, '/..')) { $path = substr($path, 0, -2) . '%2E%2E'; $segments = explode('/', $path); foreach ($segments as $i => $segment) { if ($segment === '.') { $segments[$i] = '%2E'; } elseif (str_ends_with($path, '/.')) { $path = substr($path, 0, -1) . '%2E'; elseif ($segment === '..') { $segments[$i] = '%2E%2E'; } } $path = implode('/', $segments); } if (!empty($options['prefix'])) { $path = ltrim($path, '/'); Loading core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php +24 −0 Original line number Diff line number Diff line Loading @@ -99,12 +99,16 @@ protected function setUp(): void { $third_route = new Route('/test/two/'); $fourth_route = new Route('/test/four', [], [], [], '', ['https']); $none_route = new Route('', [], [], ['_no_path' => TRUE]); $path_route = new Route('/test-path/{path}/bar', [], ['path' => '.+']); $tail_route = new Route('/test-tail/{path}', [], ['path' => '.+']); $routes->add('test_1', $first_route); $routes->add('test_2', $second_route); $routes->add('test_3', $third_route); $routes->add('test_4', $fourth_route); $routes->add('<none>', $none_route); $routes->add('test_path', $path_route); $routes->add('test_tail', $tail_route); // Create a route provider stub. $provider = $this->getMockBuilder('Drupal\Core\Routing\RouteProvider') Loading Loading @@ -135,6 +139,14 @@ protected function setUp(): void { 'route_name' => '<none>', 'return' => $none_route, ], [ 'route_name' => 'test_path', 'return' => $path_route, ], [ 'route_name' => 'test_tail', 'return' => $tail_route, ], ]; foreach ($return_map_values as $values) { $route_name_return_map[] = [$values['route_name'], $values['return']]; Loading Loading @@ -547,6 +559,18 @@ public function testGenerateWithPathProcessorChangingOptions(): void { $this->assertGenerateFromRoute('test_2', ['Lassie' => 5], $options, '/goodbye/cruel/world?zoo=5#foo', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); } /** * Tests generate with chained relative path segments. */ public function testEncodingOfChainedRelativePathSegments(): void { $this->assertGenerateFromRoute('test_path', ['path' => '../../..'], [], '/test-path/%2E%2E/%2E%2E/%2E%2E/bar', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); $this->assertGenerateFromRoute('test_path', ['path' => '././.'], [], '/test-path/%2E/%2E/%2E/bar', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); $this->assertGenerateFromRoute('test_path', ['path' => '../././..'], [], '/test-path/%2E%2E/%2E/%2E/%2E%2E/bar', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); $this->assertGenerateFromRoute('test_tail', ['path' => '../../..'], [], '/test-tail/%2E%2E/%2E%2E/%2E%2E', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); $this->assertGenerateFromRoute('test_tail', ['path' => '././.'], [], '/test-tail/%2E/%2E/%2E', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); } /** * Asserts \Drupal\Core\Routing\UrlGenerator::generateFromRoute()'s output. * Loading Loading
core/lib/Drupal/Core/Routing/UrlGenerator.php +9 −6 Original line number Diff line number Diff line Loading @@ -331,14 +331,17 @@ public function generateFromRoute(string $name, array $parameters = [], array $o // them as they are not used for this purpose here otherwise we would // generate a URI that, when followed by a user agent (e.g. browser), does // not match this route. $path = strtr($path, ['/../' => '/%2E%2E/', '/./' => '/%2E/']); if (str_ends_with($path, '/..')) { $path = substr($path, 0, -2) . '%2E%2E'; $segments = explode('/', $path); foreach ($segments as $i => $segment) { if ($segment === '.') { $segments[$i] = '%2E'; } elseif (str_ends_with($path, '/.')) { $path = substr($path, 0, -1) . '%2E'; elseif ($segment === '..') { $segments[$i] = '%2E%2E'; } } $path = implode('/', $segments); } if (!empty($options['prefix'])) { $path = ltrim($path, '/'); Loading
core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php +24 −0 Original line number Diff line number Diff line Loading @@ -99,12 +99,16 @@ protected function setUp(): void { $third_route = new Route('/test/two/'); $fourth_route = new Route('/test/four', [], [], [], '', ['https']); $none_route = new Route('', [], [], ['_no_path' => TRUE]); $path_route = new Route('/test-path/{path}/bar', [], ['path' => '.+']); $tail_route = new Route('/test-tail/{path}', [], ['path' => '.+']); $routes->add('test_1', $first_route); $routes->add('test_2', $second_route); $routes->add('test_3', $third_route); $routes->add('test_4', $fourth_route); $routes->add('<none>', $none_route); $routes->add('test_path', $path_route); $routes->add('test_tail', $tail_route); // Create a route provider stub. $provider = $this->getMockBuilder('Drupal\Core\Routing\RouteProvider') Loading Loading @@ -135,6 +139,14 @@ protected function setUp(): void { 'route_name' => '<none>', 'return' => $none_route, ], [ 'route_name' => 'test_path', 'return' => $path_route, ], [ 'route_name' => 'test_tail', 'return' => $tail_route, ], ]; foreach ($return_map_values as $values) { $route_name_return_map[] = [$values['route_name'], $values['return']]; Loading Loading @@ -547,6 +559,18 @@ public function testGenerateWithPathProcessorChangingOptions(): void { $this->assertGenerateFromRoute('test_2', ['Lassie' => 5], $options, '/goodbye/cruel/world?zoo=5#foo', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); } /** * Tests generate with chained relative path segments. */ public function testEncodingOfChainedRelativePathSegments(): void { $this->assertGenerateFromRoute('test_path', ['path' => '../../..'], [], '/test-path/%2E%2E/%2E%2E/%2E%2E/bar', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); $this->assertGenerateFromRoute('test_path', ['path' => '././.'], [], '/test-path/%2E/%2E/%2E/bar', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); $this->assertGenerateFromRoute('test_path', ['path' => '../././..'], [], '/test-path/%2E%2E/%2E/%2E/%2E%2E/bar', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); $this->assertGenerateFromRoute('test_tail', ['path' => '../../..'], [], '/test-tail/%2E%2E/%2E%2E/%2E%2E', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); $this->assertGenerateFromRoute('test_tail', ['path' => '././.'], [], '/test-tail/%2E/%2E/%2E', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)); } /** * Asserts \Drupal\Core\Routing\UrlGenerator::generateFromRoute()'s output. * Loading