From 8750cf89f076de48ff538b1b2b975ec0902075ae Mon Sep 17 00:00:00 2001 From: twoldanski <66474451+twoldanski@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:46:57 +0200 Subject: [PATCH] [TASK] Improve handling of frontend urls (#772) Allow more cases, with different domains & with nested paths Resolves: #766 --- Classes/Utility/UrlUtility.php | 16 +++++++++---- Tests/Unit/Utility/UrlUtilityTest.php | 34 ++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Classes/Utility/UrlUtility.php b/Classes/Utility/UrlUtility.php index ccaf2d32..c8b7ad50 100644 --- a/Classes/Utility/UrlUtility.php +++ b/Classes/Utility/UrlUtility.php @@ -12,6 +12,7 @@ namespace FriendsOfTYPO3\Headless\Utility; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\UriInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; use Symfony\Component\ExpressionLanguage\SyntaxError; @@ -29,6 +30,8 @@ use function ltrim; use function rtrim; use function str_contains; +use function strlen; +use function substr; class UrlUtility implements LoggerAwareInterface, HeadlessFrontendUrlInterface { @@ -83,8 +86,6 @@ public function getFrontendUrlWithSite($url, SiteInterface $site, string $return } try { - $base = $site->getBase()->getHost(); - $port = $site->getBase()->getPort(); $frontendBaseUrl = $this->resolveWithVariants( $this->conf[$returnField] ?? '', $this->variants, @@ -101,14 +102,14 @@ public function getFrontendUrlWithSite($url, SiteInterface $site, string $return $frontPort = $frontendBase->getPort(); $targetUri = new Uri($this->sanitizeBaseUrl($url)); - if (str_contains($url, $base)) { + if (str_contains($url, $site->getBase()->getHost())) { $targetUri = $targetUri->withHost($frontBase); if ($frontExtraPath) { - $targetUri = $targetUri->withPath($frontExtraPath . ($targetUri->getPath() !== '' ? '/' . ltrim($targetUri->getPath(), '/') : '')); + $targetUri = $targetUri->withPath($this->handleFrontendAndBackendPaths($frontExtraPath, $targetUri, $site->getBase()->getPath())); } } - if ($port === $frontPort) { + if ($site->getBase()->getPort() === $frontPort) { return (string)$targetUri; } @@ -286,4 +287,9 @@ private function extractConfigurationFromRequest(ServerRequestInterface $request return $object; } + + private function handleFrontendAndBackendPaths(string $frontendPath, UriInterface $targetUri, string $baseBackendPath = ''): string + { + return rtrim($frontendPath, '/') . ($targetUri->getPath() !== '' ? '/' . ltrim(substr($targetUri->getPath(), strlen($baseBackendPath)), '/') : ''); + } } diff --git a/Tests/Unit/Utility/UrlUtilityTest.php b/Tests/Unit/Utility/UrlUtilityTest.php index 73f176e3..8c8d185b 100644 --- a/Tests/Unit/Utility/UrlUtilityTest.php +++ b/Tests/Unit/Utility/UrlUtilityTest.php @@ -29,13 +29,12 @@ class UrlUtilityTest extends UnitTestCase { use ProphecyTrait; - public function testFrontendUrls(): void { $headlessMode = $this->createHeadlessMode(); $site = $this->prophesize(Site::class); - $site->getBase()->shouldBeCalled(2)->willReturn(new Uri('https://test-backend-api.tld')); + $site->getBase()->shouldBeCalled(2)->willReturn(new Uri('https://test-backend-api.tld/')); $site->getConfiguration()->shouldBeCalled(3)->willReturn([ 'base' => 'https://www.typo3.org', 'languages' => [], @@ -102,7 +101,7 @@ public function testFrontendUrls(): void $siteFinder = $this->prophesize(SiteFinder::class); - $site->getBase()->shouldBeCalled(2)->willReturn(new Uri('https://test-backend3-api.tld')); + $site->getBase()->shouldBeCalled(2)->willReturn(new Uri('https://test-backend3-api.tld/')); $urlUtility = new UrlUtility(null, $resolver->reveal(), $siteFinder->reveal(), null, $headlessMode); $urlUtility = $urlUtility->withSite($site->reveal()); @@ -115,6 +114,35 @@ public function testFrontendUrls(): void self::assertSame('#fragment-123', $urlUtility->getFrontendUrlWithSite('#fragment-123', $site->reveal())); } + public function testFrontendUrlsWithDifferentPaths(): void + { + $headlessMode = $this->createHeadlessMode(); + + $site = $this->prophesize(Site::class); + $site->getBase()->shouldBeCalled(1)->willReturn(new Uri('https://test-backend-api.tld/dev-path/')); + $site->getConfiguration()->shouldBeCalled(3)->willReturn([ + 'base' => 'https://www.typo3.org', + 'languages' => [], + 'baseVariants' => [ + [ + 'base' => 'https://test-backend-api.tld/dev-path/', + 'condition' => 'applicationContext == "Development"', + 'frontendBase' => 'https://test-frontend.tld/frontend', + ], + ], + ]); + + $resolver = $this->prophesize(Resolver::class); + $resolver->evaluate(Argument::containingString('Development'))->willReturn(true); + + $siteFinder = $this->prophesize(SiteFinder::class); + + $urlUtility = new UrlUtility(null, $resolver->reveal(), $siteFinder->reveal(), null, $headlessMode); + $urlUtility = $urlUtility->withSite($site->reveal()); + + self::assertSame('https://test-frontend.tld/frontend/content-page', $urlUtility->getFrontendUrlWithSite('https://test-backend-api.tld/dev-path/content-page', $site->reveal())); + } + public function testFrontendUrlsWithBaseProductionAndLocalOverride(): void { $site = $this->prophesize(Site::class);