From 8ad32f0ef56b13fb7930fea9dcface331f6ded22 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 10 Oct 2017 10:04:23 +0200 Subject: [PATCH 1/6] never match invalid IP addresses --- .../Component/HttpFoundation/IpUtils.php | 4 ++++ .../HttpFoundation/Tests/IpUtilsTest.php | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Symfony/Component/HttpFoundation/IpUtils.php b/src/Symfony/Component/HttpFoundation/IpUtils.php index dc6d3ec818..3bb33140f5 100644 --- a/src/Symfony/Component/HttpFoundation/IpUtils.php +++ b/src/Symfony/Component/HttpFoundation/IpUtils.php @@ -87,6 +87,10 @@ class IpUtils $netmask = 32; } + if (false === ip2long($address)) { + return self::$checkedIps[$cacheKey] = false; + } + return self::$checkedIps[$cacheKey] = 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php b/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php index 297ee3d8d3..54cbb5c206 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php @@ -82,4 +82,21 @@ class IpUtilsTest extends TestCase IpUtils::checkIp('2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'); } + + /** + * @dataProvider invalidIpAddressData + */ + public function testInvalidIpAddressesDoNotMatch($requestIp, $proxyIp) + { + $this->assertFalse(IpUtils::checkIp4($requestIp, $proxyIp)); + } + + public function invalidIpAddressData() + { + return array( + 'invalid proxy wildcard' => array('192.168.20.13', '*'), + 'invalid proxy missing netmask' => array('192.168.20.13', '0.0.0.0'), + 'invalid request IP with invalid proxy wildcard' => array('0.0.0.0', '*'), + ); + } } From c6ed0e4f86a0cda30f906237e7032ce978e40b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 12 Oct 2017 09:08:46 +0200 Subject: [PATCH 2/6] [Translation] minor: remove unused variable in test --- src/Symfony/Component/Translation/Tests/TranslatorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index 960d8f4d3c..6047cf7c3c 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -25,7 +25,7 @@ class TranslatorTest extends TestCase */ public function testConstructorInvalidLocale($locale) { - $translator = new Translator($locale, new MessageSelector()); + new Translator($locale, new MessageSelector()); } /** From 345f2fc60e54f2429b6b862a9336edaaadd3a184 Mon Sep 17 00:00:00 2001 From: Artur Eshenbrener Date: Thu, 12 Oct 2017 14:28:41 +0300 Subject: [PATCH 3/6] [DI] Fix possible incorrect php-code when dumped strings contains newlines --- .../Component/DependencyInjection/Dumper/PhpDumper.php | 7 +++++++ .../DependencyInjection/Tests/Dumper/PhpDumperTest.php | 1 + .../DependencyInjection/Tests/Fixtures/php/services10.php | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 5a0f89c8b4..01d9ca7192 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -1574,6 +1574,13 @@ EOF; return $dirname; } + if (is_string($value) && false !== strpos($value, "\n")) { + $cleanParts = explode("\n", $value); + $cleanParts = array_map(function ($part) { return var_export($part, true); }, $cleanParts); + + return implode('."\n".', $cleanParts); + } + return var_export($value, true); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index e238649361..57f8a47a90 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -55,6 +55,7 @@ class PhpDumperTest extends TestCase 'optimize concatenation with empty string' => 'string1%empty_value%string2', 'optimize concatenation from the start' => '%empty_value%start', 'optimize concatenation at the end' => 'end%empty_value%', + 'new line' => "string with \nnew line", )); $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10.php index a674eae8b4..6538f0ae53 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10.php @@ -56,7 +56,7 @@ class ProjectServiceContainer extends Container */ protected function getTestService() { - return $this->services['test'] = new \stdClass(array('only dot' => '.', 'concatenation as value' => '.\'\'.', 'concatenation from the start value' => '\'\'.', '.' => 'dot as a key', '.\'\'.' => 'concatenation as a key', '\'\'.' => 'concatenation from the start key', 'optimize concatenation' => 'string1-string2', 'optimize concatenation with empty string' => 'string1string2', 'optimize concatenation from the start' => 'start', 'optimize concatenation at the end' => 'end')); + return $this->services['test'] = new \stdClass(array('only dot' => '.', 'concatenation as value' => '.\'\'.', 'concatenation from the start value' => '\'\'.', '.' => 'dot as a key', '.\'\'.' => 'concatenation as a key', '\'\'.' => 'concatenation from the start key', 'optimize concatenation' => 'string1-string2', 'optimize concatenation with empty string' => 'string1string2', 'optimize concatenation from the start' => 'start', 'optimize concatenation at the end' => 'end', 'new line' => 'string with '."\n".'new line')); } /** From 9efb76572ae71d3bee17efeb39f0451760bf31db Mon Sep 17 00:00:00 2001 From: loru88 Date: Wed, 11 Oct 2017 16:39:25 +0200 Subject: [PATCH 4/6] [Validator] added magic method __isset() to File Constraint class --- src/Symfony/Component/Validator/Constraints/File.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Symfony/Component/Validator/Constraints/File.php b/src/Symfony/Component/Validator/Constraints/File.php index 7756978b35..54e7351562 100644 --- a/src/Symfony/Component/Validator/Constraints/File.php +++ b/src/Symfony/Component/Validator/Constraints/File.php @@ -88,6 +88,15 @@ class File extends Constraint return parent::__get($option); } + public function __isset($option) + { + if ('maxSize' === $option) { + return true; + } + + return parent::__isset($option); + } + private function normalizeBinaryFormat($maxSize) { $sizeInt = (int) $maxSize; From ff379efb59de25bcdb88225f7389013fecf54b17 Mon Sep 17 00:00:00 2001 From: Paul Mitchum Date: Fri, 2 Jun 2017 12:44:10 -0700 Subject: [PATCH 5/6] [Bridge\PhpUnit] Handle deprecations triggered in separate processes --- .../PhpUnit/DeprecationErrorHandler.php | 14 +++++ .../Legacy/SymfonyTestsListenerTrait.php | 61 ++++++++++++++----- .../PhpUnit/Tests/ProcessIsolationTest.php | 23 +++++++ src/Symfony/Bridge/PhpUnit/bootstrap.php | 4 ++ 4 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index 0f54a52bb8..a7dbc08e0c 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -238,6 +238,20 @@ class DeprecationErrorHandler } } + public static function collectDeprecations($outputFile) + { + $deprecations = array(); + $previousErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) use (&$deprecations, &$previousErrorHandler) { + if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) { + return $previousErrorHandler ? $previousErrorHandler($type, $msg, $file, $line, $context) : false; + } + $deprecations[] = array(error_reporting(), $msg); + }); + register_shutdown_function(function () use ($outputFile, &$deprecations) { + file_put_contents($outputFile, serialize($deprecations)); + }); + } + private static function hasColorSupport() { if ('\\' === DIRECTORY_SEPARATOR) { diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index b561c8f2f5..166c44a3f8 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -39,6 +39,7 @@ class SymfonyTestsListenerTrait private $testsWithWarnings; private $reportUselessTests; private $error; + private $runsInSeparateProcess = false; /** * @param array $mockedNamespaces List of namespaces, indexed by mocked features (time-sensitive or dns-sensitive) @@ -183,6 +184,12 @@ class SymfonyTestsListenerTrait $this->reportUselessTests = $test->getTestResultObject()->isStrictAboutTestsThatDoNotTestAnything(); } + // This event is triggered before the test is re-run in isolation + if ($this->willBeIsolated($test)) { + $this->runsInSeparateProcess = tempnam(sys_get_temp_dir(), 'deprec'); + putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$this->runsInSeparateProcess); + } + if (class_exists('PHPUnit_Util_Blacklist', false)) { $Test = 'PHPUnit_Util_Test'; $AssertionFailedError = 'PHPUnit_Framework_AssertionFailedError'; @@ -192,12 +199,14 @@ class SymfonyTestsListenerTrait } $groups = $Test::getGroups(get_class($test), $test->getName(false)); - if (in_array('time-sensitive', $groups, true)) { - ClockMock::register(get_class($test)); - ClockMock::withClockMock(true); - } - if (in_array('dns-sensitive', $groups, true)) { - DnsMock::register(get_class($test)); + if (!$this->runsInSeparateProcess) { + if (in_array('time-sensitive', $groups, true)) { + ClockMock::register(get_class($test)); + ClockMock::withClockMock(true); + } + if (in_array('dns-sensitive', $groups, true)) { + DnsMock::register(get_class($test)); + } } $annotations = $Test::parseTestMethodAnnotations(get_class($test), $test->getName(false)); @@ -245,17 +254,22 @@ class SymfonyTestsListenerTrait $this->reportUselessTests = null; } - $errored = false; - - if (null !== $this->error) { - if ($BaseTestRunner::STATUS_PASSED === $test->getStatus()) { - $test->getTestResultObject()->addError($test, $this->error, 0); - $errored = true; - } - + if ($errored = null !== $this->error) { + $test->getTestResultObject()->addError($test, $this->error, 0); $this->error = null; } + if ($this->runsInSeparateProcess) { + foreach (unserialize(file_get_contents($this->runsInSeparateProcess)) as $deprecation) { + if ($deprecation[0]) { + trigger_error($deprecation[1], E_USER_DEPRECATED); + } else { + @trigger_error($deprecation[1], E_USER_DEPRECATED); + } + } + $this->runsInSeparateProcess = false; + } + if ($this->expectedDeprecations) { if (!in_array($test->getStatus(), array($BaseTestRunner::STATUS_SKIPPED, $BaseTestRunner::STATUS_INCOMPLETE), true)) { $test->addToAssertionCount(count($this->expectedDeprecations)); @@ -277,7 +291,7 @@ class SymfonyTestsListenerTrait $this->expectedDeprecations = $this->gatheredDeprecations = array(); $this->previousErrorHandler = null; } - if (-2 < $this->state && ($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) { + if (!$this->runsInSeparateProcess && -2 < $this->state && ($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) { if (in_array('time-sensitive', $groups, true)) { ClockMock::withClockMock(false); } @@ -315,4 +329,21 @@ class SymfonyTestsListenerTrait } $this->gatheredDeprecations[] = $msg; } + + /** + * @param Test $test + * + * @return bool + */ + private function willBeIsolated($test) + { + if ($test->isInIsolation()) { + return false; + } + + $r = new \ReflectionProperty($test, 'runTestInSeparateProcess'); + $r->setAccessible(true); + + return $r->getValue($test); + } } diff --git a/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php new file mode 100644 index 0000000000..d8677097e5 --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php @@ -0,0 +1,23 @@ + Date: Fri, 13 Oct 2017 15:21:24 +0200 Subject: [PATCH 6/6] [BrowserKit] Handle deprecations triggered in insulated requests --- src/Symfony/Component/BrowserKit/Client.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index 2f2b08d818..fb7a254e2c 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -343,9 +343,23 @@ abstract class Client */ protected function doRequestInProcess($request) { + $deprecationsFile = tempnam(sys_get_temp_dir(), 'deprec'); + putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$deprecationsFile); $process = new PhpProcess($this->getScript($request), null, null); $process->run(); + if (file_exists($deprecationsFile)) { + $deprecations = file_get_contents($deprecationsFile); + unlink($deprecationsFile); + foreach ($deprecations ? unserialize($deprecations) : array() as $deprecation) { + if ($deprecation[0]) { + trigger_error($deprecation[1], E_USER_DEPRECATED); + } else { + @trigger_error($deprecation[1], E_USER_DEPRECATED); + } + } + } + if (!$process->isSuccessful() || !preg_match('/^O\:\d+\:/', $process->getOutput())) { throw new \RuntimeException(sprintf('OUTPUT: %s ERROR OUTPUT: %s', $process->getOutput(), $process->getErrorOutput())); }