From 4dce03c0d3747788bd716fcedb7564bfedce7598 Mon Sep 17 00:00:00 2001
From: Dan Brown <ssddanbrown@googlemail.com>
Date: Sat, 2 Apr 2022 17:14:37 +0100
Subject: [PATCH 1/3] Updated custom request overrides to better match original
 intent

This updates the custom Request handler to provide only the scheme and
host on the `getSchemeAndHttpHost` call, instead of providing the whole
APP_URL value, while adding an override to the 'getBaseUrl' to use the
APP_URL content instead of the guessed/detected Symfony value.

Untested apart from simple local setup.

Related to #2765
---
 app/Http/Request.php | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/app/Http/Request.php b/app/Http/Request.php
index c5b38f1c1..687bae9a6 100644
--- a/app/Http/Request.php
+++ b/app/Http/Request.php
@@ -8,20 +8,35 @@ class Request extends LaravelRequest
 {
     /**
      * Override the default request methods to get the scheme and host
-     * to set the custom APP_URL, if set.
+     * to directly use the custom APP_URL, if set.
      *
-     * @return \Illuminate\Config\Repository|mixed|string
+     * @return string
      */
     public function getSchemeAndHttpHost()
     {
-        $base = config('app.url', null);
+        $appUrl = config('app.url', null);
 
-        if ($base) {
-            $base = trim($base, '/');
-        } else {
-            $base = $this->getScheme() . '://' . $this->getHttpHost();
+        if ($appUrl) {
+            return implode('/', array_slice(explode('/', $appUrl), 0, 3));
         }
 
-        return $base;
+        return parent::getSchemeAndHttpHost();
+    }
+
+    /**
+     * Override the default request methods to get the base URL
+     * to directly use the custom APP_URL, if set.
+     *
+     * @return string
+     */
+    public function getBaseUrl()
+    {
+        $appUrl = config('app.url', null);
+
+        if ($appUrl) {
+            return rtrim(implode('/', array_slice(explode('/', $appUrl), 3)), '/');
+        }
+
+        return parent::getBaseUrl();
     }
 }

From 25654b232214583f06aef0a4edfc28815b66b735 Mon Sep 17 00:00:00 2001
From: Dan Brown <ssddanbrown@googlemail.com>
Date: Wed, 13 Apr 2022 12:46:19 +0100
Subject: [PATCH 2/3] Fixed base URL starting slash usage

---
 app/Http/Request.php | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/Http/Request.php b/app/Http/Request.php
index 687bae9a6..13892603d 100644
--- a/app/Http/Request.php
+++ b/app/Http/Request.php
@@ -26,6 +26,7 @@ class Request extends LaravelRequest
     /**
      * Override the default request methods to get the base URL
      * to directly use the custom APP_URL, if set.
+     * The base URL never ends with a / but should start with one if not empty.
      *
      * @return string
      */
@@ -34,7 +35,7 @@ class Request extends LaravelRequest
         $appUrl = config('app.url', null);
 
         if ($appUrl) {
-            return rtrim(implode('/', array_slice(explode('/', $appUrl), 3)), '/');
+            return '/' . rtrim(implode('/', array_slice(explode('/', $appUrl), 3)), '/');
         }
 
         return parent::getBaseUrl();

From 56254bdb66678ea69f70c95a3262d575dae03e11 Mon Sep 17 00:00:00 2001
From: Dan Brown <ssddanbrown@googlemail.com>
Date: Wed, 13 Apr 2022 13:02:42 +0100
Subject: [PATCH 3/3] Added testing for our request method overrides

---
 tests/Unit/UrlTest.php | 22 ----------------------
 tests/UrlTest.php      | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 22 deletions(-)
 delete mode 100644 tests/Unit/UrlTest.php
 create mode 100644 tests/UrlTest.php

diff --git a/tests/Unit/UrlTest.php b/tests/Unit/UrlTest.php
deleted file mode 100644
index fff5414f2..000000000
--- a/tests/Unit/UrlTest.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-
-namespace Tests\Unit;
-
-use Tests\TestCase;
-
-class UrlTest extends TestCase
-{
-    public function test_url_helper_takes_custom_url_into_account()
-    {
-        $this->runWithEnv('APP_URL', 'http://example.com/bookstack', function () {
-            $this->assertEquals('http://example.com/bookstack/books', url('/books'));
-        });
-    }
-
-    public function test_url_helper_sets_correct_scheme_even_when_request_scheme_is_different()
-    {
-        $this->runWithEnv('APP_URL', 'https://example.com/', function () {
-            $this->get('http://example.com/login')->assertSee('https://example.com/dist/styles.css');
-        });
-    }
-}
diff --git a/tests/UrlTest.php b/tests/UrlTest.php
new file mode 100644
index 000000000..b9f1acf4b
--- /dev/null
+++ b/tests/UrlTest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Tests;
+
+use BookStack\Http\Request;
+use function url;
+use function request;
+
+class UrlTest extends TestCase
+{
+    public function test_url_helper_takes_custom_url_into_account()
+    {
+        $this->runWithEnv('APP_URL', 'http://example.com/bookstack', function () {
+            $this->assertEquals('http://example.com/bookstack/books', url('/books'));
+        });
+    }
+
+    public function test_url_helper_sets_correct_scheme_even_when_request_scheme_is_different()
+    {
+        $this->runWithEnv('APP_URL', 'https://example.com/', function () {
+            $this->get('http://example.com/login')->assertSee('https://example.com/dist/styles.css');
+        });
+    }
+
+    public function test_app_url_forces_overrides_on_base_request()
+    {
+        config()->set('app.url', 'https://donkey.example.com:8091/cool/docs');
+
+        // Have to manually get and wrap request in our custom type due to testing mechanics
+        $this->get('/login');
+        $bsRequest = Request::createFrom(request());
+
+        $this->assertEquals('https://donkey.example.com:8091', $bsRequest->getSchemeAndHttpHost());
+        $this->assertEquals('/cool/docs', $bsRequest->getBaseUrl());
+        $this->assertEquals('https://donkey.example.com:8091/cool/docs/login', $bsRequest->getUri());
+    }
+}