Skip to content

Commit 9800738

Browse files
authored
[5.3] Routing: Allow to mark parsed URLs as tainted (#44455)
1 parent 2e99a5b commit 9800738

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

libraries/src/Router/Router.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ class Router
8080
*/
8181
protected $cache = [];
8282

83+
/**
84+
* Flag to mark the last parsed URL as tainted
85+
* If a URL could be read, but has errors, this
86+
* flag can be set to true to mark the URL as erroneous.
87+
*
88+
* @var bool
89+
* @since __DEPLOY_VERSION__
90+
*/
91+
protected $tainted = false;
92+
8393
/**
8494
* Router instances container.
8595
*
@@ -140,6 +150,9 @@ public static function getInstance($client, $options = [])
140150
*/
141151
public function parse(&$uri, $setVars = false)
142152
{
153+
// Reset the tainted flag
154+
$this->tainted = false;
155+
143156
// Do the preprocess stage of the URL parse process
144157
$this->processParseRules($uri, self::PROCESS_BEFORE);
145158

@@ -362,6 +375,34 @@ public function getRules()
362375
return $this->rules;
363376
}
364377

378+
/**
379+
* Set the currently parsed URL as tainted
380+
* If a URL can be parsed, but not all parts were correct,
381+
* (for example an ID was found, but the alias was wrong) the parsing
382+
* can be marked as tainted. When the URL is marked as tainted, the router
383+
* has to have returned correct data to create the right URL afterwards and
384+
* can later do additional processing, like redirecting to the right URL.
385+
* If the URL is demonstrably wrong, it should still throw a 404 exception.
386+
*
387+
* @since __DEPLOY_VERSION__
388+
*/
389+
public function setTainted()
390+
{
391+
$this->tainted = true;
392+
}
393+
394+
/**
395+
* Return if the last parsed URL was tainted.
396+
*
397+
* @return bool
398+
*
399+
* @since __DEPLOY_VERSION__
400+
*/
401+
public function isTainted()
402+
{
403+
return $this->tainted;
404+
}
405+
365406
/**
366407
* Process the parsed router variables based on custom defined rules
367408
*

plugins/system/sef/src/Extension/Sef.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,30 @@ public function onAfterRoute()
100100
return;
101101
}
102102

103+
$router = $this->getSiteRouter();
104+
105+
/**
106+
* The URL was successfully parsed, but is "tainted", e.g. parts of
107+
* it were recoverably wrong. So we take the parsed variables, build
108+
* a new URL and redirect to that.
109+
*/
110+
if ($router->isTainted()) {
111+
$parsedVars = $router->getVars();
112+
113+
if ($app->getLanguageFilter()) {
114+
$parsedVars['lang'] = $parsedVars['language'];
115+
unset($parsedVars['language']);
116+
}
117+
118+
$newRoute = Route::_($parsedVars, false);
119+
$origUri = clone Uri::getInstance();
120+
$route = $origUri->toString(['path', 'query']);
121+
122+
if ($route !== $newRoute) {
123+
$app->redirect($newRoute, 301);
124+
}
125+
}
126+
103127
// Enforce removing index.php with a redirect
104128
if ($app->get('sef_rewrite') && $this->params->get('indexphp')) {
105129
$this->removeIndexphp();

0 commit comments

Comments
 (0)