Skip to content

Commit

Permalink
Fix bug in transforming headers for response (#8)
Browse files Browse the repository at this point in the history
* Fixed problem when header has colons in the content 

---------

Co-authored-by: Garry Childs <garry.childs@xigen.co.uk>
Co-authored-by: Bryan Nielsen <bryan@packettide.com>
  • Loading branch information
3 people authored Dec 5, 2023
1 parent cc96d4e commit 0d8ef2f
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Fixed

- Bug in transforming headers for Laravel response

## [1.2.1] - 2023-11-28

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion src/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public function runGlobal()
$headers = $this->getRestrictedProperty($response, 'headers');

if ($body == '') {
return Response::fromOutput($status);
return (new Response)->fromOutput($status);
}

return new \Illuminate\Http\Response($body, $status, $headers);
Expand Down
43 changes: 26 additions & 17 deletions src/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,25 @@ class Response
* @param int $status
* @return Illuminate\Http\Response
*/
public static function fromOutput($status = 200)
public function fromOutput($status = 200)
{
$output = ee()->output->final_output;
$response = ee('Response') ?: new \ExpressionEngine\Core\Response;

// Generate No-Cache Headers

if (ee()->config->item('send_headers') == 'y' && ee()->output->out_type != 'feed' && ee()->output->out_type != '404' && ee()->output->out_type != 'cp_asset') {
ee()->output->set_status_header($status);

if (! ee('Response')->hasHeader('Expires')) {
if (! $response->hasHeader('Expires')) {
ee()->output->set_header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
}

if (! ee('Response')->hasHeader('Last-Modified')) {
if (! $response->hasHeader('Last-Modified')) {
ee()->output->set_header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
}

if (! ee('Response')->hasHeader('Pragma')) {
if (! $response->hasHeader('Pragma')) {
ee()->output->set_header('Pragma: no-cache');
}
}
Expand All @@ -38,19 +39,19 @@ public static function fromOutput($status = 200)

switch (ee()->output->out_type) {
case 'webpage':
if (! ee('Response')->hasHeader('Content-Type')) {
if (! $response->hasHeader('Content-Type')) {
ee()->output->set_header('Content-Type: text/html; charset='.ee()->config->item('charset'));
}

break;
case 'css':
if (! ee('Response')->hasHeader('Content-Type')) {
if (! $response->hasHeader('Content-Type')) {
ee()->output->set_header('Content-type: text/css');
}

break;
case 'js':
if (! ee('Response')->hasHeader('Content-Type')) {
if (! $response->hasHeader('Content-Type')) {
ee()->output->set_header('Content-type: text/javascript');
}
ee()->output->enable_profiler = false;
Expand All @@ -62,7 +63,7 @@ public static function fromOutput($status = 200)

break;
case 'xml':
if (! ee('Response')->hasHeader('Content-Type')) {
if (! $response->hasHeader('Content-Type')) {
ee()->output->set_header('Content-Type: text/xml');
}
$output = trim($output);
Expand Down Expand Up @@ -257,32 +258,40 @@ public static function fromOutput($status = 200)
// Transform headers that have already been set on the request
// to the correct format ["header_name" => "value"]
$headers = array_reduce(headers_list(), function ($carry, $header) use ($exclude) {
$pieces = explode(':', $header);
$name = trim(array_shift($pieces));
$value = ! empty($pieces) ? implode('', $pieces) : '';
$header = $this->parseHeader($header);

if (! in_array(strtolower($name), $exclude)) {
$carry[$name] = trim($value);
if (! in_array(strtolower($header->name), $exclude)) {
$carry[$header->name] = $header->value;
}

// Remove the already set header to avoid duplicates in the response
header_remove($name);
header_remove($header->name);

return $carry;
}, []);

// Transform and set headers that have been assigned to the Output class
// but not yet set on the request to be ["header_name" => "value"]
foreach (ee()->output->headers as $row) {
$header = explode(': ', $row[0]);
$header = $this->parseHeader($row[0]);
$replace = $row[1];

// If this header has not already been set, or if we are replacing it set the value
if (! in_array(strtolower($header[0]), $exclude) && (! array_key_exists($header[0], $headers) || $replace)) {
$headers[$header[0]] = $header[1];
if (! in_array(strtolower($header->name), $exclude) && (! array_key_exists($header->name, $headers) || $replace)) {
$headers[$header->name] = $header->value;
}
}

return new \Illuminate\Http\Response($output, $status, $headers);
}

protected function parseHeader($header)
{
$pieces = explode(':', $header, 2);

return (object) [
'name' => $pieces[0],
'value' => trim($pieces[1] ?? ''),
];
}
}
19 changes: 19 additions & 0 deletions tests/Core/ResponseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Tests\Core;

use Expressionengine\Coilpack\Response;
use Tests\TestCase;

class ResponseTest extends TestCase
{
public function test_parsing_headers_with_multiple_colons()
{
ee()->output->set_header('test: one:two:three');

$response = (new Response)->fromOutput();

$this->assertEquals($response->headers->get('Expires'), 'Mon, 26 Jul 1997 05:00:00 GMT');
$this->assertEquals($response->headers->get('test'), 'one:two:three');
}
}
3 changes: 3 additions & 0 deletions tests/fixtures/phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
failOnRisky="false"
>
<testsuites>
<testsuite name="Core">
<directory suffix="Test.php">./tests/Core</directory>
</testsuite>
<testsuite name="Fieldtypes">
<directory suffix="Test.php">./tests/Fieldtype</directory>
</testsuite>
Expand Down

0 comments on commit 0d8ef2f

Please sign in to comment.