From 628e335c0cb3d05dcd88ac7f9b5be2a3d18c94a1 Mon Sep 17 00:00:00 2001
From: Oliver Hader <oliver@typo3.org>
Date: Mon, 21 Nov 2022 10:56:13 +0100
Subject: [PATCH] [BUGFIX] Apply previous site identifier as fallback for URL
 resolving

Prior to #93240 URL routes were reverse sorted using the corresponding
site identifier (which did not contain any URL information). For the
scenario of matching undefined URLs (e.g. base URL is "/website/", but
request was like "https://example.org/"), the first item of a reverse
sorted list was used.

Resolves: #99149
Related: #93240
Releases: main, 11.5
Change-Id: Ia242591cebfba7d8221494a5d214f6dca75a00fc
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/78794
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: core-ci <typo3@b13.com>
---
 typo3/sysext/core/Classes/Routing/BestUrlMatcher.php     | 7 ++++++-
 typo3/sysext/core/Classes/Routing/MatchedRoute.php       | 7 +++++++
 typo3/sysext/core/Tests/Unit/Routing/SiteMatcherTest.php | 4 ++--
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/typo3/sysext/core/Classes/Routing/BestUrlMatcher.php b/typo3/sysext/core/Classes/Routing/BestUrlMatcher.php
index 415d59a627c5..fdbc376c36dd 100644
--- a/typo3/sysext/core/Classes/Routing/BestUrlMatcher.php
+++ b/typo3/sysext/core/Classes/Routing/BestUrlMatcher.php
@@ -144,6 +144,11 @@ class BestUrlMatcher extends UrlMatcher
         }
         // index `1` refers to the array index containing the corresponding `tail` match
         // @todo not sure, whether `tail` can be defined generic, it's hard coded in `SiteMatcher`
-        return $b->getPathMatchScore(1) <=> $a->getPathMatchScore(1);
+        if ($b->getPathMatchScore(1) !== $a->getPathMatchScore(1)) {
+            return $b->getPathMatchScore(1) <=> $a->getPathMatchScore(1);
+        }
+        // fallback for behavior prior to issue #93240, using reverse sorted site identifier
+        // (side note: site identifier did not contain any URL relevant information)
+        return $b->getSiteIdentifier() <=> $a->getSiteIdentifier();
     }
 }
diff --git a/typo3/sysext/core/Classes/Routing/MatchedRoute.php b/typo3/sysext/core/Classes/Routing/MatchedRoute.php
index 19da6ac54636..8a7209b286bf 100644
--- a/typo3/sysext/core/Classes/Routing/MatchedRoute.php
+++ b/typo3/sysext/core/Classes/Routing/MatchedRoute.php
@@ -18,6 +18,7 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Core\Routing;
 
 use Symfony\Component\Routing\Route as SymfonyRoute;
+use TYPO3\CMS\Core\Site\Entity\SiteInterface;
 
 /**
  * @internal
@@ -84,4 +85,10 @@ class MatchedRoute
         // example: complete: `/french/other`, tail: `/other` -> `strlen` of `/french`
         return strpos($completeMatch, $tailMatch);
     }
+
+    public function getSiteIdentifier(): string
+    {
+        $site = $this->route->getDefault('site');
+        return $site instanceof SiteInterface ? $site->getIdentifier() : '';
+    }
 }
diff --git a/typo3/sysext/core/Tests/Unit/Routing/SiteMatcherTest.php b/typo3/sysext/core/Tests/Unit/Routing/SiteMatcherTest.php
index c30dd8bd605b..3f79b3e4e85a 100644
--- a/typo3/sysext/core/Tests/Unit/Routing/SiteMatcherTest.php
+++ b/typo3/sysext/core/Tests/Unit/Routing/SiteMatcherTest.php
@@ -109,9 +109,9 @@ class SiteMatcherTest extends UnitTestCase
         $request = new ServerRequest('http://www.example.com/');
         /** @var SiteRouteResult $result */
         $result = $subject->matchRequest($request);
-        // Nothing found, only the empty site, but finds a random site ("main") according to the algorithm
+        // Nothing found, only the empty site, but finds the last site ("second") according to the algorithm
         self::assertNull($result->getLanguage());
-        self::assertEquals('main', $result->getSite()->getIdentifier());
+        self::assertEquals('second', $result->getSite()->getIdentifier());
     }
 
     /**
-- 
GitLab