diff --git a/core/lib/Drupal/Core/File/FileUrlGenerator.php b/core/lib/Drupal/Core/File/FileUrlGenerator.php
index b3fdefea70804eda22d7d590fd2de98b830c6d98..3f32d485a69ca6a083c5f078a74516a06053f306 100644
--- a/core/lib/Drupal/Core/File/FileUrlGenerator.php
+++ b/core/lib/Drupal/Core/File/FileUrlGenerator.php
@@ -211,7 +211,6 @@ public function transformRelative(string $file_url, bool $root_relative = TRUE):
     // instead of a port number.
     $request = $this->requestStack->getCurrentRequest();
     $host = $request->getHost();
-    $scheme = $request->getScheme();
     $port = $request->getPort() ?: 80;
 
     // Files may be accessible on a different port than the web request.
@@ -220,20 +219,15 @@ public function transformRelative(string $file_url, bool $root_relative = TRUE):
       return $file_url;
     }
 
-    if (('http' == $scheme && $port == 80) || ('https' == $scheme && $port == 443)) {
-      $http_host = $host;
-    }
-    else {
-      $http_host = $host . ':' . $port;
-    }
-
     // If this should not be a root-relative path but relative to the drupal
     // base path, add it to the host to be removed from the URL as well.
-    if (!$root_relative) {
-      $http_host .= $request->getBasePath();
-    }
+    $base_path = !$root_relative ? $request->getBasePath() : '';
+
+    $host = preg_quote($host, '@');
+    $port = preg_quote($port, '@');
+    $base_path = preg_quote($base_path, '@');
 
-    return preg_replace('|^https?://' . preg_quote($http_host, '|') . '|', '', $file_url);
+    return preg_replace("@^https?://{$host}(:{$port})?{$base_path}($|/)@", '/', $file_url);
   }
 
 }
