From 678035c7f57927e98967012427e394f36617a8c9 Mon Sep 17 00:00:00 2001
From: Benjamin Franzke <bfr@qbus.de>
Date: Wed, 14 Dec 2022 22:17:14 +0100
Subject: [PATCH] [BUGFIX] Fix absolute backend URL generation in frontend
 context

$normalizedParams->getRequestDir() returns '/' for frontend
requests and `/typo3/` for backend requests. This results in
problems when the backend UriBuilder relies on getRequestDir()
to provide the `/typo3/` suffix for backend URL generation.

UriBuilder is now changed to base absolute URLs on
getSiteUrl(), which is defined to return equal values
for backend and frontend requests, the typo3 suffix
is added manually.

Note that v12 introduced similar behavior with #99234,
where UriBuilder was adapted to use BackendEntryPointResolver,
which rebases the backend URL calculation on the site path as well.

Also note that the ABSOLUTE_URL mode in backend UriBuilder isn't
actually used by the TYPO3 frontend, but some extensions started
to execute system reports in frontend context, which
exposed this bug with the introduction of #99347.

Releases: 11.5, 10.4
Resolves: #99368
Related: #99347
Related: #99234
Change-Id: Ifaaeb4725c0243d34603dc86b2c89d12d9c06bdd
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/77159
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benjamin Franzke <bfr@qbus.de>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Benjamin Franzke <bfr@qbus.de>
---
 .../backend/Classes/Routing/UriBuilder.php    |  4 +--
 .../Buttons/Action/ShortcutButtonTest.php     |  8 +++++
 .../Fixtures/RecordListCopyToClipboard.html   |  2 +-
 .../RecordListSingleTableCopyToClipboard.html |  2 +-
 ...dentifierWithArgumentsCopyToClipboard.html |  2 +-
 .../Unit/Mvc/Web/Routing/UriBuilderTest.php   | 35 ++++++++++++++++++-
 6 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/typo3/sysext/backend/Classes/Routing/UriBuilder.php b/typo3/sysext/backend/Classes/Routing/UriBuilder.php
index 3bf642451aef..d91dbf2fc89f 100644
--- a/typo3/sysext/backend/Classes/Routing/UriBuilder.php
+++ b/typo3/sysext/backend/Classes/Routing/UriBuilder.php
@@ -177,9 +177,9 @@ class UriBuilder implements SingletonInterface
         } elseif (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
             && $GLOBALS['TYPO3_REQUEST']->getAttribute('normalizedParams') instanceof NormalizedParams
         ) {
-            $uri = $GLOBALS['TYPO3_REQUEST']->getAttribute('normalizedParams')->getRequestDir() . $path;
+            $uri = $GLOBALS['TYPO3_REQUEST']->getAttribute('normalizedParams')->getSiteUrl() . TYPO3_mainDir . $path;
         } else {
-            $uri = GeneralUtility::getIndpEnv('TYPO3_REQUEST_DIR') . $path;
+            $uri = GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir . $path;
         }
         return GeneralUtility::makeInstance(Uri::class, $uri);
     }
diff --git a/typo3/sysext/backend/Tests/Functional/Template/Components/Buttons/Action/ShortcutButtonTest.php b/typo3/sysext/backend/Tests/Functional/Template/Components/Buttons/Action/ShortcutButtonTest.php
index d83a7c15c34d..7e6f8479cd53 100644
--- a/typo3/sysext/backend/Tests/Functional/Template/Components/Buttons/Action/ShortcutButtonTest.php
+++ b/typo3/sysext/backend/Tests/Functional/Template/Components/Buttons/Action/ShortcutButtonTest.php
@@ -19,6 +19,9 @@ namespace TYPO3\CMS\Backend\Tests\Functional\Template\Components\Buttons\Action;
 
 use TYPO3\CMS\Backend\Template\Components\Buttons\Action\ShortcutButton;
 use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
+use TYPO3\CMS\Core\Http\NormalizedParams;
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
 
 class ShortcutButtonTest extends FunctionalTestCase
@@ -31,6 +34,11 @@ class ShortcutButtonTest extends FunctionalTestCase
 
         $this->setUpBackendUserFromFixture(1);
         Bootstrap::initializeLanguageObject();
