-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug: Multiple Expires
and Cache-Control
Headers in File Download Response
#9234
Comments
Can you provide a sample code so we can reproduce the error? |
Yes of course, but during the preparation of the example code I could narrow the issue down to a database operation which happened before. In any case I had to prepare the download response to modify any headers, I assume the headers get overridden by namespace App\Controllers;
class DownloadTest extends BaseController
{
public function getIndex($name)
{
$filename = WRITEPATH.'example/'.$name;
if (file_exists($filename)){
// Log the file access
model('MyLogsModel')->insert([
'user_id' => user_id() ?? 0,
'message' => 'Revocation list downloaded: '.$name.'.',
]);
// Prepare the download
$response = $this->response->download($filename, null);
$response->removeHeader('Expires'); // no effect
return $response
->setHeader('Content-Type', 'application/pkix-crl') // RFC 5280, section 4.2.1.13
->setHeader('Last-Modified', 'Fri, 18 Oct 2024 13:17:37 GMT') // RFC 5019, section 6.2
->setHeader('Expires', 'Sun, 17 Nov 2024 14:17:37 GMT'); // RFC 5019, section 6.2
} else {
return $this->response->setStatusCode(404);
}
}
} Respose:
If I now omit
Duplicate headers also appear when inserting without model: $db = \Config\Database::connect();
$db->table('my_logs')->insert([
'user_id' => user_id() ?? 0,
'message' => 'Revocation list downloaded: '.$name.'.',
]); |
Expires
and Last-Modified
Headers in File Download ResponseExpires
and Cache-Control
Headers in File Download Response
Thank you for the update. I have not been able to reproduce the problem, and I have to admit that the conditions that must be met for it to occur are strange. Please update CodeIgniter to the latest version (4.5.5) and try again with the built-in server:
I would guess that Apache adds some headers automatically, but since it doesn't always happen, I don't know what is causing it. By any chance, do you use any custom Generally, downloads have automatic headers set to prevent caching. To change this, you would need to extend the The only problem I see here is setting the |
I did an upgrade to I have to disagree with the statement that the headers come from the web server. The following code does not involve multiple Headers, no matter whether via spark or apache. (I know, unconventional and goes against typical framework practices) public function getIndex($name)
{
$filename = WRITEPATH . 'example/' . $name;
if (file_exists($filename)) {
// Log the file access
model('MyLogsModel')->insert([
'user_id' => user_id() ?? 0,
'message' => 'Revocation list downloaded: '.$name.'.',
]);
// Avoid using framework's response object and directly set headers with PHP
header('Content-Type: application/pkix-crl'); // RFC 5280 section 4.2.1.13
header('Last-Modified: Fri, 18 Oct 2024 13:17:37 GMT'); // RFC 5019 section 6.2
header('Expires: Sun, 17 Nov 2024 14:17:37 GMT'); // RFC 5019 section 6.2
header('Content-Length: ' . filesize($filename)); // Set content length header
header('Cache-Control: public'); // Allow caching
header('Pragma: public'); // Ensure cache compatibility
// Output the file content
readfile($filename); // Outputs the CRL directly to the client
// End script execution to avoid any further output
exit();
} else {
// Return a 404 response if the file does not exist
header("HTTP/1.0 404 Not Found");
echo 'The requested CRL was not found.';
exit();
}
} Response
Regarding the |
Thank you for mentioning Shield. That helped a lot because I realized you were using a session. Well - using a session is the real "problem". These headers are set at the PHP session level and out of CodeIgniter's control. When there is a session - all data is considered private and cache is disabled. However, the question is, shouldn't we allow On the other hand, maybe we should just modify the way we send headers and force a I'm leaning towards the second option, but I'm not convinced - I'd like to hear other people's opinions. |
I think I understand the concerns, but if I deliberately set headers with
|
PHP Version
8.1
CodeIgniter4 Version
4.5.5
CodeIgniter4 Installation Method
Manual (zip or tar.gz)
Which operating systems have you tested for this bug?
macOS, Linux
Which server did you use?
apache
Database
mysql Ver 8.3.0 for macos14.2 on arm64 (Homebrew)
What happened?
While implementing a file download feature in a CodeIgniter 4 application, I encountered an issue where multiple
Expires
andCache-Control
headers were being sent in the HTTP response. This problem occurred despite attempts to explicitly set these headers using the framework's response methods.Steps to Reproduce
Expected Output
Only one instance of each header should be sent in the response, specifically the ones set in the controller method.
Anything else?
As a workaround, the issue was resolved by using native PHP functions (
header()
andreadfile()
) to manage headers directly, bypassing CodeIgniter’s response handling. This provided complete control over the headers sent, eliminating the duplication issue.The text was updated successfully, but these errors were encountered: