Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.3] Routing: Allow to mark parsed URLs as tainted #44455

Merged
merged 3 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions libraries/src/Router/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ class Router
*/
protected $cache = [];

/**
* Flag to mark the last parsed URL as tainted
* If a URL could be read, but has errors, this
* flag can be set to true to mark the URL as erroneous.
*
* @var bool
* @since __DEPLOY_VERSION__
*/
protected $tainted = false;

/**
* Router instances container.
*
Expand Down Expand Up @@ -140,6 +150,9 @@ public static function getInstance($client, $options = [])
*/
public function parse(&$uri, $setVars = false)
{
// Reset the tainted flag
$this->tainted = false;

// Do the preprocess stage of the URL parse process
$this->processParseRules($uri, self::PROCESS_BEFORE);

Expand Down Expand Up @@ -362,6 +375,34 @@ public function getRules()
return $this->rules;
}

/**
* Set the currently parsed URL as tainted
* If a URL can be parsed, but not all parts were correct,
* (for example an ID was found, but the alias was wrong) the parsing
* can be marked as tainted. When the URL is marked as tainted, the router
* has to have returned correct data to create the right URL afterwards and
* can later do additional processing, like redirecting to the right URL.
* If the URL is demonstrably wrong, it should still throw a 404 exception.
*
* @since __DEPLOY_VERSION__
*/
public function setTainted()
{
$this->tainted = true;
}

/**
* Return if the last parsed URL was tainted.
*
* @return bool
*
* @since __DEPLOY_VERSION__
*/
public function isTainted()
{
return $this->tainted;
}

/**
* Process the parsed router variables based on custom defined rules
*
Expand Down
24 changes: 24 additions & 0 deletions plugins/system/sef/src/Extension/Sef.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,30 @@ public function onAfterRoute()
return;
}

$router = $this->getSiteRouter();

/**
* The URL was successfully parsed, but is "tainted", e.g. parts of
* it were recoverably wrong. So we take the parsed variables, build
* a new URL and redirect to that.
*/
if ($router->isTainted()) {
SniperSister marked this conversation as resolved.
Show resolved Hide resolved
$parsedVars = $router->getVars();

if ($app->getLanguageFilter()) {
$parsedVars['lang'] = $parsedVars['language'];
unset($parsedVars['language']);
}

$newRoute = Route::_($parsedVars, false);
$origUri = clone Uri::getInstance();
$route = $origUri->toString(['path', 'query']);

if ($route !== $newRoute) {
$app->redirect($newRoute, 301);
}
}

// Enforce removing index.php with a redirect
if ($app->get('sef_rewrite') && $this->params->get('indexphp')) {
$this->removeIndexphp();
Expand Down