diff --git a/htaccess.txt b/htaccess.txt
index f9d5b801b3078..551cd5e24be67 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 113410390649a..b89e6dbdf9eb2 100644
--- a/libraries/src/Router/ApiRouter.php
+++ b/libraries/src/Router/ApiRouter.php
@@ -115,18 +115,8 @@ public function parseApiRoute($method = 'GET')
// 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 @@ public function parseApiRoute($method = 'GET')
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 897d509ecdfcf..a3fc862dae809 100644
--- a/web.config.txt
+++ b/web.config.txt
@@ -5,7 +5,7 @@
-
+
@@ -15,7 +15,16 @@
-
+
+
+
+
+
+
+
+
+
+