From 4563141cd9326e2a6bb43a695eef6e0a91a7c707 Mon Sep 17 00:00:00 2001 From: "Nicholas K. Dionysopoulos" Date: Sun, 31 May 2020 22:22:31 +0300 Subject: [PATCH] Fix API application routing (#29303) API not routed correctly on semi-SEF URLs with index.php in them such as /api/index.php/v1/content/article The reason is that the ApiRouter code is incorrectly tied to the URL rewriting option in Global Configuration and doesn't really check correctly whether the index.php part is found at the beginning of the URL. --- htaccess.txt | 42 ++++++++++++++++++---------- libraries/src/Router/ApiRouter.php | 44 ++++++++++++++++++++++-------- web.config.txt | 13 +++++++-- 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/htaccess.txt b/htaccess.txt index f9d5b801b30..551cd5e24be 100644 --- a/htaccess.txt +++ b/htaccess.txt @@ -77,20 +77,34 @@ Header always set X-Content-Type-Options "nosniff" # RewriteBase / ## Begin - Joomla! core SEF Section. - # - RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] - # - # If the requested path and file is not /index.php and the request - # has not already been internally rewritten to the index.php script - RewriteCond %{REQUEST_URI} !^/index\.php - # and the requested path and file doesn't directly match a physical file - RewriteCond %{REQUEST_FILENAME} !-f - # and the requested path and file doesn't directly match a physical folder - RewriteCond %{REQUEST_FILENAME} !-d - # internally rewrite the request to the index.php script - RewriteRule .* index.php [L] - # - ## End - Joomla! core SEF Section. + # + # PHP FastCGI fix for HTTP Authorization, required for the API application + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + # -- SEF URLs for the API application + # If the requested path starts with /api, the file is not /api/index.php + # and the request has not already been internally rewritten to the + # api/index.php script + RewriteCond %{REQUEST_URI} ^/api/ + RewriteCond %{REQUEST_URI} !^/api/index\.php + # and the requested path and file doesn't directly match a physical file + RewriteCond %{REQUEST_FILENAME} !-f + # and the requested path and file doesn't directly match a physical folder + RewriteCond %{REQUEST_FILENAME} !-d + # internally rewrite the request to the /api/index.php script + RewriteRule .* api/index.php [L] + # -- SEF URLs for the public frontend application + # If the requested path and file is not /index.php and the request + # has not already been internally rewritten to the index.php script + RewriteCond %{REQUEST_URI} !^/index\.php + # and the requested path and file doesn't directly match a physical file + RewriteCond %{REQUEST_FILENAME} !-f + # and the requested path and file doesn't directly match a physical folder + RewriteCond %{REQUEST_FILENAME} !-d + # internally rewrite the request to the index.php script + RewriteRule .* index.php [L] + # + ## End - Joomla! core SEF Section. + ## These directives are only enabled if the Apache mod_rewrite module is disabled diff --git a/libraries/src/Router/ApiRouter.php b/libraries/src/Router/ApiRouter.php index 11341039064..b89e6dbdf9e 100644 --- a/libraries/src/Router/ApiRouter.php +++ b/libraries/src/Router/ApiRouter.php @@ -115,18 +115,8 @@ class ApiRouter extends Router // Remove the base URI path. $path = substr_replace($path, '', 0, \strlen($baseUri)); - if (!$this->app->get('sef_rewrite')) - { - // Transform the route - if ($path === 'index.php') - { - $path = ''; - } - else - { - $path = str_replace('index.php/', '', $path); - } - } + // Transform the route + $path = $this->removeIndexPhpFromPath($path); $query = Uri::getInstance()->getQuery(true); @@ -159,4 +149,34 @@ class ApiRouter extends Router throw new RouteNotFoundException(sprintf('Unable to handle request for route `%s`.', $path)); } + + /** + * Removes the index.php from the route's path. + * + * @param string $path + * + * @return string + * + * @since 4.0.0 + */ + private function removeIndexPhpFromPath(string $path): string + { + // Normalize the path + $path = ltrim($path, '/'); + + // We can only remove index.php if it's present in the beginning of the route + if (strpos($path, 'index.php') !== 0) + { + return $path; + } + + // Edge case: the route is index.php without a trailing slash. Bad idea but we can still map it to a null route. + if ($path === 'index.php') + { + return ''; + } + + // Remove the "index.php/" part of the route and return the result. + return substr($path, 10); + } } diff --git a/web.config.txt b/web.config.txt index 897d509ecdf..a3fc862dae8 100644 --- a/web.config.txt +++ b/web.config.txt @@ -5,7 +5,7 @@ - + @@ -15,7 +15,16 @@ - + + + + + + + + + +