Verified Commit 257ca110 authored by Dave Long's avatar Dave Long
Browse files

Issue #3410022 by heddn, larowlan, catch: Regression from #3295790...

Issue #3410022 by heddn, larowlan, catch: Regression from #3295790 content-length header set earlier than expected

(cherry picked from commit 8f087227)
parent 7eb3267b
Loading
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -891,6 +891,11 @@ services:
  argument_resolver.default:
    class: Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver
    public: false
  http_middleware.content_length:
    class: Drupal\Core\StackMiddleware\ContentLength
    tags:
      # Must run before the page_cache and big_pipe middleware.
      - { name: http_middleware, priority: 140 }
  http_middleware.ajax_page_state:
    class: Drupal\Core\StackMiddleware\AjaxPageState
    tags:
+0 −38
Original line number Diff line number Diff line
@@ -300,40 +300,6 @@ protected function setExpiresNoCache(Response $response) {
    $response->setExpires(\DateTime::createFromFormat('j-M-Y H:i:s T', '19-Nov-1978 05:00:00 UTC'));
  }

  /**
   * Sets the Content-Length header on the response.
   *
   * @param \Symfony\Component\HttpKernel\Event\ResponseEvent $event
   *   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 {
    $response = $event->getResponse();

    if ($response->isInformational() || $response->isEmpty()) {
      return;
    }

    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);
  }

  /**
   * Registers the methods in this class that should be listeners.
   *
@@ -345,10 +311,6 @@ public static function getSubscribedEvents(): array {
    // There is no specific reason for choosing 16 beside it should be executed
    // before ::onRespond().
    $events[KernelEvents::RESPONSE][] = ['onAllResponds', 16];
    // Run very late, after all other response subscribers have run. However,
    // any response subscribers that convert a response to a streamed response
    // must run after this and undo what this does.
    $events[KernelEvents::RESPONSE][] = ['setContentLengthHeader', -1024];
    return $events;
  }

+52 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Core\StackMiddleware;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;

/**
 * Adds a Content-Length HTTP header to responses.
 */
class ContentLength implements HttpKernelInterface {

  /**
   * Constructs a new ContentLength instance.
   *
   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel
   *   The wrapped HTTP kernel.
   */
  public function __construct(
    protected readonly HttpKernelInterface $httpKernel,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = TRUE): Response {
    $response = $this->httpKernel->handle($request, $type, $catch);
    if ($response->isInformational() || $response->isEmpty()) {
      return $response;
    }

    if ($response->headers->has('Transfer-Encoding')) {
      return $response;
    }

    // Drupal cannot set the correct content length header when there is a
    // server error.
    if ($response->isServerError()) {
      return $response;
    }

    $content = $response->getContent();
    if ($content === FALSE) {
      return $response;
    }

    $response->headers->set('Content-Length', strlen($content), TRUE);
    return $response;
  }

}
+5 −0
Original line number Diff line number Diff line
@@ -23,3 +23,8 @@ services:
    class: Drupal\big_pipe\EventSubscriber\NoBigPipeRouteAlterSubscriber
    tags:
      - { name: event_subscriber }
  http_middleware.big_pipe:
    class: \Drupal\big_pipe\StackMiddleware\ContentLength
    tags:
      # Must run after the content_length middleware.
      - { name: http_middleware, priority: 150 }
+0 −5
Original line number Diff line number Diff line
@@ -82,8 +82,6 @@ public function onRespond(ResponseEvent $event) {
      $content = $response->getContent();
      $content = str_replace('<drupal-big-pipe-scripts-bottom-marker>', '', $content);
      $response->setContent($content);
      // FinishResponseSubscriber::setContentLengthHeader() already ran.
      $response->headers->set('Content-Length', strlen($content), TRUE);
    }

    // If there are neither BigPipe placeholders nor no-JS BigPipe placeholders,
@@ -96,9 +94,6 @@ public function onRespond(ResponseEvent $event) {
    $big_pipe_response = new BigPipeResponse($response);
    $big_pipe_response->setBigPipeService($this->getBigPipeService($event));

    // A BigPipe response's length is impossible to predict.
    $big_pipe_response->headers->remove('Content-Length');

    $event->setResponse($big_pipe_response);
  }

Loading