From 2951072bef99bfeec97b0077515d208ff587516a Mon Sep 17 00:00:00 2001 From: Greg Hecquet Date: Mon, 22 Aug 2016 17:56:36 +0200 Subject: [PATCH] Adding WOPI Route Handler --- core/src/core/src/pydio/Core/Http/Base.php | 21 +-- .../src/pydio/Core/Http/Message/Message.php | 53 ++++++ .../Core/Http/Rest/RestApiMiddleware.php | 3 +- .../{RestServer.php => RestApiServer.php} | 3 +- .../Core/Http/Rest/RestAuthMiddleware.php | 6 +- .../src/pydio/Core/Http/TopLevelRouter.php | 11 +- .../Core/Http/Wopi/RestWopiAuthMiddleware.php | 107 ++++++++++++ .../Core/Http/Wopi/RestWopiMiddleware.php | 48 +++++ .../pydio/Core/Http/Wopi/RestWopiServer.php | 46 +++++ .../pydio/Core/Http/Wopi/WopiMiddleware.php | 105 +++++++++++ .../src/pydio/Core/Http/Wopi/WopiRouter.php | 165 ++++++++++++++++++ 11 files changed, 546 insertions(+), 22 deletions(-) create mode 100644 core/src/core/src/pydio/Core/Http/Message/Message.php rename core/src/core/src/pydio/Core/Http/Rest/{RestServer.php => RestApiServer.php} (95%) create mode 100644 core/src/core/src/pydio/Core/Http/Wopi/RestWopiAuthMiddleware.php create mode 100644 core/src/core/src/pydio/Core/Http/Wopi/RestWopiMiddleware.php create mode 100644 core/src/core/src/pydio/Core/Http/Wopi/RestWopiServer.php create mode 100644 core/src/core/src/pydio/Core/Http/Wopi/WopiMiddleware.php create mode 100644 core/src/core/src/pydio/Core/Http/Wopi/WopiRouter.php diff --git a/core/src/core/src/pydio/Core/Http/Base.php b/core/src/core/src/pydio/Core/Http/Base.php index 5877f303d4..f2e258238d 100644 --- a/core/src/core/src/pydio/Core/Http/Base.php +++ b/core/src/core/src/pydio/Core/Http/Base.php @@ -34,25 +34,20 @@ class Base */ public static function handleRoute($base, $route){ - if($route === "/api") { - - $server = new Rest\RestServer($base.$route); - - }else if($route === "/user") { - + if ($route === "/api") { + $server = new Rest\RestApiServer($base.$route); + } else if ($route == "/wopi") { + $server = new Wopi\RestWopiServer($base.$route); + } else if ($route === "/user") { $_GET["get_action"] = "user_access_point"; $server = new Server($base); - - }else if($route == "/favicon"){ - + } else if ($route == "/favicon"){ $_GET["get_action"] = "serve_favicon"; $server = new Server($base); - - }else{ - + } else { $server = new Server($base); - } + $server->registerCatchAll(); ConfService::init(); diff --git a/core/src/core/src/pydio/Core/Http/Message/Message.php b/core/src/core/src/pydio/Core/Http/Message/Message.php new file mode 100644 index 0000000000..bec630cc34 --- /dev/null +++ b/core/src/core/src/pydio/Core/Http/Message/Message.php @@ -0,0 +1,53 @@ + + * This file is part of Pydio. + * + * Pydio is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pydio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pydio. If not, see . + * + * The latest code can be found at . + */ +namespace Pydio\Core\Http\Message; + +use Pydio\Core\Controller\XMLWriter; +use Pydio\Core\Http\Response\JSONSerializableResponseChunk; +use Pydio\Core\Http\Response\XMLSerializableResponseChunk; + +defined('AJXP_EXEC') or die('Access not allowed'); + +class Message implements XMLSerializableResponseChunk, JSONSerializableResponseChunk +{ + + private $message; + + public function __construct($message) + { + $this->message = $message; + } + + public function toXML() + { + return XMLWriter::sendMessage($this->message, $this->message); + } + + public function jsonSerializableData() + { + return $this->message; + } + + public function jsonSerializableKey() + { + return 'message'; + } +} \ No newline at end of file diff --git a/core/src/core/src/pydio/Core/Http/Rest/RestApiMiddleware.php b/core/src/core/src/pydio/Core/Http/Rest/RestApiMiddleware.php index aa89e79771..1a04bb3d5b 100644 --- a/core/src/core/src/pydio/Core/Http/Rest/RestApiMiddleware.php +++ b/core/src/core/src/pydio/Core/Http/Rest/RestApiMiddleware.php @@ -23,11 +23,12 @@ use \Psr\Http\Message\ServerRequestInterface; use \Psr\Http\Message\ResponseInterface; use Pydio\Core\Exception\PydioException; +use Pydio\Core\Http\Middleware\SapiMiddleware; defined('AJXP_EXEC') or die('Access not allowed'); -class RestApiMiddleware extends \Pydio\Core\Http\Middleware\SapiMiddleware +class RestApiMiddleware extends SapiMiddleware { protected $base; diff --git a/core/src/core/src/pydio/Core/Http/Rest/RestServer.php b/core/src/core/src/pydio/Core/Http/Rest/RestApiServer.php similarity index 95% rename from core/src/core/src/pydio/Core/Http/Rest/RestServer.php rename to core/src/core/src/pydio/Core/Http/Rest/RestApiServer.php index 6cd0821ff2..5082da8535 100644 --- a/core/src/core/src/pydio/Core/Http/Rest/RestServer.php +++ b/core/src/core/src/pydio/Core/Http/Rest/RestApiServer.php @@ -21,12 +21,13 @@ namespace Pydio\Core\Http\Rest; +use Pydio\Core\Http\Server; use Pydio\Core\Services\ConfService; defined('AJXP_EXEC') or die('Access not allowed'); -class RestServer extends \Pydio\Core\Http\Server +class RestApiServer extends Server { public function __construct($base) diff --git a/core/src/core/src/pydio/Core/Http/Rest/RestAuthMiddleware.php b/core/src/core/src/pydio/Core/Http/Rest/RestAuthMiddleware.php index 51fa7cffec..de6df971a5 100644 --- a/core/src/core/src/pydio/Core/Http/Rest/RestAuthMiddleware.php +++ b/core/src/core/src/pydio/Core/Http/Rest/RestAuthMiddleware.php @@ -20,12 +20,14 @@ */ namespace Pydio\Core\Http\Rest; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Pydio\Auth\Frontend\Core\FrontendsLoader; use Pydio\Core\Exception\NoActiveWorkspaceException; use Pydio\Core\Exception\PydioException; use Pydio\Core\Exception\WorkspaceForbiddenException; +use Pydio\Core\Http\Server; use Pydio\Core\Model\Context; use Pydio\Core\Model\ContextInterface; use Pydio\Core\PluginFramework\PluginsService; @@ -53,7 +55,7 @@ class RestAuthMiddleware * @param callable|null $next * @throws PydioException */ - public static function handleRequest(\Psr\Http\Message\ServerRequestInterface &$requestInterface, \Psr\Http\Message\ResponseInterface &$responseInterface, callable $next = null){ + public static function handleRequest(ServerRequestInterface &$requestInterface, ResponseInterface &$responseInterface, callable $next = null){ $driverImpl = ConfService::getAuthDriverImpl(); PluginsService::getInstance(Context::emptyContext())->setPluginUniqueActiveForType("auth", $driverImpl->getName(), $driverImpl); @@ -97,7 +99,7 @@ public static function handleRequest(\Psr\Http\Message\ServerRequestInterface &$ RolesService::bootSequence(); } - return RestServer::callNextMiddleWare($requestInterface, $responseInterface, $next); + return Server::callNextMiddleWare($requestInterface, $responseInterface, $next); } diff --git a/core/src/core/src/pydio/Core/Http/TopLevelRouter.php b/core/src/core/src/pydio/Core/Http/TopLevelRouter.php index 553adb1bb4..8155c332da 100644 --- a/core/src/core/src/pydio/Core/Http/TopLevelRouter.php +++ b/core/src/core/src/pydio/Core/Http/TopLevelRouter.php @@ -20,7 +20,8 @@ */ namespace Pydio\Core\Http; -use Psr\Http\Message\ResponseInterface; +use FastRoute\Dispatcher; +use FastRoute\RouteCollector; use Psr\Http\Message\ServerRequestInterface; use Pydio\Core\Exception\PydioException; @@ -61,7 +62,7 @@ public function __construct($cacheOptions = []){ * @param string $base Base URI (empty string if "/"). * @param \FastRoute\RouteCollector $r */ - public function configureRoutes($base, \FastRoute\RouteCollector &$r){ + public function configureRoutes($base, RouteCollector &$r){ $allMethods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'CONNECT', 'PATCH', 'PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK']; $file = AJXP_DATA_PATH."/".AJXP_PLUGINS_FOLDER."/boot.conf/routes.json"; @@ -102,7 +103,7 @@ public function route(){ $request = ServerRequestFactory::fromGlobals(); $this->base = rtrim(dirname($request->getServerParams()["SCRIPT_NAME"]), "/"); - $dispatcher = \FastRoute\cachedDispatcher(function(\FastRoute\RouteCollector $r) { + $dispatcher = \FastRoute\cachedDispatcher(function(RouteCollector $r) { $this->configureRoutes($this->base, $r); }, $this->cacheOptions); @@ -111,14 +112,14 @@ public function route(){ $routeInfo = $dispatcher->dispatch($httpMethod, $uri); switch ($routeInfo[0]) { - case \FastRoute\Dispatcher::FOUND: + case Dispatcher::FOUND: $data = $routeInfo[1]; if(isSet($data["path"])){ require_once (AJXP_INSTALL_PATH."/".$data["path"]); } call_user_func(array($data["class"], $data["method"]), $this->base, $data["short"], $routeInfo[2]); break; - case \FastRoute\Dispatcher::NOT_FOUND: + case Dispatcher::NOT_FOUND: default: throw new PydioException("Oups, could not find any valid route for ".$uri.", method was was ".$httpMethod); break; diff --git a/core/src/core/src/pydio/Core/Http/Wopi/RestWopiAuthMiddleware.php b/core/src/core/src/pydio/Core/Http/Wopi/RestWopiAuthMiddleware.php new file mode 100644 index 0000000000..2973d6c913 --- /dev/null +++ b/core/src/core/src/pydio/Core/Http/Wopi/RestWopiAuthMiddleware.php @@ -0,0 +1,107 @@ + + * This file is part of Pydio. + * + * Pydio is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pydio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pydio. If not, see . + * + * The latest code can be found at . + */ +namespace Pydio\Core\Http\Wopi; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Pydio\Auth\Frontend\Core\FrontendsLoader; +use Pydio\Core\Exception\NoActiveWorkspaceException; +use Pydio\Core\Exception\PydioException; +use Pydio\Core\Exception\WorkspaceForbiddenException; + +use Pydio\Core\Http\Server; +use Pydio\Core\Model\Context; +use Pydio\Core\Model\ContextInterface; +use Pydio\Core\PluginFramework\PluginsService; +use Pydio\Core\Services\ConfService; + +use Pydio\Core\Services\RolesService; +use Pydio\Core\Services\UsersService; +use Pydio\Core\Utils\ApplicationState; +use Pydio\Log\Core\Logger; + +defined('AJXP_EXEC') or die('Access not allowed'); + + +/** + * Authentication middleware used in Rest context + * @package Pydio\Core\Http\Rest + */ +class RestWopiAuthMiddleware +{ + + /** + * @param ServerRequestInterface $requestInterface + * @param \Psr\Http\Message\ResponseInterface $responseInterface + * @return \Psr\Http\Message\ResponseInterface + * @param callable|null $next + * @throws PydioException + */ + public static function handleRequest(ServerRequestInterface &$requestInterface, ResponseInterface &$responseInterface, callable $next = null){ + + $driverImpl = ConfService::getAuthDriverImpl(); + PluginsService::getInstance(Context::emptyContext())->setPluginUniqueActiveForType("auth", $driverImpl->getName(), $driverImpl); + + $response = FrontendsLoader::frontendsAsAuthMiddlewares($requestInterface, $responseInterface); + if($response != null){ + return $response; + } + /** @var ContextInterface $ctx */ + $ctx = $requestInterface->getAttribute("ctx"); + + if(!$ctx->hasUser()){ + $responseInterface = $responseInterface->withStatus(401); + $responseInterface->getBody()->write('You are not authorized to access this API.'); + return $responseInterface; + } + + $repoID = $requestInterface->getAttribute("repository_id"); + if($repoID == 'pydio'){ + $userRepositories = UsersService::getRepositoriesForUser($ctx->getUser()); + if(empty($userRepositories)){ + throw new NoActiveWorkspaceException(); + } + $repo = array_shift($userRepositories); + }else{ + try{ + $repo = UsersService::getRepositoryWithPermission($ctx->getUser(), $repoID); + }catch (WorkspaceForbiddenException $w){ + $responseInterface = $responseInterface->withStatus(401); + $responseInterface->getBody()->write('You are not authorized to access this API.'); + return $responseInterface; + } + } + + $ctx->setRepositoryObject($repo); + $requestInterface = $requestInterface->withAttribute("ctx", $ctx); + + Logger::updateContext($ctx); + + if(UsersService::usersEnabled() && ApplicationState::detectApplicationFirstRun()){ + RolesService::bootSequence(); + } + + return Server::callNextMiddleWare($requestInterface, $responseInterface, $next); + + } + + +} \ No newline at end of file diff --git a/core/src/core/src/pydio/Core/Http/Wopi/RestWopiMiddleware.php b/core/src/core/src/pydio/Core/Http/Wopi/RestWopiMiddleware.php new file mode 100644 index 0000000000..1f74e8f785 --- /dev/null +++ b/core/src/core/src/pydio/Core/Http/Wopi/RestWopiMiddleware.php @@ -0,0 +1,48 @@ + + * This file is part of Pydio. + * + * Pydio is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pydio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pydio. If not, see . + * + * The latest code can be found at . + */ +namespace Pydio\Core\Http\Wopi; + +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; +use Pydio\Core\Exception\PydioException; +use Pydio\Core\Http\Wopi\WopiMiddleware; + +defined('AJXP_EXEC') or die('Access not allowed'); + + +class RestWopiMiddleware extends WopiMiddleware +{ + protected $base; + + public function __construct($base) + { + $this->base = $base; + } + + protected function parseRequestRouteAndParams(ServerRequestInterface &$request, ResponseInterface &$response){ + + $router = new WopiRouter($this->base); + if(!$router->route($request, $response)){ + throw new PydioException("Could not find any endpoint for this URI"); + } + } + +} \ No newline at end of file diff --git a/core/src/core/src/pydio/Core/Http/Wopi/RestWopiServer.php b/core/src/core/src/pydio/Core/Http/Wopi/RestWopiServer.php new file mode 100644 index 0000000000..d42581a6bf --- /dev/null +++ b/core/src/core/src/pydio/Core/Http/Wopi/RestWopiServer.php @@ -0,0 +1,46 @@ + + * This file is part of Pydio. + * + * Pydio is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pydio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pydio. If not, see . + * + * The latest code can be found at . + */ + +namespace Pydio\Core\Http\Wopi; + +use Pydio\Core\Http\Server; +use Pydio\Core\Services\ConfService; + +defined('AJXP_EXEC') or die('Access not allowed'); + + +class RestWopiServer extends Server +{ + + public function __construct($base) + { + parent::__construct($base); + ConfService::currentContextIsRestAPI($base); + } + + protected function stackMiddleWares() + { + $this->middleWares->push(array("Pydio\\Core\\Controller\\Controller", "registryActionMiddleware")); + $this->middleWares->push(array("Pydio\\Core\\Http\\Rest\\RestAuthMiddleware", "handleRequest")); + $this->topMiddleware = new RestWopiMiddleware($this->base); + $this->middleWares->push(array($this->topMiddleware, "handleRequest")); + } +} \ No newline at end of file diff --git a/core/src/core/src/pydio/Core/Http/Wopi/WopiMiddleware.php b/core/src/core/src/pydio/Core/Http/Wopi/WopiMiddleware.php new file mode 100644 index 0000000000..7568667979 --- /dev/null +++ b/core/src/core/src/pydio/Core/Http/Wopi/WopiMiddleware.php @@ -0,0 +1,105 @@ + + * This file is part of Pydio. + * + * Pydio is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pydio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pydio. If not, see . + * + * The latest code can be found at . + */ +namespace Pydio\Core\Http\Wopi; + +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; +use Pydio\Access\Core\Model\AJXP_Node; +use Pydio\Access\Core\Model\NodesList; + +use Pydio\Core\Http\Message\Message; +use Pydio\Core\Http\Middleware\SapiMiddleware; +use Pydio\Core\Http\Response\SerializableResponseStream; +use Zend\Diactoros\Response\EmptyResponse; +use Zend\Diactoros\Response\SapiEmitter; + +defined('AJXP_EXEC') or die('Access not allowed'); + +/** + * Class WopiMiddleware + * Main Middleware for Wopi requests + * @package Pydio\Core\Http\Middleware + */ +class WopiMiddleware extends SapiMiddleware +{ + + /** + * Output the response to the browser, if no headers were already sent. + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @return void + */ + public function emitResponse(ServerRequestInterface $request, ResponseInterface $response) { + + if($response !== false && $response->getBody() && $response->getBody() instanceof SerializableResponseStream){ + /** + * @var SerializableResponseStream $body; + */ + + $body = &$response->getBody(); + + /** @var NodesList $originalData */ + $originalData = $body->getChunks()[0]; + + /** @var AJXP_Node $node */ + $node = $originalData->getChildren()[0]; + + // We modify the result to have the correct format required by the api + $x = new SerializableResponseStream(); + $meta = $node->getNodeInfoMeta(); + $userId = $node->getUser()->getId(); + $data = [ + "BaseFileName" => $node->getLabel(), + "OwnerId" => $userId, + "Size" => $meta["bytesize"], + "UserId" => $userId, + "Version" => "" . $meta["ajxp_modiftime"] + ]; + + $x->addChunk(new Message($data)); + $response = $response->withBody($x); + $body = &$response->getBody(); + + $params = $request->getParsedBody(); + $forceXML = false; + + if(isSet($params["format"]) && $params["format"] == "xml"){ + $forceXML = true; + } + + if(($request->hasHeader("Accept") && $request->getHeader("Accept")[0] == "text/xml" ) || $forceXML){ + $body->setSerializer(SerializableResponseStream::SERIALIZER_TYPE_XML); + $response = $response->withHeader("Content-type", "text/xml; charset=UTF-8"); + } else { + $body->setSerializer(SerializableResponseStream::SERIALIZER_TYPE_JSON); + $response = $response->withHeader("Content-type", "application/json; charset=UTF-8"); + + } + + } + + if($response !== false && ($response->getBody()->getSize() || $response instanceof EmptyResponse) || $response->getStatusCode() != 200) { + $emitter = new SapiEmitter(); + $emitter->emit($response); + } + } + +} \ No newline at end of file diff --git a/core/src/core/src/pydio/Core/Http/Wopi/WopiRouter.php b/core/src/core/src/pydio/Core/Http/Wopi/WopiRouter.php new file mode 100644 index 0000000000..28efc3828d --- /dev/null +++ b/core/src/core/src/pydio/Core/Http/Wopi/WopiRouter.php @@ -0,0 +1,165 @@ + + * This file is part of Pydio. + * + * Pydio is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pydio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Pydio. If not, see . + * + * The latest code can be found at . + */ +namespace Pydio\Core\Http\Wopi; + +use FastRoute\Dispatcher; +use FastRoute\RouteCollector; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; + +defined('AJXP_EXEC') or die('Access not allowed'); + +class WopiRouter +{ + /** + * @var array + */ + private $base; + + /** + * @var array + * "cacheOptions" => ["cacheFile" => "path", "cacheDisabled" => true], + */ + private $cacheOptions; + + /** + * ApiRouter constructor. + * @param string $base + * @param array $cacheOptions + */ + public function __construct($base, $cacheOptions = []){ + $this->base = $base; + $this->cacheOptions = array_merge([ + "cacheDisabled" => AJXP_SKIP_CACHE, + "cacheFile" => AJXP_DATA_PATH."/cache/plugins_wopiroutes.php" + ], $cacheOptions); + } + + + /** + * @param RouteCollector $r + */ + public function configureRoutes(RouteCollector &$r){ + + $configObject = json_decode(file_get_contents(AJXP_INSTALL_PATH . "/" . AJXP_DOCS_FOLDER . "/wopi.json"), true); + + foreach ($configObject["paths"] as $path => $methods){ + foreach($methods as $method => $apiData){ + if(preg_match('/\{path\}/', $path)){ + if(isset($apiData["parameters"]["0"]['$ref']) && preg_match('/Optional$/', $apiData["parameters"]["0"]['$ref'])){ + $path = str_replace("{path}", "{path:.*}", $path); + }else{ + $path = str_replace("{path}", "{path:.+}", $path); + } + } + $path = str_replace("{roleId}", "{roleId:.+}", $path); + $r->addRoute(strtoupper($method), $this->base . $path , $apiData); + } + } + } + + /** + * Get Path component of the URI, without query parameters + * @param ServerRequestInterface $request + * @return string + */ + public function getURIForRequest(ServerRequestInterface $request){ + + $uri = $request->getServerParams()['REQUEST_URI']; + // Strip query string (?foo=bar) and decode URI + if (false !== $pos = strpos($uri, '?')) { + $uri = substr($uri, 0, $pos); + } + return rawurldecode($uri); + } + + /** + * Find a route in api definitions + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @return bool + */ + public function route(ServerRequestInterface &$request, ResponseInterface &$response){ + + $dispatcher = \FastRoute\cachedDispatcher(function(RouteCollector $r) { + + $this->configureRoutes($r); + + }, $this->cacheOptions); + + $httpMethod = $request->getServerParams()['REQUEST_METHOD']; + $uri = $this->getURIForRequest($request); + $routeInfo = $dispatcher->dispatch($httpMethod, $uri); + + switch ($routeInfo[0]) { + case Dispatcher::NOT_FOUND: + //$response = $response->withStatus(404); + break; + case Dispatcher::METHOD_NOT_ALLOWED: + //$allowedMethods = $routeInfo[1]; + //$response = $response->withStatus(405); + break; + case Dispatcher::FOUND: + $apiData = $routeInfo[1]; + $vars = $routeInfo[2]; + + $apiUri = preg_replace('/^'.preg_quote($this->base, '/').'/', '', $uri); + + $request = $request->withAttribute("api_uri", $apiUri); + $repoId = $this->findRepositoryInParameters($request, $vars); + + $request = $request + ->withAttribute("action", $apiData["x-pydio-action"]) + ->withAttribute("repository_id", $repoId) + ->withAttribute("rest_base", $this->base) + ->withAttribute("api", "v2") // We want the same behaviour as for the v2 api + ->withParsedBody(array_merge($request->getParsedBody(), $vars)); + + return true; + default: + break; + } + + return false; + } + + /** + * Analyze URI and parameters to guess the current workspace + * + * @param ServerRequestInterface $request + * @param array $pathVars + * @return mixed|string + */ + protected function findRepositoryInParameters(ServerRequestInterface $request, array $pathVars){ + $params = array_merge($request->getParsedBody(), $pathVars); + if (preg_match('/^\/admin\//', $request->getAttribute("api_uri"))) { + return "ajxp_conf"; + }else if(isSet($params["workspaceId"])){ + return $params["workspaceId"]; + }else if(isSet($params["path"]) && strpos($params["path"], "/") !== false){ + return array_shift(explode("/", ltrim($params["path"], "/"))); + } + // If no repo ID was found, return default repo id "pydio". + return "pydio"; + } + + +} \ No newline at end of file