Skip to content

Commit e29d41d

Browse files
joshtrichardsskjnldsv
authored andcommitted
fix(AppFramework): Log malformed protocol values and unify fallback behavior
Signed-off-by: Josh <josh.t.richards@gmail.com>
1 parent e8fbb0d commit e29d41d

File tree

2 files changed

+53
-22
lines changed

2 files changed

+53
-22
lines changed

lib/private/AppFramework/Http/Request.php

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use OCP\IConfig;
1515
use OCP\IRequest;
1616
use OCP\IRequestId;
17+
use Psr\Log\LoggerInterface;
1718
use Symfony\Component\HttpFoundation\IpUtils;
1819

1920
/**
@@ -627,36 +628,46 @@ private function isOverwriteCondition(): bool {
627628

628629
/**
629630
* Returns the server protocol. It respects one or more reverse proxies servers
630-
* and load balancers
631+
* and load balancers. Precedence:
632+
* 1. `overwriteprotocol` config value
633+
* 2. `X-Forwarded-Proto` header value
634+
* 3. $_SERVER['HTTPS'] value
635+
* If an invalid protocol is provided, defaults to http, continues, but logs as an error.
636+
*
631637
* @return string Server protocol (http or https)
632638
*/
633639
public function getServerProtocol(): string {
640+
$proto = 'http';
641+
634642
if ($this->config->getSystemValueString('overwriteprotocol') !== ''
635-
&& $this->isOverwriteCondition()) {
636-
return $this->config->getSystemValueString('overwriteprotocol');
637-
}
638-
639-
if ($this->fromTrustedProxy() && isset($this->server['HTTP_X_FORWARDED_PROTO'])) {
643+
&& $this->isOverwriteCondition()
644+
) {
645+
$proto = strtolower($this->config->getSystemValueString('overwriteprotocol'));
646+
} elseif ($this->fromTrustedProxy()
647+
&& isset($this->server['HTTP_X_FORWARDED_PROTO'])
648+
) {
640649
if (str_contains($this->server['HTTP_X_FORWARDED_PROTO'], ',')) {
641650
$parts = explode(',', $this->server['HTTP_X_FORWARDED_PROTO']);
642651
$proto = strtolower(trim($parts[0]));
643652
} else {
644653
$proto = strtolower($this->server['HTTP_X_FORWARDED_PROTO']);
645654
}
646-
647-
// Verify that the protocol is always HTTP or HTTPS
648-
// default to http if an invalid value is provided
649-
return $proto === 'https' ? 'https' : 'http';
650-
}
651-
652-
if (isset($this->server['HTTPS'])
653-
&& $this->server['HTTPS'] !== null
655+
} elseif (!empty($this->server['HTTPS'])
654656
&& $this->server['HTTPS'] !== 'off'
655-
&& $this->server['HTTPS'] !== '') {
656-
return 'https';
657+
) {
658+
$proto = 'https';
657659
}
658660

659-
return 'http';
661+
if ($proto !== 'https' && $proto !== 'http') {
662+
// log unrecognized value so admin has a chance to fix it
663+
\OC::$server->get(LoggerInterface::class)->critical(
664+
'Server protocol is malformed [falling back to http] (check overwriteprotocol and/or X-Forwarded-Proto to remedy): ' . $proto,
665+
['app' => 'core']
666+
);
667+
}
668+
669+
// default to http if provided an invalid value
670+
return $proto === 'https' ? 'https' : 'http';
660671
}
661672

662673
/**
@@ -743,11 +754,11 @@ public function getRawPathInfo(): string {
743754
}
744755

745756
/**
746-
* Get PathInfo from request
757+
* Get PathInfo from request (rawurldecoded)
747758
* @throws \Exception
748759
* @return string|false Path info or false when not found
749760
*/
750-
public function getPathInfo() {
761+
public function getPathInfo(): string|false {
751762
$pathInfo = $this->getRawPathInfo();
752763
return \Sabre\HTTP\decodePath($pathInfo);
753764
}

tests/lib/AppFramework/Http/RequestTest.php

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -777,12 +777,12 @@ public function testGetHttpProtocol($input, $expected): void {
777777
$this->assertSame($expected, $request->getHttpProtocol());
778778
}
779779

780-
public function testGetServerProtocolWithOverride(): void {
780+
public function testGetServerProtocolWithOverrideValid(): void {
781781
$this->config
782782
->expects($this->exactly(3))
783783
->method('getSystemValueString')
784784
->willReturnMap([
785-
['overwriteprotocol', '', 'customProtocol'],
785+
['overwriteprotocol', '', 'HTTPS'], // should be automatically lowercased
786786
['overwritecondaddr', '', ''],
787787
]);
788788

@@ -794,9 +794,29 @@ public function testGetServerProtocolWithOverride(): void {
794794
$this->stream
795795
);
796796

797-
$this->assertSame('customProtocol', $request->getServerProtocol());
797+
$this->assertSame('https', $request->getServerProtocol());
798798
}
799799

800+
public function testGetServerProtocolWithOverrideInValid(): void {
801+
$this->config
802+
->expects($this->exactly(3))
803+
->method('getSystemValueString')
804+
->willReturnMap([
805+
['overwriteprotocol', '', 'bogusProtocol'], // should trigger fallback to http
806+
['overwritecondaddr', '', ''],
807+
]);
808+
809+
$request = new Request(
810+
[],
811+
$this->requestId,
812+
$this->config,
813+
$this->csrfTokenManager,
814+
$this->stream
815+
);
816+
817+
$this->assertSame('http', $request->getServerProtocol());
818+
}
819+
800820
public function testGetServerProtocolWithProtoValid(): void {
801821
$this->config
802822
->method('getSystemValue')

0 commit comments

Comments
 (0)