Send valid HTTP status headers with PHP-CGI

plach - September 15, 2007 - 11:14
Project:Drupal
Version:7.x-dev
Component:base system
Category:bug report
Priority:normal
Assigned:Unassigned
Status:needs work
Description

This is somewhat a re-issue (hope this won't sound annoying) as I found this problem already treated in some of his aspects here:

http://drupal.org/node/81752
http://drupal.org/node/64645
http://drupal.org/node/117756
http://drupal.org/node/6678

Going straight to the point, the root problem is that if PHP is using the CGI/FastCGI server API to interface itself with the web server, the HTTP status header will not be correctly set. This is due to the CGI specification which does not allow directly setting the HTTP status code
(see http://cgi-spec.golux.com/draft-coar-cgi-v11-03.txt, section 7.2.1.3).

This fact leds to multiple problems on a CGI-based system:
- [SEO] 404 pages, 403 pages and 503 pages have 200 OK status (bad, multiple URLs with the same content)
- [user] 401 pages do not cause the browser to show up the authentication dialog
- [user] 304 pages display nothing (I think this is the cause of many of the Blank pages - The White Screen of Death)
And so on...

Someone was pointing out this is not a Drupal bug but a PHP one, and that using CGI sapi is a poor choice under the performance aspect. I agree, but not always we can choose our system. I think the more Drupal is adaptable to system configurations the better is.
By the way, one of the most popular hosting solutions provider in Italy is using this configuration and I do not think I am the only one that has experienced this kind of problems.

I am providing a patch with my solution but I am pretty new to Drupal and I am sure that a real D-guy can find one better ;)

AttachmentSize
includes_4.patch6.82 KB

#1

plach - September 15, 2007 - 15:37
Priority:critical» normal

Sorry, I have just read the priority guidelines...

#2

moshe weitzman - September 15, 2007 - 16:09
Status:needs review» needs work

Looks good.

Seems like you should use drupal_set_header within the new drupal_http_status().

#3

plach - September 15, 2007 - 16:48

this is exactly the kind of good advice I needed, thank you :)

here's the revised patch

AttachmentSize
175855.patch 0 bytes

#4

plach - September 15, 2007 - 16:51

the revised patch

AttachmentSize
175855_0.patch 6.95 KB

#5

moshe weitzman - September 15, 2007 - 19:38
Status:needs work» needs review

#6

drumm - September 17, 2007 - 00:44
Version:5.2» 6.x-dev

I would like to see this API change get into Drupal 6.x before consideration in 5.x.

#7

Gábor Hojtsy - September 17, 2007 - 08:50
Status:needs review» needs work

- Please do the diff with diff -up, so we see where the changes take effect.
- Please observe coding standards about concatenation, eg. look inside drupal_http_status(), things shuld be like .' '. without the spaces)
- Also look at phpdoc formatting conventions and use that: one line function summary at the start, @param broken to multiple lines
- Your second drupal_http_status() call seems to be badly indented

Apart from these, the code generally looks good, and reminds me of the approach we took on php.net, when I was active in the webmaster team.

#8

plach - September 17, 2007 - 12:10

I had to move the new drupal_http_status() function into bootstrap.inc in order to make 304 and 403 calls to work: in those cases the function (as the old code) uses the native header() function. I tested the patched code on both PHP Server APIs and it seems to work correctly. The tests were conducted on a plain 5.2 installation and on a plain HEAD installation.

@drumm: I am attaching a 6.x version of the patch.

@Gábor Hojtsy: I am using TortoiseCVS to make the patches and it actually uses diff -u. I corrected the source following your advices, I think it is ok now.

AttachmentSize
175855-head.patch 7.24 KB

#9

plach - September 17, 2007 - 12:12
Status:needs work» needs review

here is the 5.2 version

AttachmentSize
175855-5.2.patch 7.26 KB

#10

plach - September 17, 2007 - 15:46

and here is the diff -up version

AttachmentSize
175855-head_0.patch 7.59 KB

#11

plach - September 21, 2007 - 13:36

Any feedback out there?

#12

plach - October 6, 2007 - 11:15

Again, anyone available to review the code?

#13

plach - October 8, 2007 - 09:30

this an updated patch against the HEAD

AttachmentSize
175855-head_1.patch 7.59 KB

#14

Pancho - February 3, 2008 - 14:42

Still to be considered for D6.
Patch was broken by centralizing _db_error_page() to database.inc.
Rerolled the patch against HEAD. Didn't test it on CGI/Fast-CGI though.

AttachmentSize
http_header_175855_14.patch 4.65 KB

#15

Pancho - February 3, 2008 - 15:01

Slightly modified patch:

  • Renamed drupal_http_header() to drupal_set_http_header(), to be more descriptive.
  • Improved PHPdoc.
  • Minor code style.
AttachmentSize
http_header_175855_15.patch 4.7 KB

#16

Dave Reid - October 7, 2008 - 23:21
Status:needs review» needs work

