8000 Merge branch '5.4' into 6.0 · symfony/symfony@58c9a23 · GitHub
[go: up one dir, main page]

Skip to content

Commit 58c9a23

Browse files
committed
Merge branch '5.4' into 6.0
* 5.4: [FrameworkBundle] Allow to specify `null` for exception mapping configuration values Fix BinaryFileResponse content type detection logic [Notifier] [Expo] Throw exception on error-response from expo api Bump Symfony version to 5.4.14 Update VERSION for 5.4.13 Update CHANGELOG for 5.4.13 Bump Symfony version to 4.4.47 Update VERSION for 4.4.46 Update CONTRIBUTORS for 4.4.46 Update CHANGELOG for 4.4.46 [Security] Fix login url matching when app is not run with url rewriting or from a sub folder
2 parents c0d871b + 1d723cf commit 58c9a23

File tree

12 files changed

+256
-32
lines changed
  • yml
  • Component
  • 12 files changed

    +256
    -32
    lines changed

    CONTRIBUTORS.md

    Lines changed: 43 additions & 24 deletions
    Large diffs are not rendered by default.

    src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

    Lines changed: 7 additions & 3 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1198,15 +1198,19 @@ private function addExceptionsSection(ArrayNodeDefinition $rootNode)
    11981198
    ->scalarNode('log_level')
    11991199
    ->info('The level of log message. Null to let Symfony decide.')
    12001200
    ->validate()
    1201-
    ->ifTrue(function ($v) use ($logLevels) { return !\in_array($v, $logLevels); })
    1201+
    ->ifTrue(function ($v) use ($logLevels) { return null !== $v && !\in_array($v, $logLevels, true); })
    12021202
    ->thenInvalid(sprintf('The log level is not valid. Pick one among "%s".', implode('", "', $logLevels)))
    12031203
    ->end()
    12041204
    ->defaultNull()
    12051205
    ->end()
    12061206
    ->scalarNode('status_code')
    1207-
    ->info('The status code of the response. Null to let Symfony decide.')
    1207+
    ->info('The status code of the response. Null or 0 to let Symfony decide.')
    1208+
    ->beforeNormalization()
    1209+
    ->ifTrue(function ($v) { return 0 === $v; })
    1210+
    ->then(function ($v) { return null; })
    1211+
    ->end()
    12081212
    ->validate()
    1209-
    ->ifTrue(function ($v) { return $v < 100 || $v > 599; })
    1213+
    ->ifTrue(function ($v) { return null !== $v && ($v < 100 || $v > 599); })
    12101214
    ->thenInvalid('The status code is not valid. Pick a value between 100 and 599.')
    12111215
    ->end()
    12121216
    ->defaultNull()
    Lines changed: 15 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,12 +1,27 @@
    11
    <?php
    22

    33
    use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
    4+
    use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
    5+
    use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
    6+
    use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
    47

    58
    $container->loadFromExtension('framework', [
    69
    'exceptions' => [
    710
    BadRequestHttpException::class => [
    811
    'log_level' => 'info',
    912
    'status_code' => 422,
    1013
    ],
    14+
    NotFoundHttpException::class => [
    15+
    'log_level' => 'info',
    16+
    'status_code' => null,
    17+
    ],
    18+
    ConflictHttpException::class => [
    19+
    'log_level' => 'info',
    20+
    'status_code' => 0,
    21+
    ],
    22+
    ServiceUnavailableHttpException::class => [
    23+
    'log_level' => null,
    24+
    'status_code' => 500,
    25+
    ],
    1126
    ],
    1227
    ]);

    src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/exceptions.xml

    Lines changed: 3 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -8,6 +8,9 @@
    88
    <framework:config>
    99
    <framework:exceptions>
    1010
    <framework:exception name="Symfony\Component\HttpKernel\Exception\BadRequestHttpException" log-level="info" status-code="422" />
    11+
    <framework:exception name="Symfony\Component\HttpKernel\Exception\NotFoundHttpException" log-level="info" status-code="0" />
    12+
    <framework:exception name="Symfony\Component\HttpKernel\Exception\ConflictHttpException" log-level="info" status-code="0" />
    13+
    <framework:exception name="Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException" log-level="null" status-code="500" />
    1114
    </framework:exceptions>
    1215
    </framework:config>
    1316
    </container>

    src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/exceptions.yml

    Lines changed: 9 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -3,3 +3,12 @@ framework:
    33
    Symfony\Component\HttpKernel\Exception\BadRequestHttpException:
    44
    log_level: info
    55
    status_code: 422
    6+
    Symfony\Component\HttpKernel\Exception\NotFoundHttpException:
    7+
    log_level: info
    8+
    status_code: null
    9+
    Symfony\Component\HttpKernel\Exception\ConflictHttpException:
    10+
    log_level: info
    11+
    status_code: 0
    12+
    Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException:
    13+
    log_level: null
    14+
    status_code: 500

    src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

    Lines changed: 12 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -547,6 +547,18 @@ public function testExceptionsConfig()
    547547
    'log_level' => 'info',
    548548
    'status_code' => 422,
    549549
    ],
    550+
    \Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class => [
    551+
    'log_level' => 'info',
    552+
    'status_code' => null,
    553+
    ],
    554+
    \Symfony\Component\HttpKernel\Exception\ConflictHttpException::class => [
    555+
    'log_level' => 'info',
    556+
    'status_code' => null,
    557+
    ],
    558+
    \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException::class => [
    559+
    'log_level' => null,
    560+
    'status_code' => 500,
    561+
    ],
    550562
    ], $container->getDefinition('exception_listener')->getArgument(3));
    551563
    }
    552564

    src/Symfony/Component/HttpFoundation/BinaryFileResponse.php

    Lines changed: 4 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -182,9 +182,9 @@ public function setContentDisposition(string $disposition, string $filename = ''
    182182
    */
    183183
    public function prepare(Request $request): static
    184184
    {
    185-
    parent::prepare($request);
    186-
    187185
    if ($this->isInformational() || $this->isEmpty()) {
    186+
    parent::prepare($request);
    187+
    188188
    $this->maxlen = 0;
    189189

    190190
    return $this;
    @@ -194,6 +194,8 @@ public function prepare(Request $request): static
    194194
    $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
    195195
    }
    196196

    197+
    parent::prepare($request);
    198+
    197199
    $this->offset = 0;
    198200
    $this->maxlen = -1;
    199201

    src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php

    Lines changed: 26 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -388,6 +388,32 @@ public function testPrepareNotAddingContentTypeHeaderIfNoContentResponse()
    388388
    $this->assertFalse($response->headers->has('Content-Type'));
    389389
    }
    390390

    391+
    public function testContentTypeIsCorrectlyDetected()
    392+
    {
    393+
    $response = new BinaryFileResponse(__DIR__.'/File/Fixtures/test.gif');
    394+
    395+
    $request = Request::create('/');
    396+
    $response->prepare($request);
    397+
    398+
    $this->assertSame(200, $response->getStatusCode());
    399+
    $this->assertSame('image/gif', $response->headers->get('Content-Type'));
    400+
    }
    401+
    402+
    public function testContentTypeIsNotGuessedWhenTheFileWasNotModified()
    403+
    {
    404+
    $response = new BinaryFileResponse(__DIR__.'/File/Fixtures/test.gif');
    405+
    $response->setAutoLastModified();
    406+
    407+
    $request = Request::create('/');
    408+
    $request->headers->set('If-Modified-Since', $response->getLastModified()->format('D, d M Y H:i:s').' GMT');
    409+
    $isNotModified = $response->isNotModified($request);
    410+
    $this->assertTrue($isNotModified);
    411+
    $response->prepare($request);
    412+
    413+
    $this->assertSame(304, $response->getStatusCode());
    414+
    $this->assertFalse($response->headers->has('Content-Type'));
    415+
    }
    416+
    391417
    protected function provideResponse()
    392418
    {
    393419
    return new BinaryFileResponse(__DIR__.'/../README.md', 200, ['Content-Type' => 'application/octet-stream']);

    src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php

    Lines changed: 6 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -33,8 +33,14 @@ class ErrorListener implements EventSubscriberInterface
    3333
    protected $controller;
    3434
    protected $logger;
    3535
    protected $debug;
    36+
    /**
    37+
    * @var array<class-string, array{log_level: string|null, status_code: int<100,599>|null}>
    38+
    */
    3639
    protected $exceptionsMapping;
    3740

    41+
    /**
    42+
    * @param array<class-string, array{log_level: string|null, status_code: int<100,599>|null}> $exceptionsMapping
    43+
    */
    3844
    public function __construct(string|object|array|null $controller, LoggerInterface $logger = null, bool $debug = false, array $exceptionsMapping = [])
    3945
    {
    4046
    $this->controller = $controller;

    src/Symfony/Component/Notifier/Bridge/Expo/ExpoTransport.php

    Lines changed: 9 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -50,6 +50,9 @@ public function supports(MessageInterface $message): bool
    5050
    return $message instanceof PushMessage;
    5151
    }
    5252

    53+
    /**
    54+
    * @see https://docs.expo.dev/push-notifications/sending-notifications/#http2-api
    55+
    */
    5356
    protected function doSend(MessageInterface $message): SentMessage
    5457
    {
    5558
    if (!$message instanceof PushMessage) {
    @@ -91,10 +94,14 @@ protected function doSend(MessageInterface $message): SentMessage
    9194
    throw new TransportException('Unable to post the Expo message: '.$errorMessage, $response);
    9295
    }
    9396

    94-
    $success = $response->toArray(false);
    97+
    $result = $response->toArray(false);
    98+
    99+
    if ('error' === $result['data']['status']) {
    100+
    throw new TransportException(sprintf('Unable to post the Expo message: "%s" (%s)', $result['data']['message'], $result['data']['details']['error']), $response);
    101+
    }
    95102

    96103
    $sentMessage = new SentMessage($message, (string) $this);
    97-
    $sentMessage->setMessageId($success['data']['id']);
    104+
    $sentMessage->setMessageId($result['data']['id']);
    98105

    99106
    return $sentMessage;
    100107
    }

    src/Symfony/Component/Security/Http/Authenticator/AbstractLoginFormAuthenticator.php

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -41,7 +41,7 @@ abstract protected function getLoginUrl(Request $request): string;
    4141
    */
    4242
    public function supports(Request $request): bool
    4343
    {
    44-
    return $request->isMethod('POST') && $this->getLoginUrl($request) === $request->getPathInfo();
    44+
    return $request->isMethod('POST') && $this->getLoginUrl($request) === $request->getBaseUrl().$request->getPathInfo();
    4545
    }
    4646

    4747
    /**
    Lines changed: 121 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,121 @@
    1+
    <?php
    2+
    3+
    /*
    4+
    * This file is part of the Symfony package.
    5+
    *
    6+
    * (c) Fabien Potencier <fabien@symfony.com>
    7+
    *
    8+
    * For the full copyright and license information, please view the LICENSE
    9+
    * file that was distributed with this source code.
    10+
    */
    11+
    12+
    namespace Symfony\Component\Security\Http\Tests\Authenticator;
    13+
    14+
    use PHPUnit\Framework\TestCase;
    15+
    use Symfony\Component\HttpFoundation\Request;
    16+
    use Symfony\Component\HttpFoundation\Response;
    17+
    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
    18+
    use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
    19+
    use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
    20+
    use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
    21+
    22+
    class AbstractLoginFormAuthenticatorTest extends TestCase
    23+
    {
    24+
    /**
    25+
    * @dataProvider provideSupportsData
    26+
    */
    27+
    public function testSupports(string $loginUrl, Request $request, bool $expected)
    28+
    {
    29+
    $authenticator = new ConcreteFormAuthenticator($loginUrl);
    30+
    $this->assertSame($expected, $authenticator->supports($request));
    31+
    }
    32+
    33+
    public function provideSupportsData(): iterable
    34+
    {
    35+
    yield [
    36+
    '/login',
    37+
    Request::create('http://localhost/login', Request::METHOD_POST, [], [], [], [
    38+
    'DOCUMENT_ROOT' => '/var/www/app/public',
    39+
    'PHP_SELF' => '/index.php',
    40+
    'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
    41+
    'SCRIPT_NAME' => '/index.php',
    42+
    ]),
    43+
    true,
    44+
    ];
    45+
    yield [
    46+
    '/login',
    47+
    Request::create('http://localhost/somepath', Request::METHOD_POST, [], [], [], [
    48+
    'DOCUMENT_ROOT' => '/var/www/app/public',
    49+
    'PHP_SELF' => '/index.php',
    50+
    'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
    51+
    'SCRIPT_NAME' => '/index.php',
    52+
    ]),
    53+
    false,
    54+
    ];
    55+
    yield [
    56+
    '/folder/login',
    57+
    Request::create('http://localhost/folder/login', Request::METHOD_POST, [], [], [], [
    58+
    'DOCUMENT_ROOT' => '/var/www/app/public',
    59+
    'PHP_SELF' => '/folder/index.php',
    60+
    'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
    61+
    'SCRIPT_NAME' => '/folder/index.php',
    62+
    ]),
    63+
    true,
    64+
    ];
    65+
    yield [
    66+
    '/folder/login',
    67+
    Request::create('http://localhost/folder/somepath', Request::METHOD_POST, [], [], [], [
    68+
    'DOCUMENT_ROOT' => '/var/www/app/public',
    69+
    'PHP_SELF' => '/folder/index.php',
    70+
    'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
    71+
    'SCRIPT_NAME' => '/folder/index.php',
    72+
    ]),
    73+
    false,
    74+
    ];
    75+
    yield [
    76+
    '/index.php/login',
    77+
    Request::create('http://localhost/index.php/login', Request::METHOD_POST, [], [], [], [
    78+
    'DOCUMENT_ROOT' => '/var/www/app/public',
    79+
    'PHP_SELF' => '/index.php',
    80+
    'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
    81+
    'SCRIPT_NAME' => '/index.php',
    82+
    ]),
    83+
    true,
    84+
    ];
    85+
    yield [
    86+
    '/index.php/login',
    87+
    Request::create('http://localhost/index.php/somepath', Request::METHOD_POST, [], [], [], [
    88+
    'DOCUMENT_ROOT' => '/var/www/app/public',
    89+
    'PHP_SELF' => '/index.php',
    90+
    'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
    91+
    'SCRIPT_NAME' => '/index.php',
    92+
    ]),
    93+
    false,
    94+
    ];
    95+
    }
    96+
    }
    97+
    98+
    class ConcreteFormAuthenticator extends AbstractLoginFormAuthenticator
    99+
    {
    100+
    private $loginUrl;
    101+
    102+
    public function __construct(string $loginUrl)
    103+
    {
    104+
    $this->loginUrl = $loginUrl;
    105+
    }
    106+
    107+
    protected function getLoginUrl(Request $request): string
    108+
    {
    109+
    return $this->loginUrl;
    110+
    }
    111+
    112+
    public function authenticate(Request $request)
    113+
    {
    114+
    return new SelfValidatingPassport(new UserBadge('dummy'));
    115+
    }
    116+
    117+
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    118+
    {
    119+
    return null;
    120+
    }
    121+
    }

    0 commit comments

    Comments
     (0)
    0