diff --git a/lib/private/AppFramework/Routing/RouteConfig.php b/lib/private/AppFramework/Routing/RouteConfig.php index 654cad8b0238..6f5a7aad36e8 100644 --- a/lib/private/AppFramework/Routing/RouteConfig.php +++ b/lib/private/AppFramework/Routing/RouteConfig.php @@ -221,7 +221,7 @@ private function processResources($routes) $this->router->create($routeName, $url)->method($verb)->action( new RouteActionHandler($this->container, $controllerName, $actionName) - ); + )->requirements(['id' => '.+']); // allow / in {id} parameter } } } diff --git a/tests/lib/Route/RouterTest.php b/tests/lib/Route/RouterTest.php index 4243b876f7ab..a3e4e8076328 100644 --- a/tests/lib/Route/RouterTest.php +++ b/tests/lib/Route/RouterTest.php @@ -1,5 +1,6 @@ * @author Thomas Müller * * @copyright Copyright (c) 2018, ownCloud GmbH @@ -24,17 +25,41 @@ use OC\Route\Router; use OCP\ILogger; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; + +class LoadableRouter extends Router { + /** + * @param bool $loaded + */ + public function setLoaded($loaded) { + $this->loaded = $loaded; + } +} class RouterTest extends \Test\TestCase { + /** @var ILogger */ + private $l; + + /** + * RouterTest constructor. + * + * @param string $name + * @param array $data + * @param string $dataName + */ + public function __construct($name = null, array $data = [], $dataName = '') { + parent::__construct($name, $data, $dataName); + $this->l = $this->createMock(ILogger::class); + } + /** * @dataProvider providesWebRoot * @param $expectedBase * @param $webRoot */ public function testWebRootSetup($expectedBase, $webRoot) { - $l = $this->createMock(ILogger::class); - $router = new Router($l, $webRoot); + $router = new Router($this->l, $webRoot); $this->assertEquals($expectedBase, $router->getGenerator()->getContext()->getBaseUrl()); } @@ -47,4 +72,51 @@ public function providesWebRoot() { ['/oc/index.php', '/oc/'], ]; } + + /** + * @dataProvider urlParamSlashProvider + */ + public function testMatchURLParamContainingSlash($routeUrl, $slashesAllowed, $matchUrl, $expectedCalled) { + $router = new LoadableRouter($this->l, ''); + + $called = false; + + $router->useCollection('root'); + $route = $router->create('test', $routeUrl) + ->action(function () use (&$called) { + $called = true; + }); + if ($slashesAllowed) { + $route->requirements(['id' => '.+']); + } + + // don't load any apps + $router->setLoaded(true); + + try { + $router->match($matchUrl); + } catch (ResourceNotFoundException $e) { + $called = false; + } + + self::assertEquals($expectedCalled, $called); + } + + public function urlParamSlashProvider() { + return [ + // slashed disallowed + ['/resource/{id}', false, '/resource/id%2Fwith%2Fslashes', false], + ['/resource/{id}/sub', false, '/resource/id%2Fwith%2Fslashes/sub', false], + ['/resource/{id}/sub', false, '/resource/id%2Fwith%2Fslashes/subx', false], + ['/resource/{id}', false, '/resource/id/with/slashes', false], + ['/resource/{id}/sub', false, '/resource/id/with/slashes/sub', false], + + // slashed allowed + ['/resource/{id}', true, '/resource/id%2Fwith%2Fslashes', true], + ['/resource/{id}/sub', true, '/resource/id%2Fwith%2Fslashes/sub', true], + ['/resource/{id}/sub', true, '/resource/id%2Fwith%2Fslashes/subx', false], + ['/resource/{id}', true, '/resource/id/with/slashes', true], + ['/resource/{id}/sub', true, '/resource/id/with/slashes/sub', true], + ]; + } }