Merge branch '4.2'

* 4.2:
  [HttpFoundation] fix tests
  [Routing] fix trailing slash matching with empty-matching trailing vars
  [Routing] fix matching trailing vars with defaults
  [Validator] fix LegacyTranslatorProxy
  call method with Translator component only
  bumped Symfony version to 4.2.8
  updated VERSION for 4.2.7
  updated CHANGELOG for 4.2.7
  bumped Symfony version to 3.4.27
  updated VERSION for 3.4.26
  updated CHANGELOG for 3.4.26
This commit is contained in:
Nicolas Grekas 2019-04-19 16:28:43 +02:00
commit 98929dc292
10 changed files with 84 additions and 11 deletions

View File

@ -7,6 +7,19 @@ in 4.2 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.2.0...v4.2.1
* 4.2.7 (2019-04-17)
* bug #31107 [Routing] fix trailing slash redirection with non-greedy trailing vars (nicolas-grekas)
* bug #31108 [FrameworkBundle] decorate the ValidatorBuilder's translator with LegacyTranslatorProxy (nicolas-grekas)
* bug #31121 [HttpKernel] Fix get session when the request stack is empty (yceruto)
* bug #31084 [HttpFoundation] Make MimeTypeExtensionGuesser case insensitive (vermeirentony)
* bug #31142 Revert "bug #30423 [Security] Rework firewall's access denied rule (dimabory)" (chalasr)
* security #cve-2019-10910 [DI] Check service IDs are valid (nicolas-grekas)
* security #cve-2019-10909 [FrameworkBundle][Form] Fix XSS issues in the form theme of the PHP templating engine (stof)
* security #cve-2019-10912 [Cache][PHPUnit Bridge] Prevent destructors with side-effects from being unserialized (nicolas-grekas)
* security #cve-2019-10911 [Security] Add a separator in the remember me cookie hash (pborreli)
* security #cve-2019-10913 [HttpFoundation] reject invalid method override (nicolas-grekas)
* 4.2.6 (2019-04-16)
* bug #31088 [DI] fix removing non-shared definition while inlining them (nicolas-grekas)

View File

@ -1,7 +1,7 @@
#!/usr/bin/env php
<?php
// Cache-Id: https://github.com/symfony/symfony/commit/aad0c58
// Cache-Id: https://github.com/symfony/phpunit-bridge/commit/32c5fa570117630dad45c21528b93d26bad02bc1
if (!file_exists(__DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit')) {
echo "Unable to find the `simple-phpunit` script in `vendor/symfony/phpunit-bridge/bin/`.\nPlease run `composer update` before running this command.\n";

View File

@ -107,6 +107,7 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\Translation\Command\XliffLintCommand as BaseXliffLintCommand;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\ConstraintValidatorInterface;
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
use Symfony\Component\Validator\ObjectInitializerInterface;
@ -1209,7 +1210,7 @@ class FrameworkExtension extends Extension
$validatorBuilder = $container->getDefinition('validator.builder');
if (class_exists(LegacyTranslatorProxy::class)) {
if (interface_exists(TranslatorInterface::class) && class_exists(LegacyTranslatorProxy::class)) {
$calls = $validatorBuilder->getMethodCalls();
$calls[1] = ['setTranslator', [new Definition(LegacyTranslatorProxy::class, [new Reference('translator')])]];
$validatorBuilder->setMethodCalls($calls);

View File

@ -53,6 +53,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Translation\DependencyInjection\TranslatorPass;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
use Symfony\Component\Validator\Util\LegacyTranslatorProxy;
@ -883,7 +884,7 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertSame('setConstraintValidatorFactory', $calls[0][0]);
$this->assertEquals([new Reference('validator.validator_factory')], $calls[0][1]);
$this->assertSame('setTranslator', $calls[1][0]);
if (class_exists(LegacyTranslatorProxy::class)) {
if (interface_exists(TranslatorInterface::class) && class_exists(LegacyTranslatorProxy::class)) {
$this->assertEquals([new Definition(LegacyTranslatorProxy::class, [new Reference('translator')])], $calls[1][1]);
} else {
$this->assertEquals([new Reference('translator')], $calls[1][1]);

View File

@ -1004,14 +1004,15 @@ class ResponseTest extends ResponseTestCase
$ianaHttpStatusCodes = new \DOMDocument();
libxml_set_streams_context(stream_context_create([
$context = stream_context_create([
'http' => [
'method' => 'GET',
'timeout' => 30,
'user_agent' => __METHOD__,
],
]));
]);
$ianaHttpStatusCodes->load('https://www.iana.org/assignments/http-status-codes/http-status-codes.xml');
$ianaHttpStatusCodes->loadXML(file_get_contents('https://www.iana.org/assignments/http-status-codes/http-status-codes.xml', false, $context));
if (!$ianaHttpStatusCodes->relaxNGValidate(__DIR__.'/schema/http-status-codes.rng')) {
self::fail('Invalid IANA\'s HTTP status code list.');
}

View File

@ -137,7 +137,7 @@ trait CompiledUrlMatcherTrait
$hasTrailingVar = $trimmedPathinfo !== $pathinfo && $hasTrailingVar;
if ($hasTrailingVar && ($hasTrailingSlash || '/' !== substr($matches[\count($vars)], -1)) && preg_match($regex, $this->matchHost ? $host.'.'.$trimmedPathinfo : $trimmedPathinfo, $n) && $m === (int) $n['MARK']) {
if ($hasTrailingVar && ($hasTrailingSlash || (null === $n = $matches[\count($vars)] ?? null) || '/' !== ($n[-1] ?? '/')) && preg_match($regex, $this->matchHost ? $host.'.'.$trimmedPathinfo : $trimmedPathinfo, $n) && $m === (int) $n['MARK']) {
if ($hasTrailingSlash) {
$matches = $n;
} else {

View File

@ -158,7 +158,7 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
$hasTrailingVar = $trimmedPathinfo !== $pathinfo && preg_match('#\{\w+\}/?$#', $route->getPath());
if ($hasTrailingVar && ($hasTrailingSlash || '/' !== substr($matches[(\count($matches) - 1) >> 1], -1)) && preg_match($regex, $trimmedPathinfo, $m)) {
if ($hasTrailingVar && ($hasTrailingSlash || (null === $m = $matches[\count($compiledRoute->getPathVariables())] ?? null) || '/' !== ($m[-1] ?? '/')) && preg_match($regex, $trimmedPathinfo, $m)) {
if ($hasTrailingSlash) {
$matches = $m;
} else {

View File

@ -198,6 +198,17 @@ class RedirectableUrlMatcherTest extends UrlMatcherTest
$this->assertEquals(['_route' => 'a', 'a' => '123'], $matcher->match('/123/'));
}
public function testTrailingRequirementWithDefault_A()
{
$coll = new RouteCollection();
$coll->add('a', new Route('/fr-fr/{a}', ['a' => 'aaa'], ['a' => '.+']));
$matcher = $this->getUrlMatcher($coll);
$matcher->expects($this->once())->method('redirect')->with('/fr-fr')->willReturn([]);
$this->assertEquals(['_route' => 'a', 'a' => 'aaa'], $matcher->match('/fr-fr/'));
}
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
return $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', [$routes, $context ?: new RequestContext()]);

View File

@ -777,6 +777,41 @@ class UrlMatcherTest extends TestCase
$this->assertEquals(['_route' => 'a', 'a' => 'foo/'], $matcher->match('/foo/'));
}
public function testTrailingRequirementWithDefault()
{
$coll = new RouteCollection();
$coll->add('a', new Route('/fr-fr/{a}', ['a' => 'aaa'], ['a' => '.+']));
$coll->add('b', new Route('/en-en/{b}', ['b' => 'bbb'], ['b' => '.*']));
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(['_route' => 'a', 'a' => 'aaa'], $matcher->match('/fr-fr'));
$this->assertEquals(['_route' => 'a', 'a' => 'AAA'], $matcher->match('/fr-fr/AAA'));
$this->assertEquals(['_route' => 'b', 'b' => 'bbb'], $matcher->match('/en-en'));
$this->assertEquals(['_route' => 'b', 'b' => 'BBB'], $matcher->match('/en-en/BBB'));
}
public function testTrailingRequirementWithDefault_A()
{
$coll = new RouteCollection();
$coll->add('a', new Route('/fr-fr/{a}', ['a' => 'aaa'], ['a' => '.+']));
$matcher = $this->getUrlMatcher($coll);
$this->expectException(ResourceNotFoundException::class);
$matcher->match('/fr-fr/');
}
public function testTrailingRequirementWithDefault_B()
{
$coll = new RouteCollection();
$coll->add('b', new Route('/en-en/{b}', ['b' => 'bbb'], ['b' => '.*']));
$matcher = $this->getUrlMatcher($coll);
$this->assertEquals(['_route' => 'b', 'b' => ''], $matcher->match('/en-en/'));
}
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
return new UrlMatcher($routes, $context ?: new RequestContext());

View File

@ -22,15 +22,26 @@ class LegacyTranslatorProxy implements LegacyTranslatorInterface, TranslatorInte
{
private $translator;
public function __construct(TranslatorInterface $translator)
/**
* @param LegacyTranslatorInterface|TranslatorInterface $translator
*/
public function __construct($translator)
{
if (!$translator instanceof LocaleAwareInterface) {
if ($translator instanceof LegacyTranslatorInterface) {
// no-op
} elseif (!$translator instanceof TranslatorInterface) {
throw new \InvalidArgumentException(sprintf('The translator passed to "%s()" must implement "%s" or "%s".', __METHOD__, TranslatorInterface::class, LegacyTranslatorInterface::class));
} elseif (!$translator instanceof LocaleAwareInterface) {
throw new \InvalidArgumentException(sprintf('The translator passed to "%s()" must implement "%s".', __METHOD__, LocaleAwareInterface::class));
}
$this->translator = $translator;
}
public function getTranslator(): TranslatorInterface
/**
* @return LegacyTranslatorInterface|TranslatorInterface
*/
public function getTranslator()
{
return $this->translator;
}