You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The current behavior works great for internal redirects that follow Sulu's pattern. But for external redirects or internal redirects that are taken over from a legacy system, the current behavior quickly fails.
Possible Solution
The following workaround works for us. We have overwritten most of the RedirectRouteProvider and the WebsiteRedirectController. I am also happy to create a pull request once the target behavior has been agreed.
<?phpdeclare(strict_types=1);
namespaceApp\Vendor\Sulu\Bundle\RedirectBundle\Routing;
useSulu\Bundle\RedirectBundle\Model\RedirectRouteRepositoryInterface;
useSulu\Bundle\RedirectBundle\Routing\RedirectRouteProviderasInner;
useSymfony\Cmf\Component\Routing\RouteProviderInterface;
useSymfony\Component\DependencyInjection\Attribute\AsDecorator;
useSymfony\Component\DependencyInjection\ContainerInterface;
useSymfony\Component\HttpFoundation\Request;
useSymfony\Component\Routing\Route;
useSymfony\Component\Routing\RouteCollection;
#[AsDecorator(decorates: 'sulu_redirect.routing.provider', onInvalid: ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]
readonly classRedirectRouteProviderimplementsRouteProviderInterface
{
publicfunction__construct(
privateInner$inner,
privateRedirectRouteRepositoryInterface$redirectRouteRepository,
) {
}
publicfunctiongetRouteCollectionForRequest(Request$request): RouteCollection
{
// server encodes the url and symfony does not encode it// symfony decodes this data here https://github.com/symfony/symfony/blob/v5.2.3/src/Symfony/Component/Routing/Matcher/UrlMatcher.php#L88$pathInfo = \rawurldecode($request->getPathInfo());
$host = $request->getHost();
// Sulu strips the request extension from query. This causes problems if we explicitly want to forward a file// extension. That's why we first search for the request URL with the request extension and only call the Sulu// logic if we don't find anything here.$redirectRoute = $this->redirectRouteRepository->findEnabledBySource($pathInfo, $host);
if (!$redirectRoute) {
return$this->inner->getRouteCollectionForRequest($request);
}
$route = newRoute(
$pathInfo,
[
'_controller' => 'sulu_redirect.controller.redirect::redirect',
'redirectRoute' => $redirectRoute,
],
);
$routeCollection = newRouteCollection();
$routeCollection->add(\sprintf('sulu_redirect.%s', $redirectRoute->getId()), $route);
return$routeCollection;
}
publicfunctiongetRouteByName($name): Route
{
return$this->inner->getRouteByName($name);
}
publicfunctiongetRoutesByNames($names = null): iterable
{
return$this->inner->getRoutesByNames($names);
}
}
<?phpdeclare(strict_types=1);
namespaceApp\Vendor\Sulu\Bundle\RedirectBundle\Controller;
useSulu\Bundle\RedirectBundle\Controller\WebsiteRedirectControllerasInner;
useSulu\Bundle\RedirectBundle\Model\RedirectRouteInterface;
useSymfony\Component\DependencyInjection\Attribute\AsDecorator;
useSymfony\Component\DependencyInjection\ContainerInterface;
useSymfony\Component\HttpFoundation\RedirectResponse;
useSymfony\Component\HttpFoundation\Request;
useSymfony\Component\HttpKernel\Exception\HttpException;
#[AsDecorator(decorates: 'sulu_redirect.controller.redirect', onInvalid: ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]
readonly classWebsiteRedirectController
{
publicfunction__construct(privateInner$inner)
{
}
publicfunctionredirect(Request$request, RedirectRouteInterface$redirectRoute): RedirectResponse
{
if (410 === $redirectRoute->getStatusCode()) {
thrownewHttpException(410);
}
$sourcePathHasExtension = $this->urlHasFileExtension($redirectRoute->getSource());
$targetHasHost = $this->urlHasHost($redirectRoute->getTarget());
$targetHasFile = $this->urlHasFile($redirectRoute->getTarget());
$targetHasFileExtension = $this->urlHasFileExtension($redirectRoute->getTarget());
// Sulu forces the request extension on the forwarding target. However, this is not our desired behavior if the// forwarding target already has a file extension or the forwarding target has a host (therefore probably external)// or the forwarding target has already a file extension or is not a file but a directory.if (!$sourcePathHasExtension && !$targetHasHost && $targetHasFile && !$targetHasFileExtension) {
return$this->inner->redirect($request, $redirectRoute);
}
$url = [
$redirectRoute->getTarget(),
\str_contains($redirectRoute->getTarget(), '?') ? '&' : '?',
\http_build_query($request->query->all()),
];
$url = \trim(\implode('', $url), '&? ');
returnnewRedirectResponse($url, $redirectRoute->getStatusCode());
}
privatefunctionurlHasHost(string$url): bool
{
$host = \parse_url($url, \PHP_URL_HOST);
return\is_string($host) && !\str_ends_with($host, '/');
}
privatefunctionurlHasFile(string$url): bool
{
$path = \parse_url($url, \PHP_URL_PATH);
return\is_string($path) && !\str_ends_with($path, '/');
}
privatefunctionurlHasFileExtension(string$url): bool
{
$path = \parse_url($url, \PHP_URL_PATH);
return\is_string($path) && \pathinfo($path, \PATHINFO_EXTENSION);
}
}
The text was updated successfully, but these errors were encountered:
FlorianKoerner
changed the title
Strange behavior with request extensions
Strange behavior with request path extensions
Jul 26, 2024
Actual Behavior
The redirects do not work as expected if the source or target has an extension.
The current behavior works great for internal redirects that follow Sulu's pattern. But for external redirects or internal redirects that are taken over from a legacy system, the current behavior quickly fails.
Possible Solution
The following workaround works for us. We have overwritten most of the RedirectRouteProvider and the WebsiteRedirectController. I am also happy to create a pull request once the target behavior has been agreed.
The text was updated successfully, but these errors were encountered: