Closed rbairwell closed 8 years ago
are you sure that you are not writing to the browser?
If you say do a print "" or echo "" it will over write the content type header.
Yep, I'm, sure. I've just done new test case which consists of a single file:
<?php
// file /var/www/test/index.php
require __DIR__.'/vendor/autoload.php';
$app=new \Slim\App();
$app->get('/204test',function ($request,$response,$arg) {
$response = $response->withStatus(204, 'No Content');
return $response;
});
$app->run();
with my nginx configuration being:
server {
listen 88;
server_name "";
root /var/www/test/;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
include php.conf;
}
and /etc/nginx/php.config being:
location ~ \.php {
include fastcgi_params;
fastcgi_keep_conn on;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
fastcgi_pass unix:/var/run/php-fpm.sock;
}
and a test curl transaction is:
vagrant@host:/vagrant/project$ curl --raw http://127.0.0.1:88/204test -v
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 88 (#0)
> GET /204test HTTP/1.1
> User-Agent: curl/7.38.0
> Host: 127.0.0.1:88
> Accept: */*
>
< HTTP/1.1 204 No Content
* Server nginx/1.8.0 is not blacklisted
< Server: nginx/1.8.0
< Date: Tue, 24 Nov 2015 16:47:22 GMT
< Content-Type: text/html; charset=UTF-8
< Connection: keep-alive
< X-Powered-By: PHP/7.0.0-dev
<
* Connection #0 to host 127.0.0.1 left intact
Also Slim's response is initialized with a Content-Type header ... https://github.com/slimphp/Slim/blob/3.x/Slim/Container.php#L132-L137
OR
I believe nginx might be adding the content-type header because of this little nugget...
The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
Your browser would lose the extra headers after content-type if it were broken.
You can test this by manually adding a Content-Type header to your response. NGinx should let your's go through.
I've amended the test script to add a
$response=$response->withHeader('Content-type','text/plain');
but if the status code is 204, Slim (in App->finalize) still strips it out: causing ngnix to add the text/html Content-type back in (I've even tried add body content to see if it makes a difference: it doesn't) [changing the status code to 200 does give my text/plain content type and the body].
Changing App->finalize to:
if ($this->isEmptyResponse($response)) {
return $response->withoutHeader('Content-Type')->withoutHeader('Content-Length')->withHeader('Content-Type','');
}
did work (i.e. no Content-Type header was actually sent by nginx).
(as an aside, /etc/nginx/nginx.conf has application/octet-stream as the default_type )
I'm confused. The spec for 204 states:
The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
Surely that means that there cannot be a Content-Type or a Content-Length header?
That is my understanding as well.
@akrabat That's how I read it as well. I believe nginx is trying to be "helpful" and if there is absolutely no Content-type header set, it is adding one - however, if a Content-type header is set, but empty, "it trust you know what you are doing" but won't send the blank content-type (but also will not add its own content-type)
Right, so really we should look at seeing if we can let you manipulate the response after finalize() has run.
Just doing some tests on an Apache server and the inbuilt PHP server with a very very basic script:
It's looking more like, to achieve what Slim is trying to do by unsetting the Content-Type header, it is better off setting a blank content header (similar to "header('Content-Type:');") which will stop the content-type line being sent on all three tested servers. Counter intuitive, but works on two of the major web servers and the inbuilt one. Is there a platform where this "hack" doesn't work?
This is happening because of the php.ini default_mimetype
setting:
By default, PHP will output a character encoding using the Content-Type header. To disable sending of the charset, simply set it to be empty.
Fixed by #1629.
During testing, I found that I was getting a "Content-Type: text/html; charset=UTF-8" header being sent when I was creating a 204 No Content page (in Slim 3 RC 2 within \Slim\App::finalize and \Slim\App::isEmptyResponse it removes the Content-length and Content-type headers if the response code is 204, 205 or 304).
Obviously, this isn't a fault in Slim "per-se" but an unexpected "feature" of nginx/1.8.0 running under fastcgi. I have managed to remove the header myself using an empty Content-type header setting like:
would it be an idea of Slim to "sniff" for nginx/fastcgi and do the same if detected (I haven't been able to test this "fix" on other web servers to see if they will just strip out the empty Content-type header or not).