From 36cde3578211050b0d86c40deda1deec49217c30 Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Fri, 31 May 2019 13:41:40 +1000 Subject: [PATCH] REST: Implement 405 responses Change-Id: I2a4676569a9903d12b7f5f731c5fd47ceafc3c6c --- includes/Rest/Router.php | 49 ++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/includes/Rest/Router.php b/includes/Rest/Router.php index ab544392f9..83cd0f035e 100644 --- a/includes/Rest/Router.php +++ b/includes/Rest/Router.php @@ -181,6 +181,20 @@ class Router { return $this->matchers; } + /** + * Remove the path prefix $this->rootPath. Return the part of the path with the + * prefix removed, or false if the prefix did not match. + * + * @param string $path + * @return false|string + */ + private function getRelativePath( $path ) { + if ( substr_compare( $path, $this->rootPath, 0, strlen( $this->rootPath ) ) !== 0 ) { + return false; + } + return substr( $path, strlen( $this->rootPath ) ); + } + /** * Find the handler for a request and execute it * @@ -188,20 +202,37 @@ class Router { * @return ResponseInterface */ public function execute( RequestInterface $request ) { - $matchers = $this->getMatchers(); - $matcher = $matchers[$request->getMethod()] ?? null; - if ( $matcher === null ) { - return $this->responseFactory->createHttpError( 404 ); - } $path = $request->getUri()->getPath(); - if ( substr_compare( $path, $this->rootPath, 0, strlen( $this->rootPath ) ) !== 0 ) { + $relPath = $this->getRelativePath( $path ); + if ( $relPath === false ) { return $this->responseFactory->createHttpError( 404 ); } - $relPath = substr( $path, strlen( $this->rootPath ) ); - $match = $matcher->match( $relPath ); + + $matchers = $this->getMatchers(); + $matcher = $matchers[$request->getMethod()] ?? null; + $match = $matcher ? $matcher->match( $relPath ) : null; + if ( !$match ) { - return $this->responseFactory->createHttpError( 404 ); + // Check for 405 wrong method + $allowed = []; + foreach ( $matchers as $allowedMethod => $allowedMatcher ) { + if ( $allowedMethod === $request->getMethod() ) { + continue; + } + if ( $allowedMatcher->match( $relPath ) ) { + $allowed[] = $allowedMethod; + } + } + if ( $allowed ) { + $response = $this->responseFactory->createHttpError( 405 ); + $response->setHeader( 'Allow', $allowed ); + return $response; + } else { + // Did not match with any other method, must be 404 + return $this->responseFactory->createHttpError( 404 ); + } } + $request->setAttributes( $match['params'] ); $spec = $match['userData']; $objectFactorySpec = array_intersect_key( $spec, -- 2.20.1