Apache 2.2 conditional headers on response - apache

I am trying to configure apache to send expires and cache-control headers on response but only if I receive some specific query string on the request.
For this I've tried configuring the server as follows:
RewriteCond %{QUERY_STRING} ^.*{whateverIWantInMyQueryString}.*$
RewriteRule ^(.*)$ - [env=CACHE_HEADERS:1]
<FilesMatch "\.(js|css|png|gif|GIF)$">
<IfDefine CACHE_HEADERS>
ExpiresActive On
ExpiresDefault "access plus 12 hours"
Header append Cache-Control "public"
</IfDefine>
</FilesMatch>
But this does not seem to work.
If I change the configuration as follows:
....
<IfDefine !CACHE_HEADERS>
....
It does work, so it seems IfDefine is not able to check that CACHE_HEADERS environment variable is being set.
I've also tried configuring things with Header directive and conditional based on the same environment variable using something like this:
RewriteCond %{QUERY_STRING} ^.*{whateverIWantInMyQueryString}.*$
RewriteRule ^(.*)$ - [env=CACHE_HEADERS:1]
<FilesMatch "\.(js|css|png|gif|GIF)$">
Header always set Cache-Control "max-age=3600, public" env=CACHE_HEADERS
Header always set Expires "Thu, 01 Jan 2015 00:00:00 GMT" env=CACHE_HEADERS
</FilesMatch>
.....
But this does not work either. So I am assuming this might be because of the environment variable that is being set by mod_rewrite, that for some reason is not being detected by neither IfDefine directive nor Header directive.
Does anyone know what may be causing this or why is this not working at all?

The reason why IfDefined is not working you can find here: Apache IfDefine conditionals in .htaccess
Basically it's that IfDefined only evaluates variables defined at command line not if you define them like you did or with SetEnv or SetEnvIf.
However as far as I know env= should work.

Related

Allow Access-Control for Subdomain in .htaccess

Having issues setting up a generic Allow Origin for any subdomain in my .htaccess file. The following works for a singular subdomain:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin http://subdomain.website.com
</IfModule>
But what I am looking for is something similar to this:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin {ANY SUBDOMAIN}.website.com
</IfModule>
I have tried using a simple *.website.com wildcard, but that does not seem to work. Do you have to specify exactly what is coming in?
If you're looking to do it for whatever subdomain was being requested, try the following:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin %{HTTP_HOST}
</IfModule>
If you need something more advanced, use mod_rewrite to set an environment variable and then refer to it using %{variable_name}e

Debugging .htaccess

A few days ago I had a problem with writing my first htaccess in order to remove .html extension from URL. There were problems because I had a Windows server which I changed to Linux.
Now the issue is this:
I finally did manage to remove the .html extension from URL. What I can't do is to set an expiration date for all images (JPEG, PNG, SVG).
My working code is this (extension removal):
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]
For Image caching parameter I added the following:
//Caching schema
<FilesMatch "\.(jpg|png|svg)$">
Header set Cache-Control "private, max-age=160704000"
</FilesMatch>
When I added the additional code above I got an internal server error.
I don't know what's going on to be honest. If I remove this additional code it will work but if I add this then it wont.
So do you guys have any ideas of how to add an Image caching parameter?? The additional code above doesn't work :(
UPDATE
After some research I tried this one:
<ifModule mod_headers.c>
ExpiresActive On
# Expires after 1 month
<filesMatch ".(gif|png|jpg|jpeg|ico|pdf|js|htm|html|txt)$">
Header set Cache-Control "max-age=2592000"
</filesMatch>
# Expires after 1 day
<filesMatch ".(css)$">
Header set Cache-Control "max-age=86400"
</filesMatch>
</ifModule>
Surprisingly this works. I tested it with gtmetrix.com .You think I should move forward now?
Set AllowOverride All in your server config for the host. Do this for the directory where your htaccess resides rather than the whole server, e.g.
<Directory /var/www/html/mysite/>
AllowOverride All
</Directory>
The issue is that your syntax is valid, but the server is refusing to process the request because AllowOverride is set to something other than 'All' which is what FilesMatch requires.
If you don't want to set AllowOverride to All for the .htaccess file, then you could move the <FilesMatch> statement into the host configuration for your site and it will work from there.

htaccess env variable and headers

I am trying to add an Access-Control-Origin header in .htaccess for all URIs ending with .json. I cannot use <FilesMatch> as my paths are rewritten by mod_rewrite. (Or if I can it doesn't work.)
I found on Stack that it should be possible to do it with an env variable:
<IfModule mod_headers.c>
SetEnvIf Request_URI "\.json$" IS_JSON=TRUE
# ".json$" yields the same result
Header set Access-Control-Allow-Origin "*" env=IS_JSON
# "Header add" yields the same result
</IfModule>
But it does never add the header.
I tried using a snipper from another stack answer to check if the env variable is there using:
RewriteCond %{REQUEST_URI} !echo.php
RewriteRule .* echo.php?uri=%{REQUEST_URI}&json=%{ENV:IS_JSON} [L]
And it really was true.
When I remove the condition and leave it as:
Header set Access-Control-Allow-Origin "*"
the header is added, so the mod is loaded, but I would like to limit it for ".json$" only.
What am I doing wrong?
Instead of Header you probably meant to use RequestHeader to send custom headers to your code
SetEnvIf Request_URI \.json$ IS_JSON
RequestHeader set Access-Control-Allow-Origin "*" env=IS_JSON

".htaccess" doesn't work for cache-control at sub directories

I made my own cache-control rule in httpd.conf. ANd need to apply different rules on each different sub directories.
I made no-cache for .do extension for default(httpd.conf).
# use .htaccess files for overriding,
AccessFileName .htaccess
...
<ifModule mod_headers.c>
<LocationMatch "\.(do)$">
Header append Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
</LocationMatch>
</ifModule>
And need to cache for some directories(.htaccess).
example URL : XXX.com/en/product.do
So I made a .htaccess on <webRoot>/en.
<ifModule mod_headers.c>
<LocationMatch "\.(do)$">
Header set Cache-Control "max-age=216000, public, must-revalidate"
</LocationMatch>
</ifModule>
Am I going wrong? Is there other way to rule different on different directories?
Nothing like <locationMatch> can be used in .htaccess; it will generate a runtime error.
Also, usually *.do is proxied, in which case no filesystem directory would ever be read for .htaccess.
I suggest putting the second stanza first, and adding ^/en/ to the front.

Apache: apply rules to a URL before they're rewritten

I have a simple RewriteRule:
RewriteRule ^/r/[0-9]+/(.*)$ /$1
This is used for cache-busting. With every web site release I change the url prefix, e.g.:
/r/17/img/image.jpg gets /img/image.jpg.
I want to apply long expiry headers to these for example
<Directory /r>
Header unset ETag
FileETag None
ExpiresDefault "access plus 1 year"
</Directory>
Of course this doesn't work because after the RewriteRule is applied, the Directory doesn't match anymore.
How can I apply these rules inside the Directory directive to URLs accessed via /r/ ?
Thanks!
The <Directory> directive is for actual existing directories and not just URL paths. Try <LocationMatch> instead:
<LocationMatch "^/r(/|$)">
Header unset ETag
FileETag None
ExpiresDefault "access plus 1 year"
</LocationMatch>
Or change /r to your actual directory /img.