+        $serverParams = array_replace($_SERVER, ['HTTP_HOST' => 'example.com', 'SCRIPT_NAME' => '/typo3/index.php']);
+        $request = new ServerRequest('http://example.com/typo3/index.php', 'GET', null, $serverParams);
+        $GLOBALS['TYPO3_REQUEST'] = $request
+            ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE)
+            ->withAttribute('normalizedParams', NormalizedParams::createFromServerParams($serverParams));
     }
 
     /**
diff --git a/typo3/sysext/backend/Tests/Functional/Template/Fixtures/RecordListCopyToClipboard.html b/typo3/sysext/backend/Tests/Functional/Template/Fixtures/RecordListCopyToClipboard.html
index af066c300b7d..ff6e72c356df 100644
--- a/typo3/sysext/backend/Tests/Functional/Template/Fixtures/RecordListCopyToClipboard.html
+++ b/typo3/sysext/backend/Tests/Functional/Template/Fixtures/RecordListCopyToClipboard.html
@@ -25,7 +25,7 @@
         </button>
     </li>
     <li>
-        <typo3-copy-to-clipboard text="http://vendor/phpunit/phpunit/module/web/list">
+        <typo3-copy-to-clipboard text="http://example.com/typo3/module/web/list">
             <button type="button" class="dropdown-item btn btn-link">
                 <span class="t3js-icon icon icon-size-small icon-state-default icon-actions-link" data-identifier="actions-link">
 	                <span class="icon-markup">
diff --git a/typo3/sysext/backend/Tests/Functional/Template/Fixtures/RecordListSingleTableCopyToClipboard.html b/typo3/sysext/backend/Tests/Functional/Template/Fixtures/RecordListSingleTableCopyToClipboard.html
index 2fc07908f7f0..eae87f3988d0 100644
--- a/typo3/sysext/backend/Tests/Functional/Template/Fixtures/RecordListSingleTableCopyToClipboard.html
+++ b/typo3/sysext/backend/Tests/Functional/Template/Fixtures/RecordListSingleTableCopyToClipboard.html
@@ -25,7 +25,7 @@
         </button>
     </li>
     <li>
-        <typo3-copy-to-clipboard text="http://vendor/phpunit/phpunit/module/web/list?id=123&amp;table=some_table&amp;GET%5BclipBoard%5D=1">
+        <typo3-copy-to-clipboard text="http://example.com/typo3/module/web/list?id=123&amp;table=some_table&amp;GET%5BclipBoard%5D=1">
             <button type="button" class="dropdown-item btn btn-link">
                 <span class="t3js-icon icon icon-size-small icon-state-default icon-actions-link" data-identifier="actions-link">
 	                <span class="icon-markup">
diff --git a/typo3/sysext/backend/Tests/Functional/Template/Fixtures/SpecialRouteIdentifierWithArgumentsCopyToClipboard.html b/typo3/sysext/backend/Tests/Functional/Template/Fixtures/SpecialRouteIdentifierWithArgumentsCopyToClipboard.html
index 27c6ecd1b809..ff32f3005326 100644
--- a/typo3/sysext/backend/Tests/Functional/Template/Fixtures/SpecialRouteIdentifierWithArgumentsCopyToClipboard.html
+++ b/typo3/sysext/backend/Tests/Functional/Template/Fixtures/SpecialRouteIdentifierWithArgumentsCopyToClipboard.html
@@ -25,7 +25,7 @@
         </button>
     </li>
     <li>
-        <typo3-copy-to-clipboard text="http://vendor/phpunit/phpunit/record/edit?id=123&amp;edit%5Bpages%5D%5B123%5D=edit&amp;edit%5BoverrideVals%5D%5Bpages%5D%5Bsys_language_uid%5D=1">
+        <typo3-copy-to-clipboard text="http://example.com/typo3/record/edit?id=123&amp;edit%5Bpages%5D%5B123%5D=edit&amp;edit%5BoverrideVals%5D%5Bpages%5D%5Bsys_language_uid%5D=1">
             <button type="button" class="dropdown-item btn btn-link">
                 <span class="t3js-icon icon icon-size-small icon-state-default icon-actions-link" data-identifier="actions-link">
 	                <span class="icon-markup">
diff --git a/typo3/sysext/extbase/Tests/Unit/Mvc/Web/Routing/UriBuilderTest.php b/typo3/sysext/extbase/Tests/Unit/Mvc/Web/Routing/UriBuilderTest.php
index 3c9d1a439fb0..fe527fb26a8e 100644
--- a/typo3/sysext/extbase/Tests/Unit/Mvc/Web/Routing/UriBuilderTest.php
+++ b/typo3/sysext/extbase/Tests/Unit/Mvc/Web/Routing/UriBuilderTest.php
@@ -23,6 +23,7 @@ use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Routing\Route;
 use TYPO3\CMS\Backend\Routing\Router;
 use TYPO3\CMS\Backend\Routing\UriBuilder as BackendUriBuilder;
+use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Http\Uri;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -48,6 +49,11 @@ class UriBuilderTest extends UnitTestCase
      */
     protected $resetSingletonInstances = true;
 
+    /**
+     * @var bool Restore Environment after tests
+     */
+    protected $backupEnvironment = true;
+
     /**
      * @var ConfigurationManagerInterface
      */
@@ -368,8 +374,35 @@ class UriBuilderTest extends UnitTestCase
     /**
      * @test
      */
-    public function buildBackendUriCreatesAbsoluteUrisIfSpecified(): void
+    public function buildBackendUriCreatesAbsoluteUrisInFrontendContentIfSpecified(): void
+    {
+        $GLOBALS['TYPO3_REQUEST'] = $this->getRequestWithRouteAttribute();
+        $_SERVER['HTTP_HOST'] = 'baseuri';
+        $_SERVER['SCRIPT_NAME'] = '/index.php';
+        $_SERVER['ORIG_SCRIPT_NAME'] = '/index.php';
+        $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+        $this->uriBuilder->setCreateAbsoluteUri(true);
+        $expectedResult = 'http://baseuri/' . TYPO3_mainDir . 'test/Path?token=dummyToken';
+        $actualResult = $this->uriBuilder->buildBackendUri();
+        self::assertSame($expectedResult, $actualResult);
+    }
+
+    /**
+     * @test
+     */
+    public function buildBackendUriCreatesAbsoluteUrisInBackendContentIfSpecified(): void
     {
+        Environment::initialize(
+            Environment::getContext(),
+            true,
+            false,
+            Environment::getProjectPath(),
+            Environment::getPublicPath(),
+            Environment::getVarPath(),
+            Environment::getConfigPath(),
+            Environment::getBackendPath() . '/index.php',
+            Environment::isWindows() ? 'WINDOWS' : 'UNIX'
+        );
         $GLOBALS['TYPO3_REQUEST'] = $this->getRequestWithRouteAttribute();
         $_SERVER['HTTP_HOST'] = 'baseuri';
         $_SERVER['SCRIPT_NAME'] = '/typo3/index.php';
-- 
GitLab