httpd.conf variables : What is the difference between ${var} and %{var}?

What is the difference between ${var} and %{var} in httpd.conf?

How and when would one use ${} and %{}?

http://httpd.apache.org/docs/2.4/configuring.html mentions :

The values of variables defined with the Define of or shell environment variables can be used in configuration file lines using the syntax ${VAR}.

http://httpd.apache.org/docs/2.4/mod/mod_rewrite.html mentions:

Server-Variables:These are variables of the form %{ NAME_OF_VARIABLE }

and

RewriteMap expansions:These are expansions of the form ${mapname:key|default}.

Will ${VAR} be used everywhere in httpd.conf, except in mod_rewrite directive's (like RewriteCond, RewriteRule but except for RewriteMap expansions which use ${} as in RewriteRule ^/ex/(.*) ${examplemap:$1} )

Would a variable set in httpd.conf using SetEnvIf Directive, for use in same httpd.conf, be used as ${var} except when the variable is used with mod_rewrite directive's, where the variable would be used as %{var}?


Solution 1:

What is the difference between ${var} and %{var} in httpd.conf?

Pretty much everything. There's no hard-and-fast rule that says "$ does x, % does y", because they do different things depending on where and how they're used.

Will ${VAR} be used everywhere in httpd.conf, except in mod_rewrite directive's

No - ${VAR} is applied as a replacement in every location throughout the config, even in a mod_rewrite related line. These can only be defined at startup using the -D option passed to the httpd binary, or the Define directive.

This can be done because those variables must not contain a : character, whereas the RewriteMap usage must contain a : character. This allows for the $ to be used in extremely different ways with no conflict - the parser sees the : and knows that it's not supposed to be replacing that.

Would a variable set in httpd.conf using SetEnvIf Directive, for use in same httpd.conf, be used as ${var} except when the variable is used with mod_rewrite directive's, where the variable would be used as %{var}?

No. Environment variables are not the same as variables set via -D or Define - they're a completely separate per-request context (those are the ones you're setting with SetEnvIf), that only certain directives will use. They're specifically mentioned where supported - in mod_rewrite they're %{ENV:variable}, in logs they're %{variable}e, and a lot of directives have a logic check that looks like env=variable.


So, basically; it's a confusing mess - a testament to the web server's history over the past couple decades. Probably the main thing that's confusing you is that mod_rewrite's syntax doesn't extend to any other part of the config in any way; it's all different. The main point to take from all this is that there isn't a governing 'rule' to make all of this make sense - a $ in one spot means something completely different from a $ in another spot.

A few handy reference points:

  1. If you're looking to set a variable statically when Apache starts, use Define and ${VAR} to replace once, on Apache's startup. This is mostly useful for when you want to do something like share config files between a development and production environment - but it's not to be confused with the use of the $ from RewriteMap, which always contains a :.
  2. If you're looking to work with variables in specific requests, then environment variables are what you're after - but you cannot make assumptions about the syntax that you'll use to get at them when used with a specific directive. You'll need to check the documentation for that directive.
  3. When mod_rewrite is in question, throw out everything you thought you knew about variables and their syntax. It has its own set of variables in %{VAR}, you can get at your 'normal' environment variables with %{ENV:VAR}, and you can set environment variables with [E=VAR].

Solution 2:

I have looked at source code of mod_rewrite, and found that notes in comments (do_expand function):

        /* variable lookup */
        else if (*p == '%') {
        ...
        /* map lookup */
        else {     /* *p == '$' */

so it looks, like % are for exact variables, while $ are for lookups in hash tables ("maps"). also, all mod_rewrite expansions are completely independed from core -- whole expansion done in module by itself.

I was thought earlier, but that was wrong:

${} vars are uses environment of project, and evaluated at time of config parse.

%{} vars are uses environment of request, and evaluated at time request parsed. mod_rewrite uses %{} symantic to prevent config-time interpolation made by httpd core.