Merge remote branch 'igorw/ipv6'
* igorw/ipv6: [HttpFoundation] minor optimization minor adjustments suggested by vicb [HttpFoundation] IPv6 support for RequestMatcher [HttpFoundation] refactor RequestMatcherTest to use dataProvider [Validator] use full iPv6 regex [Validator] add IPv6 support to UrlValidator [HttpFoundation] add IPv6 support to Request [HttpFoundation] test Request::create with an IP as host name [HttpFoundation] refactor Request::getClientIp test
This commit is contained in:
commit
889c422d6e
@ -543,9 +543,9 @@ class Request
|
||||
}
|
||||
|
||||
// Remove port number from host
|
||||
$elements = explode(':', $host);
|
||||
$host = preg_replace('/:\d+$/', '', $host);
|
||||
|
||||
return trim($elements[0]);
|
||||
return trim($host);
|
||||
}
|
||||
|
||||
public function setMethod($method)
|
||||
|
@ -121,6 +121,16 @@ class RequestMatcher implements RequestMatcherInterface
|
||||
}
|
||||
|
||||
protected function checkIp($ip)
|
||||
{
|
||||
// IPv6 address
|
||||
if (false !== strpos($ip, ':')) {
|
||||
return $this->checkIp6($ip);
|
||||
} else {
|
||||
return $this->checkIp4($ip);
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkIp4($ip)
|
||||
{
|
||||
if (false !== strpos($this->ip, '/')) {
|
||||
list($address, $netmask) = explode('/', $this->ip);
|
||||
@ -135,4 +145,27 @@ class RequestMatcher implements RequestMatcherInterface
|
||||
|
||||
return 0 === substr_compare(sprintf('%032b', ip2long($ip)), sprintf('%032b', ip2long($address)), 0, $netmask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author David Soria Parra <dsp at php dot net>
|
||||
* @see https://github.com/dsp/v6tools
|
||||
*/
|
||||
protected function checkIp6($ip)
|
||||
{
|
||||
list($address, $netmask) = explode('/', $this->ip);
|
||||
|
||||
$bytes_addr = unpack("n*", inet_pton($address));
|
||||
$bytes_test = unpack("n*", inet_pton($ip));
|
||||
|
||||
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; $i++) {
|
||||
$left = $netmask - 16 * ($i-1);
|
||||
$left = ($left <= 16) ?: 16;
|
||||
$mask = ~(0xffff >> $left) & 0xffff;
|
||||
if (($bytes_addr[$i] & $mask) != ($bytes_test[$i] & $mask)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,10 @@ class UrlValidator extends ConstraintValidator
|
||||
([a-z0-9-]+\.)+[a-z]{2,6} # a domain name
|
||||
| # or
|
||||
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # a IP address
|
||||
| # or
|
||||
\[
|
||||
(?:(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){6})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:::(?:(?:(?:[0-9a-f]{1,4})):){5})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){4})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,1}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){3})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,2}(?:(?:[0-9a-f]{1,4})))?::(?:(?:(?:[0-9a-f]{1,4})):){2})(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,3}(?:(?:[0-9a-f]{1,4})))?::(?:(?:[0-9a-f]{1,4})):)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,4}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:(?:(?:(?:[0-9a-f]{1,4})):(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9]))\.){3}(?:(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])))))))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,5}(?:(?:[0-9a-f]{1,4})))?::)(?:(?:[0-9a-f]{1,4})))|(?:(?:(?:(?:(?:(?:[0-9a-f]{1,4})):){0,6}(?:(?:[0-9a-f]{1,4})))?::))))
|
||||
\] # a IPv6 address
|
||||
)
|
||||
(:[0-9]+)? # a port (optional)
|
||||
(/?|/\S+) # a /, nothing or a / with something
|
||||
|
@ -16,19 +16,28 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class RequestMatcherTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testIp()
|
||||
/**
|
||||
* @dataProvider testIpProvider
|
||||
*/
|
||||
public function testIp($matches, $remoteAddr, $cidr)
|
||||
{
|
||||
$request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => $remoteAddr));
|
||||
|
||||
$matcher = new RequestMatcher();
|
||||
$matcher->matchIp($cidr);
|
||||
|
||||
$matcher->matchIp('192.168.1.1/1');
|
||||
$request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => '192.168.1.1'));
|
||||
$this->assertTrue($matcher->matches($request));
|
||||
$this->assertEquals($matches, $matcher->matches($request));
|
||||
}
|
||||
|
||||
$matcher->matchIp('192.168.1.0/24');
|
||||
$this->assertTrue($matcher->matches($request));
|
||||
|
||||
$matcher->matchIp('1.2.3.4/1');
|
||||
$this->assertFalse($matcher->matches($request));
|
||||
public function testIpProvider()
|
||||
{
|
||||
return array(
|
||||
array(true, '192.168.1.1', '192.168.1.1/1'),
|
||||
array(true, '192.168.1.1', '192.168.1.0/24'),
|
||||
array(false, '192.168.1.1', '1.2.3.4/1'),
|
||||
array(true, '2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'),
|
||||
array(false, '2a00:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testMethod()
|
||||
|
@ -81,6 +81,22 @@ class RequestTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(90, $request->getPort());
|
||||
$this->assertTrue($request->isSecure());
|
||||
|
||||
$request = Request::create('https://127.0.0.1:90/foo');
|
||||
$this->assertEquals('https://127.0.0.1:90/foo', $request->getUri());
|
||||
$this->assertEquals('/foo', $request->getPathInfo());
|
||||
$this->assertEquals('127.0.0.1', $request->getHost());
|
||||
$this->assertEquals('127.0.0.1:90', $request->getHttpHost());
|
||||
$this->assertEquals(90, $request->getPort());
|
||||
$this->assertTrue($request->isSecure());
|
||||
|
||||
$request = Request::create('https://[::1]:90/foo');
|
||||
$this->assertEquals('https://[::1]:90/foo', $request->getUri());
|
||||
$this->assertEquals('/foo', $request->getPathInfo());
|
||||
$this->assertEquals('[::1]', $request->getHost());
|
||||
$this->assertEquals('[::1]:90', $request->getHttpHost());
|
||||
$this->assertEquals(90, $request->getPort());
|
||||
$this->assertTrue($request->isSecure());
|
||||
|
||||
$json = '{"jsonrpc":"2.0","method":"echo","id":7,"params":["Hello World"]}';
|
||||
$request = Request::create('http://example.com/jsonrpc', 'POST', array(), array(), array(), array(), $json);
|
||||
$this->assertEquals($json, $request->getContent());
|
||||
@ -434,21 +450,38 @@ class RequestTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST');
|
||||
}
|
||||
|
||||
public function testGetClientIp()
|
||||
/**
|
||||
* @dataProvider testGetClientIpProvider
|
||||
*/
|
||||
public function testGetClientIp($expected, $proxy, $remoteAddr, $httpClientIp, $httpForwardedFor)
|
||||
{
|
||||
$request = new Request;
|
||||
$this->assertEquals('', $request->getClientIp());
|
||||
$this->assertEquals('', $request->getClientIp(true));
|
||||
$request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '88.88.88.88'));
|
||||
$this->assertEquals('88.88.88.88', $request->getClientIp());
|
||||
$request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '127.0.0.1', 'HTTP_CLIENT_IP' => '88.88.88.88'));
|
||||
$this->assertEquals('127.0.0.1', $request->getClientIp());
|
||||
$request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '127.0.0.1', 'HTTP_CLIENT_IP' => '88.88.88.88'));
|
||||
$this->assertEquals('88.88.88.88', $request->getClientIp(true));
|
||||
$request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '127.0.0.1', 'HTTP_X_FORWARDED_FOR' => '88.88.88.88'));
|
||||
$this->assertEquals('127.0.0.1', $request->getClientIp());
|
||||
$request->initialize(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => '127.0.0.1', 'HTTP_X_FORWARDED_FOR' => '88.88.88.88'));
|
||||
$this->assertEquals('88.88.88.88', $request->getClientIp(true));
|
||||
|
||||
$server = array('REMOTE_ADDR' => $remoteAddr);
|
||||
if (!is_null($httpClientIp)) {
|
||||
$server['HTTP_CLIENT_IP'] = $httpClientIp;
|
||||
}
|
||||
if (!is_null($httpForwardedFor)) {
|
||||
$server['HTTP_X_FORWARDED_FOR'] = $httpForwardedFor;
|
||||
}
|
||||
|
||||
$request->initialize(array(), array(), array(), array(), array(), $server);
|
||||
$this->assertEquals($expected, $request->getClientIp($proxy));
|
||||
}
|
||||
|
||||
public function testGetClientIpProvider()
|
||||
{
|
||||
return array(
|
||||
array('88.88.88.88', false, '88.88.88.88', null, null),
|
||||
array('127.0.0.1', false, '127.0.0.1', '88.88.88.88', null),
|
||||
array('88.88.88.88', true, '127.0.0.1', '88.88.88.88', null),
|
||||
array('127.0.0.1', false, '127.0.0.1', null, '88.88.88.88'),
|
||||
array('88.88.88.88', true, '127.0.0.1', null, '88.88.88.88'),
|
||||
array('::1', false, '::1', null, null),
|
||||
array('2620:0:1cfe:face:b00c::3', true, '::1', '2620:0:1cfe:face:b00c::3', null),
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetContentWorksTwiceInDefaultMode()
|
||||
|
@ -57,6 +57,8 @@ class UrlValidatorTest extends \PHPUnit_Framework_TestCase
|
||||
array('http://www.symfony.com/'),
|
||||
array('http://127.0.0.1/'),
|
||||
array('http://127.0.0.1:80/'),
|
||||
array('http://[::1]/'),
|
||||
array('http://[::1]:80/'),
|
||||
);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user