Bug: Duplicate Response Headers
PHP Version
8.0
CodeIgniter4 Version
4.3
CodeIgniter4 Installation Method
Composer (as dependency to an existing project)
Which operating systems have you tested for this bug?
Linux
Which server did you use?
apache
Database
No response
What happened?
Cache-Control and Pragma headers are included twice
Steps to Reproduce
Make a standard controller and return a string. Check the response headers.
Expected Output
Expected to only list each header once.
This is what I get though:
Cache-Control: no-store, no-cache, must-revalidate, no-store, max-age=0, no-cache
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 5969
Content-Type: text/html; charset=UTF-8
Date: Thu, 16 Feb 2023 18:37:48 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive: timeout=5, max=100
Pragma: no-cache
Pragma: no-cache
Server: Apache/2.4.18 (Ubuntu)
Set-Cookie: ......
Vary: Accept-Encoding
Perhaps it is ok to have duplicates in some circumstances. https://stackoverflow.com/questions/4371328/are-duplicate-http-response-headers-acceptable
I wouldn't think this would be ok:
Pragma: no-cache
Pragma: no-cache
Anything else?
No response
As a work-around this issue I have been starting to use header_remove(null) in my code, especially when I want to have the images generated cached by the client. I have tried $response->setCache() but I get the feeling this causes the headers to be set twice.
Out of interest are you using $this->response->send()? i.e. the send method on the ResponseInterface? If you are noticed a while back that if you do:
return $this->response->setStatusCode(201)->send();
or similar then you get the double headers, and simply removing the return statement worked fine.
Here is my controller method:
protected function response($status=400, $result=false, $data=null, $message='', $params = [])
{
if ($data === false) {
$data = null;
}
$json = json_encode(['result' => (bool) $result, 'message' => (string) $message, 'data' => $data, 'params' => $params]);
$encoding = $this->request->negotiate('encoding', ['','gzip']);
if ($encoding === 'gzip') {
$json = gzencode($json, 9);
$this->response->setHeader('Content-Encoding', 'gzip');
}
$this->response->setHeader('Content-Length', strlen($json));
return $this->response->setStatusCode($status)->setHeader('Content-Type', 'application/json; charset=utf-8')->setBody($json);
}
Response Headers:
HTTP/1.1 200 OK
Date: Thu, 23 Feb 2023 20:00:15 GMT
Server: Apache/2.4.18 (Ubuntu)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, no-store, max-age=0, no-cache
Pragma: no-cache
Content-Encoding: gzip
Vary: Authorization
Content-Length: 453
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Pragma: no-cache
Content-Type: application/json; charset=utf-8
What If you run with php spark serve?
The cache headers will change?
<?php
namespace App\Controllers;
class Home extends BaseController
{
public function index()
{
session();
return '';
}
}
HTTP/1.1 200 OK
Host: localhost:8080
Date: Thu, 23 Feb 2023 22:56:22 GMT
Connection: close
X-Powered-By: PHP/8.1.13
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate ← PHP Session
Pragma: no-cache
Cache-Control: no-store, max-age=0, no-cache ← CI's default
Content-Type: text/html; charset=UTF-8
I wonder if it has something to do with session.
The request does create a session and then after the request a filter removes the set-cookie headers.
I'm using Myth/Auth in a filter for authorization services. This uses session. I'm using jwt for authentication.
I need to rework this a bit. I probably can find a way around using a session.
PHP Session sends cache header by default. See https://www.php.net/manual/en/session.configuration.php#ini.session.cache-limiter
The header is not managed by CI4 Response class.
I have encountered a similar problem of duplication of the Cache-Control header.
As @kenjis said, when the session starts, PHP automatically sends Cache-Control instruction to the header. It implicitely execute this instruction:
session_cache_limiter('nocache');
See also: https://www.php.net/manual/en/function.s...he-limiter
The problem is that the headers sent by session_cache_limiter() cannot be replaced or removed by CodeIgniter methods and functions such as:
// removeHeader() does NOT remove the headers sent by session_cache_limiter()
$response->removeHeader('Cache-Control');
The solution is to stop these headers from being issued BEFORE the session starts by using session_cache_limiter('');:
// We prevent PHP from sending the cache related headers
session_cache_limiter('');
// Start the session
Services::session();
It's not really a bug of CodeIgniter.
The solution is to stop these headers from being issued BEFORE the session starts by using
session_cache_limiter('');:// We prevent PHP from sending the cache related headers session_cache_limiter(''); // Start the session Services::session();
@parisiam Where in your code do you put the above lines in order to avoid the error below? I've tried in the initController method of my BaseController class without success. Is there an oficial solution for this header duplication in CI4? TIA.
session_cache_limiter(): Session cache limiter cannot be changed when a session is active
I sent PR #8601