diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index 70305ae5864c..e0a6ff9f2386 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -581,12 +581,34 @@ public function __toString(): string $path = $this->getPath(); $scheme = $this->getScheme(); + // If the hosts matches then assume this should be relative to baseURL + [$scheme, $path] = $this->changeSchemeAndPath($scheme, $path); + + return static::createURIString( + $scheme, + $this->getAuthority(), + $path, // Absolute URIs should use a "/" for an empty path + $this->getQuery(), + $this->getFragment() + ); + } + + /** + * Change the path (and scheme) assuming URIs with the same host as baseURL + * should be relative to the project's configuration. + * + * @deprecated This method will be deleted. + */ + private function changeSchemeAndPath(string $scheme, string $path): array + { // Check if this is an internal URI $config = config('App'); $baseUri = new self($config->baseURL); - // If the hosts matches then assume this should be relative to baseURL - if ($this->getHost() === $baseUri->getHost()) { + if ( + substr($this->getScheme(), 0, 4) === 'http' + && $this->getHost() === $baseUri->getHost() + ) { // Check for additional segments $basePath = trim($baseUri->getPath(), '/') . '/'; $trimPath = ltrim($path, '/'); @@ -601,13 +623,7 @@ public function __toString(): string } } - return static::createURIString( - $scheme, - $this->getAuthority(), - $path, // Absolute URIs should use a "/" for an empty path - $this->getQuery(), - $this->getFragment() - ); + return [$scheme, $path]; } /** diff --git a/tests/system/HTTP/URITest.php b/tests/system/HTTP/URITest.php index 8536fcc7c801..a4faacfbdd80 100644 --- a/tests/system/HTTP/URITest.php +++ b/tests/system/HTTP/URITest.php @@ -985,4 +985,20 @@ public function testCreateURIString() $this->assertSame($expected, $uri); } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5728 + */ + public function testForceGlobalSecureRequestsAndNonHTTPProtocol() + { + $config = new App(); + $config->forceGlobalSecureRequests = true; + $config->baseURL = 'https://localhost/'; + Factories::injectMock('config', 'App', $config); + + $expected = 'ftp://localhost/path/to/test.txt'; + $uri = new URI($expected); + + $this->assertSame($expected, (string) $uri); + } }