Merge branch 'daniel-sc-552-handle-encoded-slashes-in-url-param'

pull/556/head
Austin Collier 11 months ago
commit ebe0613589

@ -97,7 +97,7 @@ class Route
/** /**
* Checks if a URL matches the route pattern. Also parses named parameters in the URL. * Checks if a URL matches the route pattern. Also parses named parameters in the URL.
* *
* @param string $url Requested URL * @param string $url Requested URL (original format, not URL decoded)
* @param bool $case_sensitive Case sensitive matching * @param bool $case_sensitive Case sensitive matching
* *
* @return bool Match status * @return bool Match status
@ -127,11 +127,18 @@ class Route
} }
} }
$this->splat = strval(substr($url, $i + 1)); $this->splat = urldecode(strval(substr($url, $i + 1)));
} }
// Build the regex for matching // Build the regex for matching
$regex = str_replace([')', '/*'], [')?', '(/?|/.*?)'], $this->pattern); $pattern_utf_chars_encoded = preg_replace_callback(
'#(\\p{L}+)#u',
static function ($matches) {
return urlencode($matches[0]);
},
$this->pattern
);
$regex = str_replace([')', '/*'], [')?', '(/?|/.*?)'], $pattern_utf_chars_encoded);
$regex = preg_replace_callback( $regex = preg_replace_callback(
'#@([\w]+)(:([^/\(\)]*))?#', '#@([\w]+)(:([^/\(\)]*))?#',

@ -215,9 +215,8 @@ class Router
*/ */
public function route(Request $request) public function route(Request $request)
{ {
$url_decoded = urldecode($request->url);
while ($route = $this->current()) { while ($route = $this->current()) {
if ($route->matchMethod($request->method) && $route->matchUrl($url_decoded, $this->case_sensitive)) { if ($route->matchMethod($request->method) && $route->matchUrl($request->url, $this->case_sensitive)) {
$this->executedRoute = $route; $this->executedRoute = $route;
return $route; return $route;
} }

@ -198,6 +198,67 @@ class RouterTest extends TestCase
$this->check('123'); $this->check('123');
} }
public function testUrlParametersWithEncodedSlash()
{
$this->router->map('/redirect/@id', function ($id) {
echo $id;
});
$this->request->url = '/redirect/before%2Fafter';
$this->check('before/after');
}
public function testUrlParametersWithRealSlash()
{
$this->router->map('/redirect/@id', function ($id) {
echo $id;
});
$this->request->url = '/redirect/before/after';
$this->check('404');
}
public function testUrlParametersWithJapanese()
{
$this->router->map('/わたしはひとです', function () {
echo 'はい';
});
$this->request->url = '/わたしはひとです';
$this->check('はい');
}
public function testUrlParametersWithJapaneseAndParam()
{
$this->router->map('/わたしはひとです/@name', function ($name) {
echo $name;
});
$this->request->url = '/'.urlencode('わたしはひとです').'/'.urlencode('ええ');
$this->check('ええ');
}
// Passing URL parameters matched with regular expression for a URL containing Cyrillic letters:
public function testRegExParametersCyrillic()
{
$this->router->map('/категория/@name:[абвгдеёжзийклмнопрстуфхцчшщъыьэюя]+', function ($name) {
echo $name;
});
$this->request->url = '/'.urlencode('категория').'/'.urlencode('цветя');
$this->check('цветя');
}
public function testRegExOnlyCyrillicUrl()
{
$this->router->map('/категория/цветя', function () {
echo 'цветя';
});
$this->request->url = '/категория/цветя';
$this->check('цветя');
}
// Passing URL parameters matched with regular expression // Passing URL parameters matched with regular expression
public function testRegExParameters() public function testRegExParameters()
{ {
@ -384,17 +445,6 @@ class RouterTest extends TestCase
$this->check('404'); $this->check('404');
} }
// Passing URL parameters matched with regular expression for a URL containing Cyrillic letters:
public function testRegExParametersCyrillic()
{
$this->router->map('/категория/@name:[абвгдеёжзийклмнопрстуфхцчшщъыьэюя]+', function ($name) {
echo $name;
});
$this->request->url = urlencode('/категория/цветя');
$this->check('цветя');
}
public function testGetAndClearRoutes() public function testGetAndClearRoutes()
{ {
$this->router->map('/path1', [$this, 'ok']); $this->router->map('/path1', [$this, 'ok']);

@ -78,6 +78,9 @@ class LayoutMiddleware
<li><a href="/redirect">Redirect</a></li> <li><a href="/redirect">Redirect</a></li>
<li><a href="/streamResponse">Stream</a></li> <li><a href="/streamResponse">Stream</a></li>
<li><a href="/overwrite">Overwrite Body</a></li> <li><a href="/overwrite">Overwrite Body</a></li>
<li><a href="/redirect/before%2Fafter">Slash in Param</a></li>
<li><a href="/わたしはひとです">UTF8 URL</a></li>
<li><a href="/わたしはひとです/ええ">UTF8 URL w/ Param</a></li>
</ul> </ul>
HTML; HTML;
echo '<div id="container">'; echo '<div id="container">';

@ -124,6 +124,21 @@ Flight::group('', function () {
Flight::route('/overwrite', function () { Flight::route('/overwrite', function () {
echo '<span id="infotext">Route text:</span> This route status is that it <span style="color:red; font-weight: bold;">failed</span>'; echo '<span id="infotext">Route text:</span> This route status is that it <span style="color:red; font-weight: bold;">failed</span>';
})->addMiddleware([new OverwriteBodyMiddleware()]); })->addMiddleware([new OverwriteBodyMiddleware()]);
// Test 15: UTF8 Chars in url
Flight::route('/わたしはひとです', function () {
echo '<span id="infotext">Route text:</span> This route status is that it <span style="color:green; font-weight: bold;">succeeded はい!!!</span>';
});
// Test 16: UTF8 Chars in url with utf8 params
Flight::route('/わたしはひとです/@name', function ($name) {
echo '<span id="infotext">Route text:</span> This route status is that it <span style="color:'.($name === 'ええ' ? 'green' : 'red').'; font-weight: bold;">'.($name === 'ええ' ? 'succeeded' : 'failed').' URL Param: '.$name.'</span>';
});
// Test 17: Slash in param
Flight::route('/redirect/@id', function ($id) {
echo '<span id="infotext">Route text:</span> This route status is that it <span style="color:'.($id === 'before/after' ? 'green' : 'red').'; font-weight: bold;">'.($id === 'before/after' ? 'succeeded' : 'failed').' URL Param: '.$id.'</span>';
});
}, [ new LayoutMiddleware() ]); }, [ new LayoutMiddleware() ]);
// Test 9: JSON output (should not output any other html) // Test 9: JSON output (should not output any other html)

Loading…
Cancel
Save