bug #28144 [HttpFoundation] fix false-positive ConflictingHeadersException (nicolas-grekas)

This PR was merged into the 2.8 branch.

Discussion
----------

[HttpFoundation] fix false-positive ConflictingHeadersException

| Q             | A
| ------------- | ---
| Branch?       | 2.8
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #28153
| License       | MIT
| Doc PR        | -

Fixes https://jira.ez.no/browse/EZP-29492 & https://jira.ez.no/browse/EZP-29497
Ping @andrerom

Commits
-------

6089290543 [HttpFoundation] fix false-positive ConflictingHeadersException
This commit is contained in:
Nicolas Grekas 2018-08-08 10:05:06 +02:00
commit 74a4ceaad6
2 changed files with 66 additions and 6 deletions

View File

@ -1943,10 +1943,13 @@ class Request
if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
$forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
$forwardedValues = preg_match_all(sprintf('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array();
$forwardedValues = preg_match_all(sprintf('{(?:%s)="?([a-zA-Z0-9\.:_\-/\[\]]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array();
if (self::HEADER_CLIENT_PORT === $type) {
foreach ($forwardedValues as $k => $v) {
$forwardedValues[$k] = substr_replace($v, '0.0.0.0', 0, strrpos($v, ':'));
if (']' === substr($v, -1) || false === $v = strrchr($v, ':')) {
$v = $this->isSecure() ? ':443' : ':80';
}
$forwardedValues[$k] = '0.0.0.0'.$v;
}
}
}
@ -1981,9 +1984,17 @@ class Request
$firstTrustedIp = null;
foreach ($clientIps as $key => $clientIp) {
// Remove port (unfortunately, it does happen)
if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
$clientIps[$key] = $clientIp = $match[1];
if (strpos($clientIp, '.')) {
// Strip :port from IPv4 addresses. This is allowed in Forwarded
// and may occur in X-Forwarded-For.
$i = strpos($clientIp, ':');
if ($i) {
$clientIps[$key] = $clientIp = substr($clientIp, 0, $i);
}
} elseif ('[' == $clientIp[0]) {
// Strip brackets and :port from IPv6 addresses.
$i = strpos($clientIp, ']', 1);
$clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1);
}
if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {

View File

@ -967,7 +967,7 @@ class RequestTest extends TestCase
'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor,
);
Request::setTrustedProxies(array('88.88.88.88'));
Request::setTrustedProxies(array('88.88.88.88'), -1);
$request->initialize(array(), array(), array(), array(), array(), $server);
@ -2071,6 +2071,55 @@ class RequestTest extends TestCase
$this->assertEquals($expectedBaseUrl, $request->getBaseUrl());
$this->assertEquals($expectedBasePath, $request->getBasePath());
}
public function testTrustedHost()
{
Request::setTrustedProxies(array('1.1.1.1'), -1);
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host=localhost:8080');
$request->headers->set('X-Forwarded-Host', 'localhost:8080');
$this->assertSame('localhost:8080', $request->getHttpHost());
$this->assertSame(8080, $request->getPort());
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host="[::1]:443"');
$request->headers->set('X-Forwarded-Host', '[::1]:443');
$request->headers->set('X-Forwarded-Port', 443);
$this->assertSame('[::1]:443', $request->getHttpHost());
$this->assertSame(443, $request->getPort());
}
public function testTrustedPort()
{
Request::setTrustedProxies(array('1.1.1.1'), -1);
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host=localhost:8080');
$request->headers->set('X-Forwarded-Port', 8080);
$this->assertSame(8080, $request->getPort());
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host=localhost');
$request->headers->set('X-Forwarded-Port', 80);
$this->assertSame(80, $request->getPort());
$request = Request::create('/');
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('Forwarded', 'host="[::1]"');
$request->headers->set('X-Forwarded-Proto', 'https');
$request->headers->set('X-Forwarded-Port', 443);
$this->assertSame(443, $request->getPort());
}
}
class RequestContentProxy extends Request