Merge branch '4.1'
* 4.1: [HttpKernel] fix trusted headers management in HttpCache and InlineFragmentRenderer
This commit is contained in:
commit
67044af83d
@ -1962,7 +1962,7 @@ class Request
|
|||||||
foreach ($parts as $subParts) {
|
foreach ($parts as $subParts) {
|
||||||
$assoc = HeaderUtils::combine($subParts);
|
$assoc = HeaderUtils::combine($subParts);
|
||||||
if (isset($assoc[$param])) {
|
if (isset($assoc[$param])) {
|
||||||
$forwardedValues[] = $assoc[$param];
|
$forwardedValues[] = self::HEADER_X_FORWARDED_PORT === $type ? substr_replace($assoc[$param], '0.0.0.0', 0, strrpos($assoc[$param], ':')) : $assoc[$param];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Controller\ControllerReference;
|
use Symfony\Component\HttpKernel\Controller\ControllerReference;
|
||||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||||
|
use Symfony\Component\HttpKernel\HttpCache\SubRequestHandler;
|
||||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
use Symfony\Component\HttpKernel\KernelEvents;
|
use Symfony\Component\HttpKernel\KernelEvents;
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
|
|||||||
|
|
||||||
$level = ob_get_level();
|
$level = ob_get_level();
|
||||||
try {
|
try {
|
||||||
return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false);
|
return SubRequestHandler::handle($this->kernel, $subRequest, HttpKernelInterface::SUB_REQUEST, false);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
// we dispatch the exception event to trigger the logging
|
// we dispatch the exception event to trigger the logging
|
||||||
// the response that comes back is simply ignored
|
// the response that comes back is simply ignored
|
||||||
@ -109,14 +110,6 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
|
|||||||
$cookies = $request->cookies->all();
|
$cookies = $request->cookies->all();
|
||||||
$server = $request->server->all();
|
$server = $request->server->all();
|
||||||
|
|
||||||
if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
|
|
||||||
$currentXForwardedFor = $request->headers->get('X_FORWARDED_FOR', '');
|
|
||||||
|
|
||||||
$server['HTTP_X_FORWARDED_FOR'] = ($currentXForwardedFor ? $currentXForwardedFor.', ' : '').$request->getClientIp();
|
|
||||||
}
|
|
||||||
|
|
||||||
$server['REMOTE_ADDR'] = $this->resolveTrustedProxy();
|
|
||||||
|
|
||||||
unset($server['HTTP_IF_MODIFIED_SINCE']);
|
unset($server['HTTP_IF_MODIFIED_SINCE']);
|
||||||
unset($server['HTTP_IF_NONE_MATCH']);
|
unset($server['HTTP_IF_NONE_MATCH']);
|
||||||
|
|
||||||
@ -135,17 +128,6 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
|
|||||||
return $subRequest;
|
return $subRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resolveTrustedProxy()
|
|
||||||
{
|
|
||||||
if (!$trustedProxies = Request::getTrustedProxies()) {
|
|
||||||
return '127.0.0.1';
|
|
||||||
}
|
|
||||||
|
|
||||||
$firstTrustedProxy = reset($trustedProxies);
|
|
||||||
|
|
||||||
return false !== ($i = strpos($firstTrustedProxy, '/')) ? substr($firstTrustedProxy, 0, $i) : $firstTrustedProxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -444,27 +444,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
|
|||||||
$this->surrogate->addSurrogateCapability($request);
|
$this->surrogate->addSurrogateCapability($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
// modify the X-Forwarded-For header if needed
|
|
||||||
$forwardedFor = $request->headers->get('X-Forwarded-For');
|
|
||||||
if ($forwardedFor) {
|
|
||||||
$request->headers->set('X-Forwarded-For', $forwardedFor.', '.$request->server->get('REMOTE_ADDR'));
|
|
||||||
} else {
|
|
||||||
$request->headers->set('X-Forwarded-For', $request->server->get('REMOTE_ADDR'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix the client IP address by setting it to 127.0.0.1 as HttpCache
|
|
||||||
// is always called from the same process as the backend.
|
|
||||||
$request->server->set('REMOTE_ADDR', '127.0.0.1');
|
|
||||||
|
|
||||||
// make sure HttpCache is a trusted proxy
|
|
||||||
if (!\in_array('127.0.0.1', $trustedProxies = Request::getTrustedProxies())) {
|
|
||||||
$trustedProxies[] = '127.0.0.1';
|
|
||||||
Request::setTrustedProxies($trustedProxies, Request::HEADER_X_FORWARDED_ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// always a "master" request (as the real master request can be in cache)
|
// always a "master" request (as the real master request can be in cache)
|
||||||
$response = $this->kernel->handle($request, HttpKernelInterface::MASTER_REQUEST, $catch);
|
$response = SubRequestHandler::handle($this->kernel, $request, HttpKernelInterface::MASTER_REQUEST, $catch);
|
||||||
// FIXME: we probably need to also catch exceptions if raw === true
|
|
||||||
|
|
||||||
// we don't implement the stale-if-error on Requests, which is nonetheless part of the RFC
|
// we don't implement the stale-if-error on Requests, which is nonetheless part of the RFC
|
||||||
if (null !== $entry && \in_array($response->getStatusCode(), array(500, 502, 503, 504))) {
|
if (null !== $entry && \in_array($response->getStatusCode(), array(500, 502, 503, 504))) {
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpKernel\HttpCache;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\IpUtils;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class SubRequestHandler
|
||||||
|
{
|
||||||
|
public static function handle(HttpKernelInterface $kernel, Request $request, $type, $catch): Response
|
||||||
|
{
|
||||||
|
// save global state related to trusted headers and proxies
|
||||||
|
$trustedProxies = Request::getTrustedProxies();
|
||||||
|
$trustedHeaderSet = Request::getTrustedHeaderSet();
|
||||||
|
|
||||||
|
// remove untrusted values
|
||||||
|
$remoteAddr = $request->server->get('REMOTE_ADDR');
|
||||||
|
if (!IpUtils::checkIp($remoteAddr, $trustedProxies)) {
|
||||||
|
$trustedHeaders = array(
|
||||||
|
'FORWARDED' => $trustedHeaderSet & Request::HEADER_FORWARDED,
|
||||||
|
'X_FORWARDED_FOR' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_FOR,
|
||||||
|
'X_FORWARDED_HOST' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_HOST,
|
||||||
|
'X_FORWARDED_PROTO' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PROTO,
|
||||||
|
'X_FORWARDED_PORT' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PORT,
|
||||||
|
);
|
||||||
|
foreach (array_filter($trustedHeaders) as $name => $key) {
|
||||||
|
$request->headers->remove($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute trusted values, taking any trusted proxies into account
|
||||||
|
$trustedIps = array();
|
||||||
|
$trustedValues = array();
|
||||||
|
foreach (array_reverse($request->getClientIps()) as $ip) {
|
||||||
|
$trustedIps[] = $ip;
|
||||||
|
$trustedValues[] = sprintf('for="%s"', $ip);
|
||||||
|
}
|
||||||
|
if ($ip !== $remoteAddr) {
|
||||||
|
$trustedIps[] = $remoteAddr;
|
||||||
|
$trustedValues[] = sprintf('for="%s"', $remoteAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set trusted values, reusing as much as possible the global trusted settings
|
||||||
|
if (Request::HEADER_FORWARDED & $trustedHeaderSet) {
|
||||||
|
$trustedValues[0] .= sprintf(';host="%s";proto=%s', $request->getHttpHost(), $request->getScheme());
|
||||||
|
$request->headers->set('Forwarded', implode(', ', $trustedValues));
|
||||||
|
}
|
||||||
|
if (Request::HEADER_X_FORWARDED_FOR & $trustedHeaderSet) {
|
||||||
|
$request->headers->set('X-Forwarded-For', implode(', ', $trustedIps));
|
||||||
|
} elseif (!(Request::HEADER_FORWARDED & $trustedHeaderSet)) {
|
||||||
|
Request::setTrustedProxies($trustedProxies, $trustedHeaderSet | Request::HEADER_X_FORWARDED_FOR);
|
||||||
|
$request->headers->set('X-Forwarded-For', implode(', ', $trustedIps));
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix the client IP address by setting it to 127.0.0.1,
|
||||||
|
// which is the core responsibility of this method
|
||||||
|
$request->server->set('REMOTE_ADDR', '127.0.0.1');
|
||||||
|
|
||||||
|
// ensure 127.0.0.1 is set as trusted proxy
|
||||||
|
if (!IpUtils::checkIp('127.0.0.1', $trustedProxies)) {
|
||||||
|
Request::setTrustedProxies(array_merge($trustedProxies, array('127.0.0.1')), Request::getTrustedHeaderSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $kernel->handle($request, $type, $catch);
|
||||||
|
} finally {
|
||||||
|
// restore global state
|
||||||
|
Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -44,7 +44,7 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
$subRequest = Request::create('/_fragment?_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dmain_controller');
|
$subRequest = Request::create('/_fragment?_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dmain_controller');
|
||||||
$subRequest->attributes->replace(array('object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en'));
|
$subRequest->attributes->replace(array('object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en'));
|
||||||
$subRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$subRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$subRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
$subRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest));
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest));
|
||||||
|
|
||||||
@ -55,7 +55,10 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
{
|
{
|
||||||
Request::setTrustedProxies(array(), 0);
|
Request::setTrustedProxies(array(), 0);
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest(Request::create('/')));
|
$expectedSubRequest = Request::create('/');
|
||||||
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
|
|
||||||
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
||||||
$this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent());
|
$this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent());
|
||||||
|
|
||||||
Request::setTrustedProxies(array(), -1);
|
Request::setTrustedProxies(array(), -1);
|
||||||
@ -146,8 +149,8 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
|
|
||||||
if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
|
if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
|
||||||
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
|
||||||
}
|
}
|
||||||
|
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
||||||
|
|
||||||
@ -158,7 +161,7 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
|
|
||||||
public function testESIHeaderIsKeptInSubrequestWithTrustedHeaderDisabled()
|
public function testESIHeaderIsKeptInSubrequestWithTrustedHeaderDisabled()
|
||||||
{
|
{
|
||||||
Request::setTrustedProxies(array(), 0);
|
Request::setTrustedProxies(array(), Request::HEADER_FORWARDED);
|
||||||
|
|
||||||
$this->testESIHeaderIsKeptInSubrequest();
|
$this->testESIHeaderIsKeptInSubrequest();
|
||||||
|
|
||||||
@ -169,7 +172,7 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
{
|
{
|
||||||
$expectedSubRequest = Request::create('/');
|
$expectedSubRequest = Request::create('/');
|
||||||
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
||||||
$request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*'));
|
$request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*'));
|
||||||
@ -182,9 +185,9 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
|
|
||||||
$expectedSubRequest = Request::create('/');
|
$expectedSubRequest = Request::create('/');
|
||||||
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
||||||
$expectedSubRequest->server->set('REMOTE_ADDR', '1.1.1.1');
|
$expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
|
||||||
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
||||||
|
|
||||||
@ -199,9 +202,9 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
{
|
{
|
||||||
$expectedSubRequest = Request::create('/');
|
$expectedSubRequest = Request::create('/');
|
||||||
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
||||||
$expectedSubRequest->server->set('REMOTE_ADDR', '1.1.1.1');
|
$expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
|
||||||
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
|
||||||
|
|
||||||
Request::setTrustedProxies(array('1.1.1.1/24'), -1);
|
Request::setTrustedProxies(array('1.1.1.1/24'), -1);
|
||||||
|
|
||||||
|
@ -1338,20 +1338,27 @@ class HttpCacheTest extends HttpCacheTestCase
|
|||||||
$this->setNextResponse();
|
$this->setNextResponse();
|
||||||
$this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
|
$this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
|
||||||
|
|
||||||
$this->assertEquals('127.0.0.1', $this->kernel->getBackendRequest()->server->get('REMOTE_ADDR'));
|
$this->kernel->assert(function ($backendRequest) {
|
||||||
|
$this->assertSame('127.0.0.1', $backendRequest->server->get('REMOTE_ADDR'));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getTrustedProxyData
|
* @dataProvider getTrustedProxyData
|
||||||
*/
|
*/
|
||||||
public function testHttpCacheIsSetAsATrustedProxy(array $existing, array $expected)
|
public function testHttpCacheIsSetAsATrustedProxy(array $existing)
|
||||||
{
|
{
|
||||||
Request::setTrustedProxies($existing, Request::HEADER_X_FORWARDED_ALL);
|
Request::setTrustedProxies($existing, Request::HEADER_X_FORWARDED_ALL);
|
||||||
|
|
||||||
$this->setNextResponse();
|
$this->setNextResponse();
|
||||||
$this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
|
$this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
|
||||||
|
$this->assertSame($existing, Request::getTrustedProxies());
|
||||||
|
|
||||||
$this->assertEquals($expected, Request::getTrustedProxies());
|
$existing = array_unique(array_merge($existing, array('127.0.0.1')));
|
||||||
|
$this->kernel->assert(function ($backendRequest) use ($existing) {
|
||||||
|
$this->assertSame($existing, Request::getTrustedProxies());
|
||||||
|
$this->assertsame('10.0.0.1', $backendRequest->getClientIp());
|
||||||
|
});
|
||||||
|
|
||||||
Request::setTrustedProxies(array(), -1);
|
Request::setTrustedProxies(array(), -1);
|
||||||
}
|
}
|
||||||
@ -1359,45 +1366,41 @@ class HttpCacheTest extends HttpCacheTestCase
|
|||||||
public function getTrustedProxyData()
|
public function getTrustedProxyData()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array(array(), array('127.0.0.1')),
|
array(array()),
|
||||||
array(array('10.0.0.2'), array('10.0.0.2', '127.0.0.1')),
|
array(array('10.0.0.2')),
|
||||||
array(array('10.0.0.2', '127.0.0.1'), array('10.0.0.2', '127.0.0.1')),
|
array(array('10.0.0.2', '127.0.0.1')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getXForwardedForData
|
* @dataProvider getForwardedData
|
||||||
*/
|
*/
|
||||||
public function testXForwarderForHeaderForForwardedRequests($xForwardedFor, $expected)
|
public function testForwarderHeaderForForwardedRequests($forwarded, $expected)
|
||||||
{
|
{
|
||||||
$this->setNextResponse();
|
$this->setNextResponse();
|
||||||
$server = array('REMOTE_ADDR' => '10.0.0.1');
|
$server = array('REMOTE_ADDR' => '10.0.0.1');
|
||||||
if (false !== $xForwardedFor) {
|
if (null !== $forwarded) {
|
||||||
$server['HTTP_X_FORWARDED_FOR'] = $xForwardedFor;
|
Request::setTrustedProxies($server, -1);
|
||||||
|
$server['HTTP_FORWARDED'] = $forwarded;
|
||||||
}
|
}
|
||||||
$this->request('GET', '/', $server);
|
$this->request('GET', '/', $server);
|
||||||
|
|
||||||
$this->assertEquals($expected, $this->kernel->getBackendRequest()->headers->get('X-Forwarded-For'));
|
$this->kernel->assert(function ($backendRequest) use ($expected) {
|
||||||
|
$this->assertSame($expected, $backendRequest->headers->get('Forwarded'));
|
||||||
|
});
|
||||||
|
|
||||||
|
Request::setTrustedProxies(array(), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getXForwardedForData()
|
public function getForwardedData()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array(false, '10.0.0.1'),
|
array(null, 'for="10.0.0.1";host="localhost";proto=http'),
|
||||||
array('10.0.0.2', '10.0.0.2, 10.0.0.1'),
|
array('for=10.0.0.2', 'for="10.0.0.2";host="localhost";proto=http, for="10.0.0.1"'),
|
||||||
array('10.0.0.2, 10.0.0.3', '10.0.0.2, 10.0.0.3, 10.0.0.1'),
|
array('for=10.0.0.2, for=10.0.0.3', 'for="10.0.0.2";host="localhost";proto=http, for="10.0.0.3", for="10.0.0.1"'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testXForwarderForHeaderForPassRequests()
|
|
||||||
{
|
|
||||||
$this->setNextResponse();
|
|
||||||
$server = array('REMOTE_ADDR' => '10.0.0.1');
|
|
||||||
$this->request('POST', '/', $server);
|
|
||||||
|
|
||||||
$this->assertEquals('10.0.0.1', $this->kernel->getBackendRequest()->headers->get('X-Forwarded-For'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponses()
|
public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponses()
|
||||||
{
|
{
|
||||||
$time = \DateTime::createFromFormat('U', time());
|
$time = \DateTime::createFromFormat('U', time());
|
||||||
|
@ -0,0 +1,153 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\HttpKernel\Tests\HttpCache;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\HttpCache\SubRequestHandler;
|
||||||
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
|
|
||||||
|
class SubRequestHandlerTest extends TestCase
|
||||||
|
{
|
||||||
|
private static $globalState;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
self::$globalState = $this->getGlobalState();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
Request::setTrustedProxies(self::$globalState[0], self::$globalState[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTrustedHeadersAreKept()
|
||||||
|
{
|
||||||
|
Request::setTrustedProxies(array('10.0.0.1'), -1);
|
||||||
|
$globalState = $this->getGlobalState();
|
||||||
|
|
||||||
|
$request = Request::create('/');
|
||||||
|
$request->server->set('REMOTE_ADDR', '10.0.0.1');
|
||||||
|
$request->headers->set('X-Forwarded-For', '10.0.0.2');
|
||||||
|
$request->headers->set('X-Forwarded-Host', 'Good');
|
||||||
|
$request->headers->set('X-Forwarded-Port', '1234');
|
||||||
|
$request->headers->set('X-Forwarded-Proto', 'https');
|
||||||
|
|
||||||
|
$kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
|
||||||
|
$this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
|
||||||
|
$this->assertSame('10.0.0.2', $request->getClientIp());
|
||||||
|
$this->assertSame('Good', $request->headers->get('X-Forwarded-Host'));
|
||||||
|
$this->assertSame('1234', $request->headers->get('X-Forwarded-Port'));
|
||||||
|
$this->assertSame('https', $request->headers->get('X-Forwarded-Proto'));
|
||||||
|
});
|
||||||
|
|
||||||
|
SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true);
|
||||||
|
|
||||||
|
$this->assertSame($globalState, $this->getGlobalState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUntrustedHeadersAreRemoved()
|
||||||
|
{
|
||||||
|
$request = Request::create('/');
|
||||||
|
$request->server->set('REMOTE_ADDR', '10.0.0.1');
|
||||||
|
$request->headers->set('X-Forwarded-For', '10.0.0.2');
|
||||||
|
$request->headers->set('X-Forwarded-Host', 'Evil');
|
||||||
|
$request->headers->set('X-Forwarded-Port', '1234');
|
||||||
|
$request->headers->set('X-Forwarded-Proto', 'http');
|
||||||
|
$request->headers->set('Forwarded', 'Evil2');
|
||||||
|
|
||||||
|
$kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
|
||||||
|
$this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
|
||||||
|
$this->assertSame('10.0.0.1', $request->getClientIp());
|
||||||
|
$this->assertFalse($request->headers->has('X-Forwarded-Host'));
|
||||||
|
$this->assertFalse($request->headers->has('X-Forwarded-Port'));
|
||||||
|
$this->assertFalse($request->headers->has('X-Forwarded-Proto'));
|
||||||
|
$this->assertSame('for="10.0.0.1";host="localhost";proto=http', $request->headers->get('Forwarded'));
|
||||||
|
});
|
||||||
|
|
||||||
|
SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true);
|
||||||
|
|
||||||
|
$this->assertSame(self::$globalState, $this->getGlobalState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTrustedForwardedHeader()
|
||||||
|
{
|
||||||
|
Request::setTrustedProxies(array('10.0.0.1'), -1);
|
||||||
|
$globalState = $this->getGlobalState();
|
||||||
|
|
||||||
|
$request = Request::create('/');
|
||||||
|
$request->server->set('REMOTE_ADDR', '10.0.0.1');
|
||||||
|
$request->headers->set('Forwarded', 'for="10.0.0.2";host="foo.bar:1234";proto=https');
|
||||||
|
|
||||||
|
$kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
|
||||||
|
$this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
|
||||||
|
$this->assertSame('10.0.0.2', $request->getClientIp());
|
||||||
|
$this->assertSame('foo.bar:1234', $request->getHttpHost());
|
||||||
|
$this->assertSame('https', $request->getScheme());
|
||||||
|
$this->assertSame(1234, $request->getPort());
|
||||||
|
});
|
||||||
|
|
||||||
|
SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true);
|
||||||
|
|
||||||
|
$this->assertSame($globalState, $this->getGlobalState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTrustedXForwardedForHeader()
|
||||||
|
{
|
||||||
|
Request::setTrustedProxies(array('10.0.0.1'), -1);
|
||||||
|
$globalState = $this->getGlobalState();
|
||||||
|
|
||||||
|
$request = Request::create('/');
|
||||||
|
$request->server->set('REMOTE_ADDR', '10.0.0.1');
|
||||||
|
$request->headers->set('X-Forwarded-For', '10.0.0.2');
|
||||||
|
$request->headers->set('X-Forwarded-Host', 'foo.bar');
|
||||||
|
$request->headers->set('X-Forwarded-Proto', 'https');
|
||||||
|
|
||||||
|
$kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) {
|
||||||
|
$this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR'));
|
||||||
|
$this->assertSame('10.0.0.2', $request->getClientIp());
|
||||||
|
$this->assertSame('foo.bar', $request->getHttpHost());
|
||||||
|
$this->assertSame('https', $request->getScheme());
|
||||||
|
});
|
||||||
|
|
||||||
|
SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true);
|
||||||
|
|
||||||
|
$this->assertSame($globalState, $this->getGlobalState());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getGlobalState()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
Request::getTrustedProxies(),
|
||||||
|
Request::getTrustedHeaderSet(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSubRequestHandlerKernel implements HttpKernelInterface
|
||||||
|
{
|
||||||
|
private $assertCallback;
|
||||||
|
|
||||||
|
public function __construct(\Closure $assertCallback)
|
||||||
|
{
|
||||||
|
$this->assertCallback = $assertCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
|
||||||
|
{
|
||||||
|
$assertCallback = $this->assertCallback;
|
||||||
|
$assertCallback($request, $type, $catch);
|
||||||
|
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
}
|
@ -39,15 +39,25 @@ class TestHttpKernel extends HttpKernel implements ControllerResolverInterface,
|
|||||||
parent::__construct(new EventDispatcher(), $this, null, $this);
|
parent::__construct(new EventDispatcher(), $this, null, $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBackendRequest()
|
public function assert(\Closure $callback)
|
||||||
{
|
{
|
||||||
return $this->backendRequest;
|
$trustedConfig = array(Request::getTrustedProxies(), Request::getTrustedHeaderSet());
|
||||||
|
|
||||||
|
list($trustedProxies, $trustedHeaderSet, $backendRequest) = $this->backendRequest;
|
||||||
|
Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$callback($backendRequest);
|
||||||
|
} finally {
|
||||||
|
list($trustedProxies, $trustedHeaderSet) = $trustedConfig;
|
||||||
|
Request::setTrustedProxies($trustedProxies, $trustedHeaderSet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = false)
|
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = false)
|
||||||
{
|
{
|
||||||
$this->catch = $catch;
|
$this->catch = $catch;
|
||||||
$this->backendRequest = $request;
|
$this->backendRequest = array(Request::getTrustedProxies(), Request::getTrustedHeaderSet(), $request);
|
||||||
|
|
||||||
return parent::handle($request, $type, $catch);
|
return parent::handle($request, $type, $catch);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user