aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh <josh.t.richards@gmail.com>2025-01-08 13:31:03 -0500
committerJosh Richards <josh.t.richards@gmail.com>2025-01-09 09:51:26 -0500
commit6b84508733e086477caa5417010b6d3c9146cae7 (patch)
treeba7783a4457eb47567fde269fde851efd4a3d91d
parentdd0f7f0bbfb9c176fe4845458bdc62ec7b388d8f (diff)
downloadnextcloud-server-jtr/fix-appframework-server-proto.tar.gz
nextcloud-server-jtr/fix-appframework-server-proto.zip
fix(AppFramework): Log malformed protocol values and unify fallback behaviorjtr/fix-appframework-server-proto
Signed-off-by: Josh <josh.t.richards@gmail.com>
-rw-r--r--lib/private/AppFramework/Http/Request.php49
-rw-r--r--tests/lib/AppFramework/Http/RequestTest.php26
2 files changed, 53 insertions, 22 deletions
diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php
index d177221556c..27b15e1b72d 100644
--- a/lib/private/AppFramework/Http/Request.php
+++ b/lib/private/AppFramework/Http/Request.php
@@ -14,6 +14,7 @@ use OC\Security\TrustedDomainHelper;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IRequestId;
+use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\IpUtils;
/**
@@ -613,36 +614,46 @@ class Request implements \ArrayAccess, \Countable, IRequest {
/**
* Returns the server protocol. It respects one or more reverse proxies servers
- * and load balancers
+ * and load balancers. Precedence:
+ * 1. `overwriteprotocol` config value
+ * 2. `X-Forwarded-Proto` header value
+ * 3. $_SERVER['HTTPS'] value
+ * If an invalid protocol is provided, defaults to http, continues, but logs as an error.
+ *
* @return string Server protocol (http or https)
*/
public function getServerProtocol(): string {
+ $proto = 'http';
+
if ($this->config->getSystemValueString('overwriteprotocol') !== ''
- && $this->isOverwriteCondition()) {
- return $this->config->getSystemValueString('overwriteprotocol');
- }
-
- if ($this->fromTrustedProxy() && isset($this->server['HTTP_X_FORWARDED_PROTO'])) {
+ && $this->isOverwriteCondition()
+ ) {
+ $proto = strtolower($this->config->getSystemValueString('overwriteprotocol'));
+ } elseif ($this->fromTrustedProxy()
+ && isset($this->server['HTTP_X_FORWARDED_PROTO'])
+ ) {
if (str_contains($this->server['HTTP_X_FORWARDED_PROTO'], ',')) {
$parts = explode(',', $this->server['HTTP_X_FORWARDED_PROTO']);
$proto = strtolower(trim($parts[0]));
} else {
$proto = strtolower($this->server['HTTP_X_FORWARDED_PROTO']);
}
-
- // Verify that the protocol is always HTTP or HTTPS
- // default to http if an invalid value is provided
- return $proto === 'https' ? 'https' : 'http';
- }
-
- if (isset($this->server['HTTPS'])
- && $this->server['HTTPS'] !== null
+ } elseif (!empty($this->server['HTTPS'])
&& $this->server['HTTPS'] !== 'off'
- && $this->server['HTTPS'] !== '') {
- return 'https';
+ ) {
+ $proto = 'https';
}
- return 'http';
+ if ($proto !== 'https' && $proto !== 'http') {
+ // log unrecognized value so admin has a chance to fix it
+ \OC::$server->get(LoggerInterface::class)->critical(
+ 'Server protocol is malformed [falling back to http] (check overwriteprotocol and/or X-Forwarded-Proto to remedy): ' . $proto,
+ ['app' => 'core']
+ );
+ }
+
+ // default to http if provided an invalid value
+ return $proto === 'https' ? 'https' : 'http';
}
/**
@@ -729,11 +740,11 @@ class Request implements \ArrayAccess, \Countable, IRequest {
}
/**
- * Get PathInfo from request
+ * Get PathInfo from request (rawurldecoded)
* @throws \Exception
* @return string|false Path info or false when not found
*/
- public function getPathInfo() {
+ public function getPathInfo(): string|false {
$pathInfo = $this->getRawPathInfo();
return \Sabre\HTTP\decodePath($pathInfo);
}
diff --git a/tests/lib/AppFramework/Http/RequestTest.php b/tests/lib/AppFramework/Http/RequestTest.php
index 1c7f07580cc..4bf0ac84bed 100644
--- a/tests/lib/AppFramework/Http/RequestTest.php
+++ b/tests/lib/AppFramework/Http/RequestTest.php
@@ -787,12 +787,12 @@ class RequestTest extends \Test\TestCase {
$this->assertSame($expected, $request->getHttpProtocol());
}
- public function testGetServerProtocolWithOverride(): void {
+ public function testGetServerProtocolWithOverrideValid(): void {
$this->config
->expects($this->exactly(3))
->method('getSystemValueString')
->willReturnMap([
- ['overwriteprotocol', '', 'customProtocol'],
+ ['overwriteprotocol', '', 'HTTPS'], // should be automatically lowercased
['overwritecondaddr', '', ''],
]);
@@ -804,9 +804,29 @@ class RequestTest extends \Test\TestCase {
$this->stream
);
- $this->assertSame('customProtocol', $request->getServerProtocol());
+ $this->assertSame('https', $request->getServerProtocol());
}
+ public function testGetServerProtocolWithOverrideInValid(): void {
+ $this->config
+ ->expects($this->exactly(3))
+ ->method('getSystemValueString')
+ ->willReturnMap([
+ ['overwriteprotocol', '', 'bogusProtocol'], // should trigger fallback to http
+ ['overwritecondaddr', '', ''],
+ ]);
+
+ $request = new Request(
+ [],
+ $this->requestId,
+ $this->config,
+ $this->csrfTokenManager,
+ $this->stream
+ );
+
+ $this->assertSame('http', $request->getServerProtocol());
+ }
+
public function testGetServerProtocolWithProtoValid(): void {
$this->config
->method('getSystemValue')