diff --git a/core/tests/Drupal/KernelTests/Core/File/UrlTransformRelativeTest.php b/core/tests/Drupal/KernelTests/Core/File/UrlTransformRelativeTest.php
index 57111ee2f442a235dcaf51ecd96ed909cfdcd4fd..4a4d7e5a42b3195bb1fd9ed68e5c99ac1d77fdd4 100644
--- a/core/tests/Drupal/KernelTests/Core/File/UrlTransformRelativeTest.php
+++ b/core/tests/Drupal/KernelTests/Core/File/UrlTransformRelativeTest.php
@@ -19,25 +19,25 @@ class UrlTransformRelativeTest extends KernelTestBase {
    *
    * @dataProvider providerFileUrlTransformRelative
    */
-  public function testFileUrlTransformRelative($host, $port, $https, $url, $expected) {
+  public function testFileUrlTransformRelative($host, $port, $https, $base_path, $root_relative, $url, $expected) {
 
     $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
     $_SERVER['SERVER_ADDR'] = '127.0.0.1';
     $_SERVER['SERVER_PORT'] = $port;
     $_SERVER['SERVER_SOFTWARE'] = NULL;
     $_SERVER['SERVER_NAME'] = $host;
-    $_SERVER['REQUEST_URI'] = '/';
+    $_SERVER['REQUEST_URI'] = "{$base_path}/";
     $_SERVER['REQUEST_METHOD'] = 'GET';
-    $_SERVER['SCRIPT_NAME'] = '/index.php';
-    $_SERVER['SCRIPT_FILENAME'] = '/index.php';
-    $_SERVER['PHP_SELF'] = '/index.php';
+    $_SERVER['SCRIPT_NAME'] = "{$base_path}/index.php";
+    $_SERVER['SCRIPT_FILENAME'] = "{$base_path}/index.php";
+    $_SERVER['PHP_SELF'] = "{$base_path}/index.php";
     $_SERVER['HTTP_USER_AGENT'] = 'Drupal command line';
     $_SERVER['HTTPS'] = $https;
 
     $request = Request::createFromGlobals();
     \Drupal::requestStack()->push($request);
 
-    $this->assertSame($expected, \Drupal::service('file_url_generator')->transformRelative($url));
+    $this->assertSame($expected, \Drupal::service('file_url_generator')->transformRelative($url, $root_relative));
   }
 
   public function providerFileUrlTransformRelative() {
@@ -46,20 +46,116 @@ public function providerFileUrlTransformRelative() {
         'example.com',
         80,
         '',
+        '',
+        TRUE,
         'http://example.com/page',
         '/page',
       ],
+      'http with base path and root relative' => [
+        'example.com',
+        80,
+        '',
+        '/~foo',
+        TRUE,
+        'http://example.com/~foo/page',
+        '/~foo/page',
+      ],
+      'http with base path and not root relative' => [
+        'example.com',
+        80,
+        '',
+        '/~foo',
+        FALSE,
+        'http://example.com/~foo/page',
+        '/page',
+      ],
+      'http with weird base path and root relative' => [
+        'example.com',
+        80,
+        '',
+        '/~foo$.*!',
+        TRUE,
+        'http://example.com/~foo$.*!/page',
+        '/~foo$.*!/page',
+      ],
+      'http with weird base path and not root relative' => [
+        'example.com',
+        80,
+        '',
+        '/~foo$.*!',
+        FALSE,
+        'http://example.com/~foo$.*!/page',
+        '/page',
+      ],
+      'http frontpage' => [
+        'example.com',
+        80,
+        '',
+        '',
+        TRUE,
+        'http://example.com',
+        '/',
+      ],
+      'http frontpage with a slash' => [
+        'example.com',
+        80,
+        '',
+        '',
+        TRUE,
+        'http://example.com/',
+        '/',
+      ],
+      'https on http' => [
+        'example.com',
+        80,
+        '',
+        '',
+        TRUE,
+        'https://example.com/page',
+        '/page',
+      ],
       'https' => [
         'example.com',
         443,
         'on',
+        '',
+        TRUE,
         'https://example.com/page',
         '/page',
       ],
+      'https frontpage' => [
+        'example.com',
+        443,
+        'on',
+        '',
+        TRUE,
+        'https://example.com',
+        '/',
+      ],
+      'https frontpage with a slash' => [
+        'example.com',
+        443,
+        'on',
+        '',
+        TRUE,
+        'https://example.com/',
+        '/',
+      ],
+      'http with path containing special chars' => [
+        'example.com',
+        80,
+        '',
+        '',
+        TRUE,
+        'http://example.com/~page$.*!',
+        '/~page$.*!',
+      ],
       'http 8080' => [
         'example.com',
         8080,
         '',
+        '',
+        TRUE,
         'https://example.com:8080/page',
         '/page',
       ],
@@ -67,6 +163,8 @@ public function providerFileUrlTransformRelative() {
         'example.com',
         8443,
         'on',
+        '',
+        TRUE,
         'https://example.com:8443/page',
         '/page',
       ],
@@ -74,6 +172,8 @@ public function providerFileUrlTransformRelative() {
         'example.com',
         80,
         '',
+        '',
+        TRUE,
         'http://exampleXcom/page',
         'http://exampleXcom/page',
       ],
@@ -81,6 +181,8 @@ public function providerFileUrlTransformRelative() {
         'example.com',
         80,
         '',
+        '',
+        TRUE,
         'http://example.com:9000/page',
         'http://example.com:9000/page',
       ],
@@ -88,9 +190,47 @@ public function providerFileUrlTransformRelative() {
         'example.com',
         443,
         'on',
+        '',
+        TRUE,
         'https://example.com:8443/page',
         'https://example.com:8443/page',
       ],
+      'http files on different port than the web request on non default port' => [
+        'example.com',
+        8080,
+        '',
+        '',
+        TRUE,
+        'http://example.com:9000/page',
+        'http://example.com:9000/page',
+      ],
+      'https files on different port than the web request on non default port' => [
+        'example.com',
+        8443,
+        'on',
+        '',
+        TRUE,
+        'https://example.com:9000/page',
+        'https://example.com:9000/page',
+      ],
+      'http with default port explicit mentioned in URL' => [
+        'example.com',
+        80,
+        '',
+        '',
+        TRUE,
+        'http://example.com:80/page',
+        '/page',
+      ],
+      'https with default port explicit mentioned in URL' => [
+        'example.com',
+        443,
+        'on',
+        '',
+        TRUE,
+        'https://example.com:443/page',
+        '/page',
+      ],
     ];
     return $data;
   }