Setting HTTP results code vs. HTTP type

php.internals

Christian Schneider

19 years ago
Hi all, I ran into the following problem I would like to get an opinion on: We noticed that our website returns a HTTP/1.1 chunked response even when the request was a HTTP/1.0 request (e.g. php file_get_contents). What happens: - Wordpress (wrongly) set the result code with a hardcoded @header("HTTP/1.1 $header $text", true, $header); - PHP 5.2.1 (IMHO wrongly) patches the protocol in sapi/apache2handler/sapi_apache2.c function php_apache_sapi_send_headers, probably because "force-response-1.1" does not exist (at least not in any production version): ctx->r->proto_num = 1000 + (sline[7]-'0'); - Apache thinks the request was 1.1 and under some circumstances decides to switch to Transfer-Encoding chunked. I think the following should be done: - Ask Wordpress to use $_SERVER['SERVER_PROTOCOL'] when available instead of a hardcoded HTTP/1.1 (I'll do that) - Update the PHP header() documentation to mention this. I was also thinking that supporting/documenting header(null, true, 404); or the like would be nice for people who only want to set the return code and leave the HTTP type unchanged. - Maybe change php_apache_sapi_send_headers to not mess with proto_num. This make it impossible to force the response to HTTP/1.1 but I don't think that should be done anyway as the client might not expect it. For the same reason I think the line apr_table_set(ctx->r->subprocess_env, "force-response-1.1", "true"); should probably be removed as well... Should I open a bug report on this? Regards, - Chris

Rasmus Lerdorf

19 years ago
Replying to a 1.0 request with a 1.1 response is perfectly fine. It is the default for a fresh Apache install on a request for a simple static file, for example. -Rasmus Christian Schneider wrote:

Christian Schneider

19 years ago
Rasmus Lerdorf wrote:
> Replying to a 1.0 request with a 1.1 response is perfectly fine. > It is the default for a fresh Apache install on a request for a > simple static file, for example.
This seems bogus to me. Quoting from the very last line of the HTTP RFC 3.6 Transfer Codings: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6 "A server MUST NOT send transfer-codings to an HTTP/1.0 client." Now if all the Apache requirements for chunked encoding match (apart from the request originally being a HTTP/1.0 one) then this will lead to a Transfer-Encoding: chunked being sent to the client. Which violates the RFC and breaks clients like wget, php and other simple clients not expecting a chunked response. On top of that http://www.ietf.org/rfc/rfc2145.txt states in section 2.3 that "An HTTP server SHOULD send a response version equal to the highest version for which the server is at least conditionally compliant, and whose major version is less than or equal to the one received in the request." It doesn't seem to be a problem with static files as it won't send a chunked response if it knows the length and hence can send a Content-Length header. Still a violation of the RFCs IMHO though. On the other hand I see no reason to upgrade a reponse to HTTP/1.1 when HTTP/1.0 was requested. Regards, - Chris

Christian Schneider

19 years ago
Christian Schneider wrote:
> version for which the server is at least conditionally compliant, and > whose major version is less than or equal to the one received in the > request."
Oops, missed the "major" version part there. Sorry for that, should read things more carefully, especially at 1:30am :-) I still think it breaks the other RFC though. And it definitely breaks some HTTP/1.0 clients if chunked transfer is done because of upgrading the response. - Chris

Rasmus Lerdorf

19 years ago
Christian Schneider wrote:
> Christian Schneider wrote: >> version for which the server is at least conditionally compliant, and >> whose major version is less than or equal to the one received in the >> request." > > Oops, missed the "major" version part there. Sorry for that, should read > things more carefully, especially at 1:30am :-) > > I still think it breaks the other RFC though. And it definitely breaks > some HTTP/1.0 clients if chunked transfer is done because of upgrading > the response.
This came up many times on the Apache lists years ago, and Roy Fielding who wrote that spec repeatedly said it was fine to reply with a 1.1 response to a 1.0 request. -Rasmus

Oliver Block

19 years ago
Am Dienstag, 1. Mai 2007 01:49 schrieb Rasmus Lerdorf:
> This came up many times on the Apache lists years ago, and Roy Fielding > who wrote that spec repeatedly said it was fine to reply with a 1.1 > response to a 1.0 request.
Did he give any rationale for his view? Regards, Oliver

Rasmus Lerdorf

19 years ago
Oliver Block wrote:
> Am Dienstag, 1. Mai 2007 01:49 schrieb Rasmus Lerdorf: > >> This came up many times on the Apache lists years ago, and Roy Fielding >> who wrote that spec repeatedly said it was fine to reply with a 1.1 >> response to a 1.0 request. > > Did he give any rationale for his view?
Go read the archives. And note that I only said it was fine to respond with a 1.1 reply, that doesn't mean it is fine to send an encoding the client doesn't support. -Rasmus

Christian Schneider

