From e1ce4ed4ce3394718578f7f20b86387eb41d0315 Mon Sep 17 00:00:00 2001
From: Susanne Moog <susanne.moog@typo3.org>
Date: Thu, 25 Oct 2018 22:18:45 +0200
Subject: [PATCH] [BUGFIX] Allow relative URLs in locationHeaderUrl

Resolves: #81720
Releases: master, 8.7
Change-Id: I099c905bf335a13fafa920c2849fd88971dc0e44
Reviewed-on: https://review.typo3.org/58705
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Joerg Kummer <typo3@enobe.de>
Tested-by: Joerg Kummer <typo3@enobe.de>
Reviewed-by: Ursula Klinger <klinger@punkt.de>
Tested-by: Ursula Klinger <klinger@punkt.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
---
 .../core/Classes/Utility/GeneralUtility.php   | 21 ++++---
 .../Tests/Unit/Utility/GeneralUtilityTest.php | 63 ++++++++++++++++++-
 2 files changed, 76 insertions(+), 8 deletions(-)

diff --git a/typo3/sysext/core/Classes/Utility/GeneralUtility.php b/typo3/sysext/core/Classes/Utility/GeneralUtility.php
index 00e62e81de89..f68d5b99f553 100644
--- a/typo3/sysext/core/Classes/Utility/GeneralUtility.php
+++ b/typo3/sysext/core/Classes/Utility/GeneralUtility.php
@@ -2444,14 +2444,21 @@ class GeneralUtility
      */
     public static function locationHeaderUrl($path)
     {
-        $uI = parse_url($path);
+        if (strpos($path, '//') === 0) {
+            return $path;
+        }
+
         // relative to HOST
-        if ($path[0] === '/') {
-            $path = self::getIndpEnv('TYPO3_REQUEST_HOST') . $path;
-        } elseif (!$uI['scheme']) {
+        if (strpos($path, '/') === 0) {
+            return self::getIndpEnv('TYPO3_REQUEST_HOST') . $path;
+        }
+
+        $urlComponents = parse_url($path);
+        if (!($urlComponents['scheme'] ?? false)) {
             // No scheme either
-            $path = self::getIndpEnv('TYPO3_REQUEST_DIR') . $path;
+            return self::getIndpEnv('TYPO3_REQUEST_DIR') . $path;
         }
+
         return $path;
     }
 
@@ -2715,7 +2722,7 @@ class GeneralUtility
                         ? (($_SERVER['ORIG_PATH_INFO'] ?? '') ?: ($_SERVER['PATH_INFO'] ?? ''))
                         : (($_SERVER['ORIG_SCRIPT_NAME'] ?? '') ?: ($_SERVER['SCRIPT_NAME'] ?? ''));
                 // Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
-                if (self::cmpIP($_SERVER['REMOTE_ADDR'] ?? '', $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
+                if (self::cmpIP($_SERVER['REMOTE_ADDR'] ?? '', $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'] ?? '')) {
                     if (self::getIndpEnv('TYPO3_SSL') && $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL']) {
                         $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL'] . $retVal;
                     } elseif ($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix']) {
@@ -2898,7 +2905,7 @@ class GeneralUtility
                 $retVal = substr(self::getIndpEnv('TYPO3_REQUEST_URL'), strlen(self::getIndpEnv('TYPO3_SITE_URL')));
                 break;
             case 'TYPO3_SSL':
-                $proxySSL = trim($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxySSL']);
+                $proxySSL = trim($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxySSL'] ?? null);
                 if ($proxySSL === '*') {
                     $proxySSL = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'];
                 }
diff --git a/typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php b/typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php
index d91ba7779e8c..7361bda40e51 100644
--- a/typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php
+++ b/typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php
@@ -73,7 +73,10 @@ class GeneralUtilityTest extends UnitTestCase
      */
     protected function tearDown()
     {
-        ExtensionManagementUtilityAccessibleProxy::setPackageManager($this->backupPackageManager);
+        GeneralUtility::flushInternalRuntimeCaches();
+        if ($this->backupPackageManager) {
+            ExtensionManagementUtilityAccessibleProxy::setPackageManager($this->backupPackageManager);
+        }
         parent::tearDown();
     }
 
@@ -4640,4 +4643,62 @@ class GeneralUtilityTest extends UnitTestCase
 
         $requestFactory->request(Argument::any(), Argument::any(), ['headers' => $expectedHeaders])->shouldHaveBeenCalled();
     }
+
+    public function locationHeaderUrlDataProvider(): array
+    {
+        return [
+            'simple relative path' => [
+                'foo',
+                'foo.bar.test',
+                'http://foo.bar.test/foo'
+            ],
+            'path beginning with slash' => [
+                '/foo',
+                'foo.bar.test',
+                'http://foo.bar.test/foo'
+            ],
+            'path with full domain and https scheme' => [
+                'https://example.com/foo',
+                'foo.bar.test',
+                'https://example.com/foo'
+            ],
+            'path with full domain and http scheme' => [
+                'http://example.com/foo',
+                'foo.bar.test',
+                'http://example.com/foo'
+            ],
+            'path with full domain and relative scheme' => [
+                '//example.com/foo',
+                'foo.bar.test',
+                '//example.com/foo'
+            ],
+        ];
+    }
+
+    /**
+     * @test
+     * @param string $path
+     * @param string $host
+     * @param string $expected
+     * @dataProvider locationHeaderUrlDataProvider
+     * @throws \TYPO3\CMS\Core\Exception
+     */
+    public function locationHeaderUrl($path, $host, $expected): void
+    {
+        Environment::initialize(
+            Environment::getContext(),
+            true,
+            false,
+            Environment::getProjectPath(),
+            Environment::getPublicPath(),
+            Environment::getVarPath(),
+            Environment::getConfigPath(),
+            Environment::getCurrentScript(),
+            Environment::isWindows() ? 'WINDOWS' : 'UNIX'
+        );
+        $_SERVER['HTTP_HOST'] = $host;
+        $_SERVER['SCRIPT_NAME'] = '/index.php';
+        $result = GeneralUtility::locationHeaderUrl($path);
+        self::assertSame($expected, $result);
+    }
 }
-- 
GitLab