3

I am having a little annoying situation here.

I have a server managed by plesk. In the /etc/apache2/apache2.conf mod_headers and mod_expires based configuration takes place. For example:

<filesMatch "\.(jpg|jpeg|png|gif|swf)$">
    Header set Cache-Control "max-age=604800, public"
</filesMatch>

This is working quite well.

I have a problem with some of my applications. I want to application to keep the control over cache if it wants to. Currently this is not possible, because header settings takes place emediatly before returning the response to the client, which means after the application has completeted all their actions. The headers set by the application will be overwritten.

Header merge Cache-Controll...

is not working though, because it just appends the given header string. And I doubt that browsers would handle headers like this one like I would like them to:

Cache-Control max-age=0, no-cache, no-store, must-revalidate, max-age=604800, public

My question now is: Is there a possibilty to set the header only if there is absolutly no content in the specific header "field"? I do not want my application to set any enviroment variables, because an application should not be changed to fit the needs of one server.

I also tried - for testing purpose only - to unset the header via vhost.conf for a specific domain. But it gets executed before the header setting in the apache2.conf, which means they would be overwritten, too.

sysadmin1138
  • 131,083
  • 18
  • 173
  • 296
func0der
  • 154
  • 4
  • 15

2 Answers2

7

Apache 2.4.7:

Header setifempty Access-Control-Allow-Origin "*"

Apache 2.2.4 below

Header append Access-Control-Allow-Origin ""
Header edit Access-Control-Allow-Origin "^$" "*"
Michael Hampton
  • 237,123
  • 42
  • 477
  • 940
Kangur
  • 231
  • 3
  • 6
  • This was useful for me. It appends an empty value to the header, then if the value matches an empty string, then it replaces the value with the star. – camomileCase Jan 05 '16 at 19:21
  • It appears edit expects the replacement to be a string, I'm trying to use an environmental variable (the request origin), not a "*" but it keeps interpreting it as a string ("%{origin_is}e"). Any way to get an environment variable in there? – chrismarx Sep 08 '16 at 13:07
  • I ended up using Header merge instead – chrismarx Sep 08 '16 at 14:39
  • @chrismarx will merge work if the value is already set to some domain? I'm afraid not. Could you post your solution as another answer? – Kangur Feb 24 '17 at 15:59
  • right, it won't, I was trying to solve the problem of only adding it if didn't already exist – chrismarx Feb 24 '17 at 22:48
  • The solution for Apache 2.2.4 and below listed here `Header append Access-Control-Allow-Origin ""` `Header edit Access-Control-Allow-Origin "^$" "*"` may have a side effect of appending `, ` to a non-empty header value because it's how `append` action works. It's the case, at least, in Apache 2.4.6. Try to experiment with the following `Header set Access-Control-Allow-Origin "*" "expr=-z %{req:Access-Control-Allow-Origin}"` if it suits your needs. – Artem Shafranov Feb 08 '21 at 17:03
3

I think you can pull this off using Header edit. The secret sauce is a negated look-ahead assertion:

Header edit Cache-control "^(?!.*max-age.*)(.*)" "max-age=604800,\1"

The idea is that the ^(?!.*max-age.*)(.*) matches the start of the header value if the string max-age does not exist anywhere in the header. If the match succeeds (meaning "max-age" does not already exist) it then inserts "max-age=604800," followed by the rest of the original header.

EDIT: Apache uses PCRE, so you might need to use $1 instead of \1 in the replacement string.

Insyte
  • 9,314
  • 2
  • 27
  • 45
  • Thanks. In that case i would have to write a really big regex if I want to match all the directives defined here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 Would it be possible to just put in "(?!.+)" to match an empty string and replace it with my wanted header values? – func0der Mar 05 '13 at 23:18
  • Do you need a general solution for all possible cache-control fields? If so, then my suggestion isn't a decent option. If, however, you need to be able to set a max-age and one or two other things, then this seems like a good approach. I don't understand your suggestion of `(?!.+)`, as it seems to me like that would never match. The ?! syntax is a negative look-ahead, described here: http://perldoc.perl.org/perlre.html#Look-Around-Assertions – Insyte Mar 06 '13 at 00:28
  • OK, ignore my last comment. I really don't understand what you're getting at. I interpreted your question to mean that you want to set a default "max-age" value (and some others) but only if that value was not already set in your application. If that is the case, then the negative look-ahead check only needs to look at the existing "Cache-control" header to see if the field it wants to set ("max-age" in my example) has already been set. If it has, it does nothing. If it hasn't, it inserts the new "max-age" value at the beginning of the line. – Insyte Mar 06 '13 at 00:35
  • My comment was misleading. I want to set the header only if there is absolutly no value set. No merging. – func0der Mar 06 '13 at 21:15
  • Nothing for the specific header field, like "max-age", or for the entire header ("cache-control") to be blank? If you only want Apache to set "max-age=blah" if the backend has not set a "max-age" header at all, then my suggested approach should work. – Insyte Mar 07 '13 at 06:00
  • I only want to set "Cache-Control" Header if it was not already set. Sorry, if I am may have been unclear :/ – func0der Mar 07 '13 at 11:15
  • Still there? No idea? – func0der Mar 13 '13 at 22:51
  • Yeah, sorry. I've poked around a bit and can't find a way to do this in Apache. In my network, I would accomplish this using a proxy server (Varnish) in front of Apache. Proxy servers make response header manipulation trivial. – Insyte Mar 15 '13 at 00:54
  • Hey :D Thanks for your feedback. That seems like an idea. I have not yet worked with proxy servers for caching and stuff. Is it possible to put this proxy server on the same as your apache is running on? – func0der Mar 15 '13 at 10:54
  • That should work just fine. – Insyte Mar 18 '13 at 19:49