Description
Symfony version(s) affected: 4.3
Description
The TraceableUrlMatcher
does not treat the trailing slash the same way the UrlMatcher
does.
How to reproduce
On a fresh install of the website skeletton with composer create-project symfony/website-skeleton sf-debug-routes
.
Add in your config/routes.yml the following content:
hardlink_with_host_without_trailing_slash:
path: /search
controller: App\Controller\DefaultController::index
dynamic_link_with_trailing_slash:
path: /{search}/
controller: App\Controller\DefaultController::index
requirements:
search: "search"
According to the documentation, this should be treated as one route (/search) - even if I disagree with that behaviour.
And with a dummy DefaultController:
<?php
# src/Controller/DefaultController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
class DefaultController
{
public function index()
{
return new Response('ok');
}
}
Now check the output of the command "router:match" for the 2 paths "/search/" and "/search":
$ php bin/console router:match "/search"
[OK] Route "hardlink_without_trailing_slash" matches
+--------------+---------------------------------------------------------+
| Property | Value |
+--------------+---------------------------------------------------------+
| Route Name | hardlink_without_trailing_slash |
| Path | /search |
| Path Regex | #^/search$#sDu |
| Host | ANY |
| Host Regex | |
| Scheme | ANY |
| Method | ANY |
| Requirements | NO CUSTOM |
| Class | Symfony\Component\Routing\Route |
| Defaults | _controller: App\Controller\DefaultController::index |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
| | utf8: true |
+--------------+---------------------------------------------------------+
And
$ php bin/console router:match "/search/"
[OK] Route "dynamic_link_with_trailing_slash" matches
+--------------+---------------------------------------------------------+
| Property | Value |
+--------------+---------------------------------------------------------+
| Route Name | dynamic_link_with_trailing_slash |
| Path | /{search}/ |
| Path Regex | #^/(?P<search>search)/$#sDu |
| Host | ANY |
| Host Regex | |
| Scheme | ANY |
| Method | ANY |
| Requirements | search: search |
| Class | Symfony\Component\Routing\Route |
| Defaults | _controller: App\Controller\DefaultController::index |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
| | utf8: true
6E40
|
+--------------+---------------------------------------------------------+
So the TraceableUrlMatcher
is not redirecting the "/search/" to the "/search", as the route hardlink_without_trailing_slash
is defined first.
The web output (with a webserver started with php bin/console server:start
) is the following:
Route without the trailing slash is 200:
$ curl -v -o/dev/null http://127.0.0.1:8000/search
> GET /search HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
(...)
Route with the trailing slash is 301:
$ curl -v -o/dev/null http://127.0.0.1:8000/search/
> GET /search/ HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Location: http://127.0.0.1:8000/search
(...)
I'm also wondering if that bug can be present elsewhere in the codebase, we had a more complex bug in production, but it was not present in dev or staging envs - not as this one.
The static link was defined with a host match and the dynamic link was not (this dynamic link was imported from a bundle and the "search" requirements was a configuration option of this bundle). The output of router:match
in production were similar to the one I posted in this issue and the redirection was not done on any other environments. I wonder if there is an issue with the CompiledUrlMatcher
in this case. In production our version of symfony is 4.2.3, I'll make some new tests to try to reproduce this precise use case on a fresh install.
Possible Solution
- Detect this issue at build and do not allow to define conflicting routes (or add a warning message)
- Add an option to disable the redirection
- ... ?
Thanks for your help.