Skip to content

Commit

Permalink
fix: prioritize headers set by the Response class
Browse files Browse the repository at this point in the history
  • Loading branch information
michalsn committed Oct 25, 2024
1 parent c830d5f commit 575c916
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 2 deletions.
6 changes: 4 additions & 2 deletions system/HTTP/ResponseTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -403,16 +403,18 @@ public function sendHeaders()
if ($value instanceof Header) {
header(
$name . ': ' . $value->getValueLine(),
false,
true,
$this->getStatusCode()
);
} else {
$replace = true;
foreach ($value as $header) {
header(
$name . ': ' . $header->getValueLine(),
false,
$replace,
$this->getStatusCode()
);
$replace = false;
}
}
}
Expand Down
50 changes: 50 additions & 0 deletions tests/system/HTTP/ResponseSendTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,54 @@ public function testDoNotSendUnSecureCookie(): void
// send it
$response->send();
}

/**
* Make sure that the headers set by the header() function
* are overridden by the headers defined in the Response class.
*/
#[PreserveGlobalState(false)]
#[RunInSeparateProcess]
#[WithoutErrorHandler]
public function testHeaderOverride(): void
{
$response = new Response(new App());
$response->pretend(false);

$body = 'Hello';
$response->setBody($body);

// single header
$response->setHeader('Vary', 'Accept-Encoding');
$this->assertSame('Accept-Encoding', $response->header('Vary')->getValue());

// multiple headers
$response->setHeader('Access-Control-Expose-Headers', 'X-Custom-Header');
$response->addHeader('Access-Control-Expose-Headers', 'Content-Length');
$header = $response->header('Access-Control-Expose-Headers');
$this->assertIsArray($header);
$this->assertSame('X-Custom-Header', $header[0]->getValue());
$this->assertSame('Content-Length', $header[1]->getValue());

// send it
ob_start();
header('Vary: User-Agent');
header('Access-Control-Expose-Headers: Content-Encoding');
header('Allow: GET, POST');
$response->send();
if (ob_get_level() > 0) {
ob_end_clean();
}

// single header
$this->assertHeaderEmitted('Vary: Accept-Encoding');
$this->assertHeaderNotEmitted('Vary: User-Agent');

// multiple headers
$this->assertHeaderEmitted('Access-Control-Expose-Headers: X-Custom-Header');
$this->assertHeaderEmitted('Access-Control-Expose-Headers: Content-Length');
$this->assertHeaderNotEmitted('Access-Control-Expose-Headers: Content-Encoding');

// not overridden by the response class
$this->assertHeaderEmitted('Allow: GET, POST');
}
}
14 changes: 14 additions & 0 deletions user_guide_src/source/changelogs/v4.6.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ See :ref:`Upgrading Guide <upgrade-460-sid-change>` for details.

.. _v460-interface-changes:

Headers
-------

The headers set by the ``Response`` class replace those that can be set by the PHP
``header()`` function.

In previous versions, headers set by the ``Response`` class were added to existing
ones - giving no options to change them. That could lead to unexpected behavior when
the same headers were set with mutually exclusive directives.

Interface Changes
=================

Expand Down Expand Up @@ -282,6 +292,10 @@ Deprecations
Bugs Fixed
**********

- **Response:**
- Headers set using the ``Response`` class are now prioritized and replace headers
that can be set manually using the PHP ``header()`` function.

See the repo's
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_
for a complete list of bugs fixed.

0 comments on commit 575c916

Please sign in to comment.