2

I just realized my apparent problem (and the "solution" Content-Encoding: none from the StackOverflow question I referred to in my initial question, below) may very well have simply been due to a misunderstanding how things are actually working. Please review my addendum at the end.


In a PHP application I'm building, I'm trying to manage my own content-encoding negotiation and compression.

When I set the response header Content-Encoding from within PHP to either gzip or deflate, Apache respects this. However, when I set it to identity Apache ignores this and compresses the response.

It only seems to respect the non-standard Content-Encoding: none, as I found in some of the answers and their comments in this Stack Overflow question.

I'm therefore currently setting it to none, from within PHP and then altering the header through .htaccess with:

Header edit Content-Encoding ^none$ identity

... but this really feels like an ugly hack. I wish I didn't have to do this, in case I ever switch servers, for instance.

Is this a known issue and/or is this non-standard behavior documented somewhere? I can't seem to find any concrete documentation about this.

I've also searched Apache's bug tracker, but was only able to find a tangentially related bug report, about Apache not respecting Accept-Encoding header values.


Addendum

When I disable Apache's mod_deflate in .htaccess with (there are other options available to do this as well):

SetEnv no-gzip 1

... and set Content-Encoding: identity from within PHP, Apache keeps this header and the content intact, just fine.

Therefore, here's what I think is actually happening:

It's not that Content-Encoding: none is some official signal to Apache to disable compression (Content-Encoding: bogus, for instance, produces the same result), which would explain why I couldn't find any documentation about it.

Rather, it is simply a value that is not an RFC standard. Therefore mod_deflate leaves the content untouched, assuming it's some non-standard encoding it doesn't want to interfere with.

So, when I set Content-Encoding: identity from within PHP, mod_deflate probably recognizes this as a valid RFC standard, signifying that content has not been compressed yet and, since mod_deflate is enabled, goes ahead and compresses it.

Furthermore, if I set Content-Encoding to gzip or deflate, for instance, mod_deflate probably either leaves it untouched completely, or tries to compress it anyway, but the compression algorithm recognizes that the content was already compressed.

Can somebody perhaps confirm whether this is a correct interpretation of what is actually going on?


So, a possible solution would be to either disable mod_deflate for some selected files/paths that my PHP application manages, or perhaps even disable mod_deflate altogether/site-wide/server-wide if all my content was already compressed in some other way.

Decent Dabbler
  • 169
  • 1
  • 1
  • 8

1 Answers1

0

So, I've managed to solve my issues, by taking into account the assumptions I've outlined in my question, which appear to be correct. But not without a struggle.

On trying to implement it for only PHP-generated content, I ran into some other issues, which I'll describe here:

I initially had the following rewrite rules in my .htaccess:

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^.*$ - [NC,L]

RewriteRule ^.*$ index.php [NC,L]

With RewriteRule flags, you should be able to set environment variables. So, I figured I should be able to set the E=no-gzip:1 flag on merely the last RewriteRule, by doing:

RewriteRule ^.*$ index.php [NC,E=no-gzip:1,L]

And even though the earlier mentioned

SetEnv no-gzip 1

worked fine, the RewriteRule flag just wouldn't catch on. Then I looked into all sorts of related questions on Stack Overflow, such as this one this one. But they didn't offer satisfactory solutions.

I then momentarily resorted to setting the environment variable from within PHP with apache_setenv( 'no-gzip', 1 );, which did the trick. But that just didn't feel right and also made me wonder why the damn RewriteRule flag wouldn't work just as well.

I then decided to do a var_dump( $_SERVER ), to see whether the RewriteRule flag was actually set, only to be confronted with an old nemesis I had forgotten about:

array(39) {
  ["REDIRECT_no-gzip"]=>
  string(1) "1"
  ["REDIRECT_APP_ENV"]=>
  string(11) "development"
  /* etc. */
}

The damn REDIRECT_ that gets prepended to environment variables when rewriting.

I was under the impression that the L flag on my last RewriteRule should mean stop rewriting, but apparently I had misinterpreted this rule and it's conditions:

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^.*$ - [NC,L]

Since RewriteRule ^.*$ index.php [NC,E=no-gzip:1,L] rewrites to index.php, which is a regular file (-s), the aforementioned conditions and rule still kick in.

Now that I've changed that rule to

RewriteRule !^index.php - [NC,L]

everything is finally working as desired!

Decent Dabbler
  • 169
  • 1
  • 1
  • 8