Skip to content

Commit e4ed547

Browse files
authored
Merge pull request #50099 from nextcloud/jtr/fix-appframework-server-proto
2 parents 17ae4e7 + d2a20ea commit e4ed547

File tree

4 files changed

+73
-24
lines changed

4 files changed

+73
-24
lines changed

lib/composer/composer/InstalledVersions.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
*/
2727
class InstalledVersions
2828
{
29+
/**
30+
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
31+
* @internal
32+
*/
33+
private static $selfDir = null;
34+
2935
/**
3036
* @var mixed[]|null
3137
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
@@ -322,6 +328,18 @@ public static function reload($data)
322328
self::$installedIsLocalDir = false;
323329
}
324330

331+
/**
332+
* @return string
333+
*/
334+
private static function getSelfDir()
335+
{
336+
if (self::$selfDir === null) {
337+
self::$selfDir = strtr(__DIR__, '\\', '/');
338+
}
339+
340+
return self::$selfDir;
341+
}
342+
325343
/**
326344
* @return array[]
327345
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
@@ -336,7 +354,7 @@ private static function getInstalled()
336354
$copiedLocalDir = false;
337355

338356
if (self::$canGetVendors) {
339-
$selfDir = strtr(__DIR__, '\\', '/');
357+
$selfDir = self::getSelfDir();
340358
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
341359
$vendorDir = strtr($vendorDir, '\\', '/');
342360
if (isset(self::$installedByVendor[$vendorDir])) {

lib/composer/composer/installed.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'name' => '__root__',
44
'pretty_version' => 'dev-master',
55
'version' => 'dev-master',
6-
'reference' => 'b7422ba97b7b42a9955a52031a32457ca521d740',
6+
'reference' => '3fce359f4c606737b21b1b4213efd5bc5536e867',
77
'type' => 'library',
88
'install_path' => __DIR__ . '/../../../',
99
'aliases' => array(),
@@ -13,7 +13,7 @@
1313
'__root__' => array(
1414
'pretty_version' => 'dev-master',
1515
'version' => 'dev-master',
16-
'reference' => 'b7422ba97b7b42a9955a52031a32457ca521d740',
16+
'reference' => '3fce359f4c606737b21b1b4213efd5bc5536e867',
1717
'type' => 'library',
1818
'install_path' => __DIR__ . '/../../../',
1919
'aliases' => array(),

lib/private/AppFramework/Http/Request.php

Lines changed: 29 additions & 18 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 {
634-
if ($this->config->getSystemValueString('overwriteprotocol') !== ''
635-
&& $this->isOverwriteCondition()) {
636-
return $this->config->getSystemValueString('overwriteprotocol');
637-
}
640+
$proto = 'http';
638641

639-
if ($this->fromTrustedProxy() && isset($this->server['HTTP_X_FORWARDED_PROTO'])) {
642+
if ($this->config->getSystemValueString('overwriteprotocol') !== ''
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';
655+
} elseif (!empty($this->server['HTTPS'])
656+
&& $this->server['HTTPS'] !== 'off'
657+
) {
658+
$proto = 'https';
650659
}
651660

652-
if (isset($this->server['HTTPS'])
653-
&& $this->server['HTTPS'] !== null
654-
&& $this->server['HTTPS'] !== 'off'
655-
&& $this->server['HTTPS'] !== '') {
656-
return 'https';
661+
if ($proto !== 'https' && $proto !== 'http') {
662+
// log unrecognized value so admin has a chance to fix it
663+
\OCP\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+
);
657667
}
658668

659-
return 'http';
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,7 +794,27 @@ public function testGetServerProtocolWithOverride(): void {
794794
$this->stream
795795
);
796796

797-
$this->assertSame('customProtocol', $request->getServerProtocol());
797+
$this->assertSame('https', $request->getServerProtocol());
798+
}
799+
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());
798818
}
799819

800820
public function testGetServerProtocolWithProtoValid(): void {

0 commit comments

Comments
 (0)