From 5a37f84713e3bc36b3400e3d85043b176bfdf6b3 Mon Sep 17 00:00:00 2001 From: Chris Wilkinson Date: Tue, 31 Jan 2017 08:56:27 +0000 Subject: [PATCH] [HttpFoundation] Find the original request protocol version --- .../Component/HttpFoundation/Request.php | 24 +++++++++++++++ .../HttpFoundation/Tests/RequestTest.php | 30 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 6fd0707b059f..6cfee8f4af68 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1581,6 +1581,30 @@ public function isMethodCacheable() return in_array($this->getMethod(), array('GET', 'HEAD')); } + /** + * Returns the protocol version. + * + * If the application is behind a proxy, the protocol version used in the + * requests between the client and the proxy and between the proxy and the + * server might be different. This returns the former (from the "Via" header) + * if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns + * the latter (from the "SERVER_PROTOCOL" server parameter). + * + * @return string + */ + public function getProtocolVersion() + { + if ($this->isFromTrustedProxy()) { + preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via'), $matches); + + if ($matches) { + return 'HTTP/'.$matches[2]; + } + } + + return $this->server->get('SERVER_PROTOCOL'); + } + /** * Returns the request body content. * diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index b36fbb7e9625..54c95c431545 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -2188,6 +2188,36 @@ public function testGetTrustedHeaderName() Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT'); Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO'); } + + /** + * @dataProvider protocolVersionProvider + */ + public function testProtocolVersion($serverProtocol, $trustedProxy, $via, $expected) + { + if ($trustedProxy) { + Request::setTrustedProxies(array('1.1.1.1')); + } + + $request = new Request(); + $request->server->set('SERVER_PROTOCOL', $serverProtocol); + $request->server->set('REMOTE_ADDR', '1.1.1.1'); + $request->headers->set('Via', $via); + + $this->assertSame($expected, $request->getProtocolVersion()); + } + + public function protocolVersionProvider() + { + return array( + 'untrusted without via' => array('HTTP/2.0', false, '', 'HTTP/2.0'), + 'untrusted with via' => array('HTTP/2.0', false, '1.0 fred, 1.1 nowhere.com (Apache/1.1)', 'HTTP/2.0'), + 'trusted without via' => array('HTTP/2.0', true, '', 'HTTP/2.0'), + 'trusted with via' => array('HTTP/2.0', true, '1.0 fred, 1.1 nowhere.com (Apache/1.1)', 'HTTP/1.0'), + 'trusted with via and protocol name' => array('HTTP/2.0', true, 'HTTP/1.0 fred, HTTP/1.1 nowhere.com (Apache/1.1)', 'HTTP/1.0'), + 'trusted with broken via' => array('HTTP/2.0', true, 'HTTP/1^0 foo', 'HTTP/2.0'), + 'trusted with partially-broken via' => array('HTTP/2.0', true, '1.0 fred, foo', 'HTTP/1.0'), + ); + } } class RequestContentProxy extends Request