This hasn't been bumped in a while, and after my attempt to get this fixed in #81752: Incorrect headers when using PHP as CGI, this would probably best be fixed by modifing the $_SERVER['SERVER_PROTOCOL'] variable to "Status:" within drupal_initialize_variables.

#17

Dave Reid - October 7, 2008 - 23:39
Title:HTTP status header and CGI server api» Send valid HTTP status headers with PHP-CGI
Status:needs work» needs review

Here's a patch that doesn't require a new function and only makes the change in the drupal_initialize_varibables function.

AttachmentSize
cgi-headers-175855-D7.patch 906 bytes
Testbed results
cgi-headers-175855-D7.patchre-testing

#18

earnie - October 8, 2008 - 10:53

@Dave Reid: Is this patch for D7 as it indicates in the file name? If so, please change the version to indicate that.

#19

Dave Reid - October 8, 2008 - 15:02
Version:6.x-dev» 7.x-dev

Thanks earnie, I overlooked that.

#20

System Message - November 16, 2008 - 21:45
Status:needs review» needs work

The last submitted patch failed testing.

#21

Dave Reid - November 17, 2008 - 03:58
Status:needs work» needs review

Failed due to #74645: modify file_scan_directory to include a regex for the nomask.. Setting back to code needs review.

#22

c960657 - November 18, 2008 - 17:28

Isn't this fixed by adjusting cgi.rfc2616_headers? As you can see in the PHP source code, PHP already translates the status code into a Status: header (the linked source is that of PHP 5.2.0 - it has been updated several times since then).

If adjusting cgi.rfc2616_headers does not fix the problem, what is the PHP bug number? There are a number of bugs that sound like this that have already been fixed in recent PHP versions.

#23

catch - January 17, 2009 - 20:39
Status:needs review» needs work

We need a comment here to the PHP bug number so we can remove the workaround later on when it's fixed (if it hasn't been already).

#24

toomanypets - April 5, 2009 - 13:25

I just spent far too many hours tracking this problem down with D6.1 in a CGI/FastCGI environment. In this case users were getting 500's instead of 404's. I do not believe this is a PHP bug. While setting cgi.rfc2616_headers to 0 in php.ini resolves the problem, this workaround is impractical for many who do not have access to php.ini, or who can't override php.ini settings in an .htaccess file. Additionally, it seems to me that making the headers non-compliant is (a) counter-intuitive and (b) may break other applications.

Until a permanent fix is available, I hacked the /includes/common.inc file as suggested in many other posts, but this only addresses 404 problems:

function drupal_not_found() {
  if ((substr(php_sapi_name(),0,3)=='cgi')&&(ini_get('cgi.rfc2616_headers')=='1')) {
  drupal_set_header('Status: 404 Not Found');
    }
  else {
    drupal_set_header('HTTP/1.1 404 Not Found');
  }

#25

kenorb - May 17, 2009 - 13:44

Similar problem.
The same website with the same code, but different responses:

GET /b1 HTTP/1.1
Host: host_with_php-cgi5

HTTP/1.1 404 Not Found
Date: Sat, 16 May 2009 03:43:06 GMT
Server: Apache/1.3.33
X-Powered-By: PHP/5.2.10-dev
Set-Cookie: SESSd62a0dd407ed7b169d8e935e80db7b4c=c2dbcf35da8c545d04866f51d241ecb9; expires=Mon, 08-Jun-2009 07:16:33 GMT; path=/; domain=. example.com
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Sat, 16 May 2009 03:43:13 GMT
Cache-Control: store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
Cache-Control: max-age=1209600
Expires: Sat, 30 May 2009 03:43:06 GMT
Location: http://example.com/new_location
Transfer-Encoding:
chunked
Content-Type: text/html; charset=utf-8

Tested with PHP 5.2.8, 5.2.9 and latest CVS snapshot

GET /b1 HTTP/1.1
Host: host_with_mod_php4

HTTP/1.1 301 Moved Permanently
Date: Sat, 16 May 2009 03:44:33 GMT
Server: Apache/1.3.33
Cache-Control: store, no-cache, must-revalidate
Expires: Sun, 19 Nov 1978 05:00:00 GMT
X-Powered-By: PHP/4.3.10
Set-Cookie: SESSdfdd77ce611e8b8fa2de6ee9fb8957a7=98af664c1448c514cf1f2c50e4c41c0e; expires=Mon, 08-Jun-2009 07:17:59 GMT; path=/; domain=.example.com
Last-Modified: Sat, 16 May 2009 03:44:39 GMT
Cache-Control: post-check=0, pre-check=0
Location: http://example.com/new_location
Transfer-Encoding:
chunked
Content-Type: text/html; charset=utf-8

There is something wrong with headers when using php-cgi
I even can't log in.

Tested on Drupal 6.11
Fix in #24 fixed only Page Not Found, but there are some problem with redirection as well.

Voting for patch #24 to be in the core.

#26

kenorb - May 16, 2009 - 17:49
 
 

Drupal is a registered trademark of Dries Buytaert.