Skip to content

Commit 73abd62

Browse files
Toflarfabpot
authored andcommitted
[HttpFoundation] Cache trusted values
1 parent bc38faa commit 73abd62

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ class Request
212212
private bool $isForwardedValid = true;
213213
private bool $isSafeContentPreferred;
214214

215+
private array $trustedValuesCache = [];
216+
215217
private static int $trustedHeaderSet = -1;
216218

217219
private const FORWARDED_PARAMS = [
@@ -1997,8 +1999,20 @@ public function isFromTrustedProxy(): bool
19971999
return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR', ''), self::$trustedProxies);
19982000
}
19992001

2002+
/**
2003+
* This method is rather heavy because it splits and merges headers, and it's called by many other methods such as
2004+
* getPort(), isSecure(), getHost(), getClientIps(), getBaseUrl() etc. Thus, we try to cache the results for
2005+
* best performance.
2006+
*/
20002007
private function getTrustedValues(int $type, string $ip = null): array
20012008
{
2009+
$cacheKey = $type."\0".((self::$trustedHeaderSet & $type) ? $this->headers->get(self::TRUSTED_HEADERS[$type]) : '');
2010+
$cacheKey .= "\0".$ip."\0".$this->headers->get(self::TRUSTED_HEADERS[self::HEADER_FORWARDED]);
2011+
2012+
if (isset($this->trustedValuesCache[$cacheKey])) {
2013+
return $this->trustedValuesCache[$cacheKey];
2014+
}
2015+
20022016
$clientValues = [];
20032017
$forwardedValues = [];
20042018

@@ -2011,7 +2025,6 @@ private function getTrustedValues(int $type, string $ip = null): array
20112025
if ((self::$trustedHeaderSet & self::HEADER_FORWARDED) && (isset(self::FORWARDED_PARAMS[$type])) && $this->headers->has(self::TRUSTED_HEADERS[self::HEADER_FORWARDED])) {
20122026
$forwarded = $this->headers->get(self::TRUSTED_HEADERS[self::HEADER_FORWARDED]);
20132027
$parts = HeaderUtils::split($forwarded, ',;=');
2014-
$forwardedValues = [];
20152028
$param = self::FORWARDED_PARAMS[$type];
20162029
foreach ($parts as $subParts) {
20172030
if (null === $v = HeaderUtils::combine($subParts)[$param] ?? null) {
@@ -2033,15 +2046,15 @@ private function getTrustedValues(int $type, string $ip = null): array
20332046
}
20342047

20352048
if ($forwardedValues === $clientValues || !$clientValues) {
2036-
return $forwardedValues;
2049+
return $this->trustedValuesCache[$cacheKey] = $forwardedValues;
20372050
}
20382051

20392052
if (!$forwardedValues) {
2040-
return $clientValues;
2053+
return $this->trustedValuesCache[$cacheKey] = $clientValues;
20412054
}
20422055

20432056
if (!$this->isForwardedValid) {
2044-
return null !== $ip ? ['0.0.0.0', $ip] : [];
2057+
return $this->trustedValuesCache[$cacheKey] = null !== $ip ? ['0.0.0.0', $ip] : [];
20452058
}
20462059
$this->isForwardedValid = false;
20472060

src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,6 +2550,23 @@ public function testTrustedProxiesRemoteAddr($serverRemoteAddr, $trustedProxies,
25502550
$this->assertSame($result, Request::getTrustedProxies());
25512551
}
25522552

2553+
public function testTrustedValuesCache()
2554+
{
2555+
$request = Request::create('http://example.com/');
2556+
$request->server->set('REMOTE_ADDR', '3.3.3.3');
2557+
$request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2');
2558+
$request->headers->set('X_FORWARDED_PROTO', 'https');
2559+
2560+
$this->assertFalse($request->isSecure());
2561+
2562+
Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO);
2563+
$this->assertTrue($request->isSecure());
2564+
2565+
// Header is changed, cache must not be hit now
2566+
$request->headers->set('X_FORWARDED_PROTO', 'http');
2567+
$this->assertFalse($request->isSecure());
2568+
}
2569+
25532570
public static function trustedProxiesRemoteAddr()
25542571
{
25552572
return [

0 commit comments

Comments
 (0)