浏览代码

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
Fabien Potencier 14 年之前
父节点
当前提交
889c422d6e

+ 2 - 2
src/Symfony/Component/HttpFoundation/Request.php

@@ -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)

+ 33 - 0
src/Symfony/Component/HttpFoundation/RequestMatcher.php

@@ -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;
+    }
 }

文件差异内容过多而无法显示
+ 7 - 3
src/Symfony/Component/Validator/Constraints/UrlValidator.php


+ 18 - 9
tests/Symfony/Tests/Component/HttpFoundation/RequestMatcherTest.php

@@ -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)
     {
-        $matcher = new RequestMatcher();
+        $request = Request::create('', 'get', array(), array(), array(), array('REMOTE_ADDR' => $remoteAddr));
 
-        $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));
+        $matcher = new RequestMatcher();
+        $matcher->matchIp($cidr);
 
-        $matcher->matchIp('192.168.1.0/24');
-        $this->assertTrue($matcher->matches($request));
+        $this->assertEquals($matches, $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()

+ 44 - 11
tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php

@@ -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()

+ 2 - 0
tests/Symfony/Tests/Component/Validator/Constraints/UrlValidatorTest.php

@@ -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/'),
         );
     }