CodeIgniter4 icon indicating copy to clipboard operation
CodeIgniter4 copied to clipboard

Bug: Duplicate Response Headers

Open sclubricants opened this issue 2 years ago • 8 comments

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

sclubricants avatar Feb 16 '23 18:02 sclubricants

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.

tangix avatar Feb 18 '23 07:02 tangix

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.

benedict-tshaba avatar Feb 23 '23 15:02 benedict-tshaba

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

sclubricants avatar Feb 23 '23 20:02 sclubricants

What If you run with php spark serve? The cache headers will change?

kenjis avatar Feb 23 '23 22:02 kenjis

<?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

kenjis avatar Feb 23 '23 22:02 kenjis

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.

sclubricants avatar Feb 24 '23 01:02 sclubricants

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.

kenjis avatar Feb 24 '23 01:02 kenjis

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.

parisiam avatar Aug 22 '23 22:08 parisiam

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

bgeneto avatar Feb 29 '24 17:02 bgeneto

I sent PR #8601

kenjis avatar Mar 02 '24 13:03 kenjis