6

When I set a custom header in Apache + mod_php5, this works fine:

header('Foo: Bar');

But when I try this while also sending a 304 Not Modified response, the header appears to be removed by apache (along with X-Powered-By and other standard headers).

header('HTTP/1.1 304 No Content');
header('Foo: Bar');

Does anyone know how to solve this issue?

Evert
  • 93,428
  • 18
  • 118
  • 189
  • I'm not quite sure how to read the [RFC](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5) on this one. Could it be that Apache removes the headers to comply with the RFC (and aid cache managers)? Perhaps you can make sense of it? – jensgram Jun 27 '11 at 10:26
  • I know the RFC's fairly well, and it doesn't impose a restriction. It does mention certain headers should be there (mainly the cache-related ones). In my case I need to add CORS headers, for cross-domain access.. – Evert Jun 27 '11 at 10:28
  • Try this one instead of 2: `header('Foo: Bar', true, 304);`. As for the _"the header appears to be removed by apache"_ -- you will need to show your apache config (`httpd.conf`, your `` as well as `.htaccess` -- these instructions can be anywhere. – LazyOne Jun 27 '11 at 10:28
  • LazyOne: Trying that header() syntax results in the same issue. As for configuration, I'm using 100% default configuration on Ubuntu and neither a virtualhost nor .htaccess. I thought it was also notable that even X-Powered-By was removed. I know your name is lazy, but try it on your own system, I'm sure you'll see the same thing. – Evert Jun 27 '11 at 10:32
  • @Evert `X-Powered-By` may simply not be sent by PHP itself if `expose_php = Off` in php.ini. As for 304 -- I re-run few tests (after my initial comment) and yes -- custom header got removed for 304, but is present for 404 and other non 3xx codes (checked with 302, 303, 305, 306). Must be 304-specific optimisation (304 = Not Modified) where response body must be as small as possible. – LazyOne Jun 27 '11 at 10:47
  • Yea I just added the note about X-Powered-By because it specifically got removed for 304's.. This was my first indicator this was Apache's doing. Thanks for checking though =) – Evert Jun 27 '11 at 11:08

4 Answers4

3

As of Apache 2.4.23 (the latest release as of today, as far as I know), you're not going to be able to get around that problem when you send a 304 "Not Modified" response because, indeed, Apache does explicitly remove all non-whitelisted headers:

http://svn.apache.org/viewvc/httpd/httpd/tags/2.4.23/modules/http/http_filters.c?view=markup#l1331

So, whether we like it or not (because I'm on the same boat of having my CORS headers removed by Apache from the response when I send a 304), it does seem like Apache is following the RFC recommendation and it's indeed treating everything that falls outside of that list as entity headers.

One solution is to patch-up the Apache source to extend that list and turn to deploying your home-grown package to your server(s), but that's definitely not without a long list of implications of its own. On the flip side, I hear that nginx doesn't suffer from this problem.

The content that I'm delivering will be consumed, among others, by WebGL runtimes in standard browsers, so if they do complain about the lack of CORS in my 304 responses I'm going to have to turn everything to 200 OK and forego the bandwidth savings.

3

Does this not answer the question?

If the conditional GET used a strong cache validator (see section 13.3.3), the response SHOULD NOT include other entity-headers. Otherwise (i.e., the conditional GET used a weak validator), the response MUST NOT include other entity-headers; this prevents inconsistencies between cached entity-bodies and updated headers.

from http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5

Ben
  • 1,525
  • 11
  • 19
  • 3
    I'm not sure CORS headers (which is what I'm actually trying) are considered 'entity-headers', but regardless I'd expect that I'd be able to add in any additional headers if I want to. Specifically I need the CORS headers to avoid browser-errors. So it doesn't answer the question, because it doesn't solve my problem. – Evert Jun 27 '11 at 11:04
  • @Evert Maybe you could update your question to mention that your sending CORS headers (i did spot it in the comments though). Also what browser problems are you having? It seems to me that you are trying to do something that shouldn't be possible and is been prevented by the web server. – Ben Jun 27 '11 at 11:36
  • It's with Firefox 5, but that's a bit aside the point. All I care about is being able to set a custom header, while also sending back a 304 status code. Nothing in the HTTP spec prevents this. – Evert Jun 27 '11 at 11:44
  • @Evert unrecognised headers are treated as entity-headers. http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html – Ben Jun 27 '11 at 11:48
  • They may be treated as entity-headers but the specification also says 'SHOULD' be removed, not 'MUST'. But aside from that, I really don't care about the specification; I just want to fix my bug ;) – Evert Jun 27 '11 at 11:51
  • @Evert in your code do you always want the addtional header to be `Foo: Bar` or does that value change dynamically? If not I managed to get that working. For some reason I also have the X-Powered-By regardless of sending a 304. – Ben Jun 27 '11 at 12:09
0

I do a trick to solve this issue by : 1. put all header before 304 header 2. flush these header before send 304

header('Foo: Bar');
flush();
header('HTTP/1.1 304 No Content');

Apache will not remove any header until it found 304. We force other header send out by flush() before send 304. That apache can not hurt me.

Chanatip Yim
  • 356
  • 1
  • 3
  • 11
-1

Try:

header('Foo: bar', true, 304);
Brian
  • 8,418
  • 2
  • 25
  • 32