Issue #3396559 by alexpott, catch: Only set content-length header in specific situations
parent
d6b6ad8fd6
commit
f47d1d159e
|
@ -12,7 +12,6 @@ use Drupal\Core\PageCache\ResponsePolicyInterface;
|
||||||
use Drupal\Core\Site\Settings;
|
use Drupal\Core\Site\Settings;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||||
use Symfony\Component\HttpKernel\KernelEvents;
|
use Symfony\Component\HttpKernel\KernelEvents;
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
@ -306,14 +305,33 @@ class FinishResponseSubscriber implements EventSubscriberInterface {
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\HttpKernel\Event\ResponseEvent $event
|
* @param \Symfony\Component\HttpKernel\Event\ResponseEvent $event
|
||||||
* The event to process.
|
* The event to process.
|
||||||
|
*
|
||||||
|
* @see \Symfony\Component\HttpFoundation\Response::prepare()
|
||||||
|
* @see https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length
|
||||||
*/
|
*/
|
||||||
public function setContentLengthHeader(ResponseEvent $event): void {
|
public function setContentLengthHeader(ResponseEvent $event): void {
|
||||||
$response = $event->getResponse();
|
$response = $event->getResponse();
|
||||||
if ($response instanceof StreamedResponse) {
|
|
||||||
|
if ($response->isInformational() || $response->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$response->headers->set('Content-Length', strlen($response->getContent()), TRUE);
|
if ($response->headers->has('Transfer-Encoding')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drupal cannot set the correct content length header when there is a
|
||||||
|
// server error.
|
||||||
|
if ($response->isServerError()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = $response->getContent();
|
||||||
|
if ($content === FALSE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->headers->set('Content-Length', strlen($content), TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Tests\Core\EventSubscriber;
|
||||||
|
|
||||||
|
use Drupal\Core\Cache\Context\CacheContextsManager;
|
||||||
|
use Drupal\Core\EventSubscriber\FinishResponseSubscriber;
|
||||||
|
use Drupal\Core\Language\LanguageManagerInterface;
|
||||||
|
use Drupal\Core\PageCache\RequestPolicyInterface;
|
||||||
|
use Drupal\Core\PageCache\ResponsePolicyInterface;
|
||||||
|
use Drupal\Tests\UnitTestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||||
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @coversDefaultClass \Drupal\Core\EventSubscriber\FinishResponseSubscriber
|
||||||
|
* @group EventSubscriber
|
||||||
|
*/
|
||||||
|
class FinishResponserSubscriberTest extends UnitTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::setContentLengthHeader
|
||||||
|
* @dataProvider providerTestSetContentLengthHeader
|
||||||
|
*/
|
||||||
|
public function testSetContentLengthHeader(false|int $expected_header, Response $response) {
|
||||||
|
$event_subscriber = new FinishResponseSubscriber(
|
||||||
|
$this->prophesize(LanguageManagerInterface::class)->reveal(),
|
||||||
|
$this->getConfigFactoryStub(),
|
||||||
|
$this->prophesize(RequestPolicyInterface::class)->reveal(),
|
||||||
|
$this->prophesize(ResponsePolicyInterface::class)->reveal(),
|
||||||
|
$this->prophesize(CacheContextsManager::class)->reveal()
|
||||||
|
);
|
||||||
|
|
||||||
|
$event = new ResponseEvent(
|
||||||
|
$this->prophesize(HttpKernelInterface::class)->reveal(),
|
||||||
|
$this->prophesize(Request::class)->reveal(),
|
||||||
|
HttpKernelInterface::MAIN_REQUEST,
|
||||||
|
$response
|
||||||
|
);
|
||||||
|
|
||||||
|
$event_subscriber->setContentLengthHeader($event);
|
||||||
|
if ($expected_header === FALSE) {
|
||||||
|
$this->assertFalse($event->getResponse()->headers->has('Content-Length'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->assertSame((string) $expected_header, $event->getResponse()->headers->get('Content-Length'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerTestSetContentLengthHeader() {
|
||||||
|
return [
|
||||||
|
'Informational' => [
|
||||||
|
FALSE,
|
||||||
|
new Response('', 101),
|
||||||
|
],
|
||||||
|
'200 ok' => [
|
||||||
|
12,
|
||||||
|
new Response('Test content', 200),
|
||||||
|
],
|
||||||
|
'204' => [
|
||||||
|
FALSE,
|
||||||
|
new Response('Test content', 204),
|
||||||
|
],
|
||||||
|
'304' => [
|
||||||
|
FALSE,
|
||||||
|
new Response('Test content', 304),
|
||||||
|
],
|
||||||
|
'Client error' => [
|
||||||
|
13,
|
||||||
|
new Response('Access denied', 403),
|
||||||
|
],
|
||||||
|
'Server error' => [
|
||||||
|
FALSE,
|
||||||
|
new Response('Test content', 500),
|
||||||
|
],
|
||||||
|
'200 with transfer-encoding' => [
|
||||||
|
FALSE,
|
||||||
|
new Response('Test content', 200, ['Transfer-Encoding' => 'Chunked']),
|
||||||
|
],
|
||||||
|
'200 with FalseContentResponse' => [
|
||||||
|
FALSE,
|
||||||
|
new FalseContentResponse('Test content', 200),
|
||||||
|
],
|
||||||
|
'200 with StreamedResponse' => [
|
||||||
|
FALSE,
|
||||||
|
new StreamedResponse(status: 200),
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response that returns FALSE from ::getContent().
|
||||||
|
*/
|
||||||
|
class FalseContentResponse extends Response {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getContent(): string|false {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue