Skip to content

Commit

Permalink
review
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas committed Nov 17, 2022
1 parent 2eca954 commit 4d5e71d
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 23 deletions.
2 changes: 1 addition & 1 deletion UPGRADE-6.3.md
Expand Up @@ -4,4 +4,4 @@ UPGRADE FROM 6.2 to 6.3
HttpFoundation
--------------

* Deprecate calling `Response::sendHeaders()` without any arguments
* `Response::sendHeaders()` now takes an optional `$statusCode` parameter
58 changes: 37 additions & 21 deletions src/Symfony/Component/HttpFoundation/Response.php
Expand Up @@ -110,6 +110,11 @@ class Response
*/
public $headers;

/**
* Track
*/
private ?ResponseHeaderBag $alreadySentHeaders = null;

/**
* @var string
*/
Expand Down Expand Up @@ -211,6 +216,13 @@ class Response
511 => 'Network Authentication Required', // RFC6585
];

/**
* @var array<string, bool>
*
* Tracks headers already sent in informational responses.
*/
private array $sentHeaders;

/**
* @param int $status The HTTP status code (200 "OK" by default)
*
Expand Down Expand Up @@ -332,47 +344,51 @@ public function prepare(Request $request): static
*/
public function sendHeaders(/* ?int $statusCode = null */): static
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/http-foundation', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);

$statusCode = null;
} else {
$statusCode = func_get_arg(0) ?: null;
}

// headers have already been sent by the developer
if (headers_sent()) {
return $this;
}

$statusCode = \func_num_args() > 0 ? func_get_arg(0) : null;
$informationalResponse = $statusCode >= 100 && $statusCode < 200;
if ($informationalResponse && !\function_exists('headers_send')) {
// skip informational responses if not supported by the SAPI
return $this;
}

// headers
foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
$previousValues = $this->sentHeaders[$name] ?? null;
if ($previousValues === $values) {
// Header already sent in a previous response, it will be automatically copied in this response by PHP
continue;
}

$replace = 0 === strcasecmp($name, 'Content-Type');
foreach ($values as $value) {

$newValues = null === $previousValues ? $values : array_diff($values, $previousValues);
foreach ($newValues as $value) {
header($name.': '.$value, $replace, $this->statusCode);
}

if ($informationalResponse) {
$this->sentHeaders[$name] = $values;
}
}

// cookies
foreach ($this->headers->getCookies() as $cookie) {
header('Set-Cookie: '.$cookie, false, $this->statusCode);
}

if ($statusCode) {
if (\function_exists('headers_send')) {
headers_send($statusCode);
if ($informationalResponse) {
headers_send($statusCode);

return $this;
}

if ($statusCode >= 100 && $statusCode < 200) {
// skip informational responses if not supported by the SAPI
return $this;
}
} else {
$statusCode = $this->statusCode;
return $this;
}

$statusCode ??= $this->statusCode;

// status
header(sprintf('HTTP/%s %s %s', $this->version, $statusCode, $this->statusText), true, $statusCode);

Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/HttpFoundation/StreamedResponse.php
Expand Up @@ -63,7 +63,7 @@ public function setCallback(callable $callback): static
*
* @return $this
*/
public function sendHeaders(): static
public function sendHeaders(/* ?int $statusCode = null */): static
{
if ($this->headersSent) {
return $this;
Expand Down

0 comments on commit 4d5e71d

Please sign in to comment.