yii2 icon indicating copy to clipboard operation
yii2 copied to clipboard

Http Statuscode-Line is ignored in ISS Server (and maybe other fastCGI servers)

Open Radon8472 opened this issue 2 years ago • 7 comments

What steps will reproduce the problem?

Set response-code in an IIS Server like this:

\Yii::$app->response->statusCode = 500;

or create any critical php error (e.g. echo 10/0).

What is the expected result?

Expected result is Statuscode 500 in Browser, and HTTP/1.1 500 Internal Server Error on first line of http headers.

What do you get instead?

Statuscode 200 and first header line of HTTP/1.1 200 OK

Additional info

Q A
Yii version 2.0.48.1
PHP version 8.1
Microsoft-IIS version 8.5
Operating system Window

my Researches to find the problem

I discovered, that yii does not return a statuscode 500 on php errors, and made some research. I followed the defined status-code in the response until I found yii\web\Response::sendHeaders().

After more testing I can ensure that the statuscode is correctly passed in this method and correctly passed into the header function. E.g. adding a custom header as debug like this (e.g. in one of your controller actions):

header("X-StatusLine: HTTP/{$this->version} {$statusCode} {$this->statusText}")

Gives the header X-StatusLine: HTTP/1.0 500 Internal Server Error, what makes me sure that a currect formated statusline is created in the sendHeaders() function, but statuscode is not delivered to browser.

After more reseach I discovered the Status-header, and made some tests adding this extra header. The line

header("Status: {$statusCode} {$this->statusText}");

in Response::sendStatus did not chance anything. But adding the stuscode to the 3. argument of the header function gave the expected result.

Suggestion to fix

Add the line

header("Status: {$statusCode} {$this->statusText}", true, $statusCode);

right after https://github.com/yiisoft/yii2/blob/504a66dae50c43d7bcfd8cd506b0b4ec2f096b2a/framework/web/Response.php#L383

or maybe replace the existing line with

if (php_sapi_name() === 'cgi-fcgi')
  header("Status: {$statusCode} {$this->statusText}", true, $statusCode);
else
  header("HTTP/{$this->version} {$statusCode} {$this->statusText}");

Reasons

It seems that IIS (and maybe other servers) do not respect the statuscode / message set as HTTP/{Protocol} {code} {message} -header. Adding the extra header Status: {code} {message} tells this server to chance their statusline line expected.

As far as I could find out, this behavior has something to do with cgi/fastCGI, so I thinkt this is not only an IIS exclusive problem, and could affect other server types too.

Radon8472 avatar Aug 02 '23 08:08 Radon8472

I can see that Symfony is sending

header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);

so it looks like our way. Do you think that your problem might come from misconfiguration of the server?

bizley avatar Aug 02 '23 11:08 bizley

I can see that Symfony is sending

header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);

so it looks like our way. Do you think that your problem might come from misconfiguration of the server?

I took lot of time investigation this problem. Currently it seems that: header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode

is corrent and fine for all "normal" webservers. But in this strange fast CGI modus there seem to be situations, where you need an additional header of Status: 500 Error-Text that server changes the response-code.

I am not 100% sure if this happens for all servers in fast cgi mode, or only for IIS, or if it is any special configuration in IIS.

Radon8472 avatar Aug 02 '23 12:08 Radon8472

Any disadvantages specifying statusCode argument?

samdark avatar Aug 18 '23 11:08 samdark

Any disadvantages specifying statusCode argument?

I could not find any disadvantages via google ect.

But I found the matching RFC for this header see rfc3875. Seems to be true, that this header only affects cgi based calls.

Maybe we should extend the qury for api type a bit to somthing linke the example on php.net to

$sapi_type = php_sapi_name();
if (substr($sapi_type, 0, 3) == 'cgi') {
  header("Status: {$statusCode} {$this->statusText}", true, $statusCode);
else
  header("HTTP/{$this->version} {$statusCode} {$this->statusText}");

That makes it covering fast cgi and basic cgi-mode

Radon8472 avatar Aug 25 '23 17:08 Radon8472

Yes. Good idea.

samdark avatar Aug 26 '23 01:08 samdark

Do you have time for a pull request?

samdark avatar Aug 26 '23 01:08 samdark

Do you have time for a pull request?

I think I can write the code, I am not sure if this is all, or if there is anything more to do in documentations ect.. I would start to make a pr containing the code, and test it in iss and apache, but I need some time, this week is very busy.

Radon8472 avatar Aug 30 '23 04:08 Radon8472