diff --git a/src/Response.php b/src/Response.php index adcfc02..3f76a86 100755 --- a/src/Response.php +++ b/src/Response.php @@ -540,9 +540,15 @@ public function enablePayload(): static * * @param string $key * @param string $value + * @param bool $override */ - public function addHeader(string $key, string $value): static + public function addHeader(string $key, string $value, bool $override = false): static { + if ($override) { + $this->headers[$key] = $value; + return $this; + } + if (\array_key_exists($key, $this->headers)) { if (\is_array($this->headers[$key])) { $this->headers[$key][] = $value; @@ -659,13 +665,21 @@ public function send(string $body = ''): void } $serverHeader = $this->headers['Server'] ?? 'Utopia/Http'; - $this->addHeader('Server', $serverHeader); + $this->addHeader('Server', $serverHeader, override: true); $this->appendCookies(); + $hasContentEncoding = false; + foreach ($this->headers as $name => $values) { + if (\strtolower($name) === 'content-encoding') { + $hasContentEncoding = true; + break; + } + } + // Compress body only if all conditions are met: if ( - empty($this->headers['content-encoding']) && + !$hasContentEncoding && !empty($this->acceptEncoding) && $this->isCompressible($this->contentType) && strlen($body) > $this->compressionMinSize @@ -674,14 +688,14 @@ public function send(string $body = ''): void if ($algorithm) { $body = $algorithm->compress($body); - $this->addHeader('Content-Length', (string) \strlen($body)); - $this->addHeader('Content-Encoding', $algorithm->getContentEncoding()); - $this->addHeader('X-Utopia-Compression', 'true'); - $this->addHeader('Vary', 'Accept-Encoding'); + $this->addHeader('Content-Length', (string) \strlen($body), override: true); + $this->addHeader('Content-Encoding', $algorithm->getContentEncoding(), override: true); + $this->addHeader('X-Utopia-Compression', 'true', override: true); + $this->addHeader('Vary', 'Accept-Encoding', override: true); } } - $this->addHeader('X-Debug-Speed', (string) (microtime(true) - $this->startTime)); + $this->addHeader('X-Debug-Speed', (string) (microtime(true) - $this->startTime), override: true); $this->appendHeaders(); // Send response @@ -769,7 +783,7 @@ public function chunk(string $body = '', bool $end = false): void $this->sent = true; } - $this->addHeader('X-Debug-Speed', (string) (microtime(true) - $this->startTime)); + $this->addHeader('X-Debug-Speed', (string) (microtime(true) - $this->startTime), override: true); $this ->appendCookies() @@ -799,7 +813,7 @@ protected function appendHeaders(): static // Send content type header if (!empty($this->contentType)) { - $this->addHeader('Content-Type', $this->contentType); + $this->addHeader('Content-Type', $this->contentType, override: true); } // Set application headers @@ -908,7 +922,7 @@ public function redirect(string $url, int $statusCode = 301): void } $this - ->addHeader('Location', $url) + ->addHeader('Location', $url, override: true) ->setStatusCode($statusCode) ->send(''); } diff --git a/tests/e2e/ResponseTest.php b/tests/e2e/ResponseTest.php index ccb734b..9db080e 100644 --- a/tests/e2e/ResponseTest.php +++ b/tests/e2e/ResponseTest.php @@ -162,5 +162,10 @@ public function testSetCookie() $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('value1', $response['cookies']['key1']); $this->assertEquals('value2', $response['cookies']['key2']); + + $response = $this->client->call(Client::METHOD_GET, '/set-cookie-override'); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertArrayNotHasKey('key1', $response['cookies']); + $this->assertEquals('value2', $response['cookies']['key2']); } } diff --git a/tests/e2e/server.php b/tests/e2e/server.php index 0a6641a..3cec25d 100644 --- a/tests/e2e/server.php +++ b/tests/e2e/server.php @@ -42,6 +42,15 @@ $response->send('OK'); }); +App::get('/set-cookie-override') + ->inject('request') + ->inject('response') + ->action(function (Request $request, Response $response) { + $response->addHeader('Set-Cookie', 'key1=value1', override: true); + $response->addHeader('Set-Cookie', 'key2=value2', override: true); + $response->send('OK'); + }); + App::get('/chunked') ->inject('response') ->action(function (Response $response) {