mod_rewrite is supposed to append to the Vary HTTP response header any HTTP request headers used in RewriteCond statements. This doesn't seem to work. Relevant conf: <Directory ${docroot}/js> ExpiresActive On ExpiresDefault "access plus 30 minutes" SetEnvIf Via AkamaiGHost VIA_AKAMAI_EDGE # ch.8 of Edge Server Config Guide # Only set Edge-Control if via Akamai Edge server, so as to # not increase size of response to non-Akamai clients Header set Edge-Control max-age=1800 env=VIA_AKAMAI_EDGE FileETag MTime Size RewriteEngine On RewriteCond %{HTTP:Accept-Encoding} (^|,)\s*(x-)?gzip(?!\s*;\s*qs\s*=\s*0([.]0{0,3})?(\s|,|$)) RewriteRule (.*)[.]js$ $1.js.gz </Directory> And the response headers I get back: HTTP/1.1 200 OK Date: Fri, 01 Feb 2013 21:41:30 GMT Server: Apache/2.4.3 Last-Modified: Wed, 09 Jan 2013 16:57:50 GMT ETag: "1a27-4d2ddf660ff80" Accept-Ranges: bytes Content-Length: 6695 Cache-Control: max-age=1800 Expires: Fri, 01 Feb 2013 22:11:30 GMT P3P: CP="CAO DSP COR CURa ADMa DEVa PSAa PSDa IVAi IVDi CONi OUR OTRi IND PHY ONL UNI FIN COM NAV INT DEM STA" Content-Type: application/javascript Content-Encoding: application/gzip I have a workaround of adding these two lines to the Directory section: SetEnvIf Accept-Encoding (^|,)\s*(x-)?gzip(?!\s*;\s*qs\s*=\s*0([.]0{0,3})?(\s|,|$)) VARY_ACCEPT_ENCODING Header append Vary Accept-Encoding env=VARY_ACCEPT_ENCODING Then I get back: HTTP/1.1 200 OK Date: Fri, 01 Feb 2013 21:42:53 GMT Server: Apache/2.4.3 Last-Modified: Wed, 09 Jan 2013 16:57:50 GMT ETag: "1a27-4d2ddf660ff80" Accept-Ranges: bytes Content-Length: 6695 Cache-Control: max-age=1800 Expires: Fri, 01 Feb 2013 22:12:53 GMT Vary: Accept-Encoding P3P: CP="CAO DSP COR CURa ADMa DEVa PSAa PSDa IVAi IVDi CONi OUR OTRi IND PHY ONL UNI FIN COM NAV INT DEM STA" Content-Type: application/javascript Content-Encoding: application/gzip But adding these extra two lines of config should not be necessary, because mod_rewrite is supposed to do it. I see the code in the module (high-level part pasted below), but it doesn't seem to be doing it. ctx->vary = NULL; rc = apply_rewrite_rule(p, ctx); if (rc) { /* Regardless of what we do next, we've found a match. Check to see * if any of the request header fields were involved, and add them * to the Vary field of the response. */ if (ctx->vary) { apr_table_merge(r->headers_out, "Vary", ctx->vary); } The rewrite rule itself is working; the response has the content-encoded application/gzip file of 6695 bytes. When I do a request with no Accept-Encoding: gzip header, I get the uncompressed file and response: HTTP/1.1 200 OK Date: Fri, 01 Feb 2013 21:41:06 GMT Server: Apache/2.4.3 Last-Modified: Wed, 09 Jan 2013 16:57:48 GMT ETag: "523d-4d2ddf6427b00" Accept-Ranges: bytes Content-Length: 21053 Cache-Control: max-age=1800 Expires: Fri, 01 Feb 2013 22:11:06 GMT P3P: CP="CAO DSP COR CURa ADMa DEVa PSAa PSDa IVAi IVDi CONi OUR OTRi IND PHY ONL UNI FIN COM NAV INT DEM STA" Content-Type: application/javascript It's just the adding of the Vary header which is not working in the mod_rewrite module.
In directory context, action flags AND a substitution together don't work because it is not carried forward for the "internal redirect" used to change the URL. Output headers specifically are not preserved across an "internal redirect". Your best bet is configuring this outside of <Directory> context.
I moved all my RewriteRules (and RewriteConds) out of Directory context, and edited them for the server context, and it now works. I see now that Directory context runs in a totally different phase of request processing; the fixup phase instead of the uri2name phase, and that the fixup phase processing does an ap_internal_redirect if you rewrite the url, and therefore the request parsing phase is done over again in the subrequest, and from what you said, response headers are reset for the subrequest. I would guess that this would mean that in Directory context, not only setting the Vary header from RewriteCond's %{HTTP:header} processing wouldn't work, but probably also the cookie|CO flag and perhaps the type|T flag would not work. I think it'd be a good idea to add documentation about this to: 1. RewriteCond's %{HTTP:header} documentation. 2. RewriteRule's "Per-directory Rewrites" documentation. 3. RewriteRule's flags documentation for each flag that won't work in Directory context.