19 years ago
Rasmus Lerdorf wrote:
> Go read the archives. And note that I only said it was fine to respond > with a 1.1 reply, that doesn't mean it is fine to send an encoding the > client doesn't support.
That's why I think PHP shouldn't mess with the proto_num field or otherwise upgrade the HTTP version of the response because it makes Apache believe it is safe to send a chunked response if it wants to. And I don't see any benefit in doing so. I'd be interested to learn why this was done though. My assumption so far is that it's done "because the PHP script asked for HTTP/1.1 so we should try to send that back" without considering the danger of creating a chunked response as a side effect. Regards, - Chris

Oliver Block

19 years ago
Am Dienstag, 1. Mai 2007 02:22 schrieb Rasmus Lerdorf:
> Oliver Block wrote: > And note that I only said it was fine to respond > with a 1.1 reply, that doesn't mean it is fine to send an encoding the > client doesn't support.
Well. Regards, Oliver

Uwe Schindler

19 years ago
> -----Original Message----- > From: Rasmus Lerdorf [mailto:rasmus@lerdorf.com] > Sent: Tuesday, May 01, 2007 2:22 AM > To: Oliver Block > Cc: internals@lists.php.net > Subject: Re: [PHP-DEV] Setting HTTP results code vs. HTTP type > > Oliver Block wrote: > > Am Dienstag, 1. Mai 2007 01:49 schrieb Rasmus Lerdorf: > > > >> This came up many times on the Apache lists years ago, and Roy Fielding > >> who wrote that spec repeatedly said it was fine to reply with a 1.1 > >> response to a 1.0 request. > > > > Did he give any rationale for his view? > > Go read the archives. And note that I only said it was fine to respond > with a 1.1 reply, that doesn't mean it is fine to send an encoding the > client doesn't support.
And that's exactly what other web servers also do: I come from Sun One Web Server 6.1 and 7.0), so I can tell what they do: They respond always with HTTP/1.1 but if the request came in with HTTP/1.0 they do not use chunked encoding for the reply and use "Connection: close". Uwe

Oliver Block

19 years ago
Hello Rasmus, Am Dienstag, 1. Mai 2007 01:05 schrieb Rasmus Lerdorf:
> Replying to a 1.0 request with a 1.1 response is perfectly fine.
I doubt that it is standard conformant. HTTP/1.0 doesn't even know chunked data (RFC1945). Best Regards, Oliver

Uwe Schindler

19 years ago
> - Update the PHP header() documentation to mention this. I was also > thinking that supporting/documenting header(null, true, 404); or the > like would be nice for people who only want to set the return code and > leave the HTTP type unchanged.
I think this would bet he best approach, to give the PHP a users a _consistent_ way (consistent through all SAPIs) to set the http response code without changing protocols. Your problem only occurs with apache, as apache gives PHP the possibility to change the HTTP protocol version. Other SAPIs, like my NSAPI one, cannot do this because the protocol is the servers task and modules are not allowed to change it in a wrong way. The problem with setting the response code is: * Some PHP scripts use header('Status: 301') to set response code. Problem here: This only works with CGI and Apache. The problem here is in PHP SAPI code: PHP only checks for ('HTTP/...') header strings and extracts status code and protocol version from it. The string 'HTTP/..' is never send to the SAPI. In case of 'Status: ', SAPI sends the header as a _normal_ HTTP header to the webserver -> Apache maps this, CGI also because specs want this. * Some scripts use header('HTTP/1.0 301 Moved Permanently'). Problem here: You must supply a HTTP version (this seems to be a problem in Apache), and you must supply the textual representation (but most/all? SAPIs ignore the textual representation). So header('HTTP/1.0 301 X') would be OK. What we need is: 1) a consistent parsing of header() inputs before sending to the underlying SAPI. This means also parsing for 'Status: XXX' and setting the status code. The later SAPI then will generate the correct parameters to be sent to the server (in case of CGI it will "regenerate" a Status:-header). 2) a function to simply set the status code without changing anything other. 1. supplies such a method with 'Status: 301' if it is correctly implemented. If nobody is against it I would try to implement a consistent header parsing for SAPI...

Christian Schneider

19 years ago
Uwe Schindler wrote:
> * Some scripts use header('HTTP/1.0 301 Moved Permanently'). Problem here: > You must supply a HTTP version (this seems to be a problem in Apache), and
This is not necessarily a problem with Apache, it is just a problem in the current implementation as far as I can tell. If the Apache2 SAPI would not try to change the HTTP version of the Apache request structure (or only downgrade it, never upgrade it) then no problem would arise. Therefore I was hoping that this could be treated as a bug fix and be done in 5.2.3 or even 5.2.2. - Chris

Michael Wallner

19 years ago
Uwe Schindler wrote:
> What we need is: > 2) a function to simply set the status code without changing anything other.
There's a (external) function: http://php.net/manual/en/function.http-send-status.php ...and for the unlucky: header("Dummy:", true, $status_code); But if your patch makes sense, I'm all for it! ;) Regards,
-- Michael