Artur Cichosz
Artur Cichosz

Reputation: 1054

apache 2.4, nested If directives

I try to set some environment variables in Apache configuration file with the following directive block given that the header "X-Forwarded-Proto" is set.

<If "-n req('X-Forwarded-Proto')">
  SetEnv NON_EMPTY_PROTO on
  <If "req('X-Forwarded-Proto') =~ /https/">
    SetEnv HTTPS on
  </If>
  <Else>
    SetEnv HTTPS off
  </Else>
</If>

As a result, the environment variable NON_EMPTY_PROTO is set as expected but the variable HTTPS is not. But if I avoid nesting just for test both variables are set as expected.

<If "-n req('X-Forwarded-Proto')">
  SetEnv NON_EMPTY_PROTO on
</If>

<If "req('X-Forwarded-Proto') =~ /https/">
  SetEnv HTTPS on
</If>
<Else>
  SetEnv HTTPS off
</Else>

Why is the inner block not validated in first example? The directives documentation does not mention anything about possible or not possible nesting.

By the way, I know I can use a logical equivalent like this below, but nesting is just simpler and more convenient if the scenario gets more complex.

<If "-n req('X-Forwarded-Proto') && req('X-Forwarded-Proto') =~ /https/">
  SetEnv HTTPS on
</If>
<ElseIf "-n req('X-Forwarded-Proto')">
  SetEnv HTTPS off
</ElseIf>

I ask explicitly for the reason why the nested version does not work here.

Upvotes: 5

Views: 10470

Answers (1)

PeterA
PeterA

Reputation: 805

Updated Answer:

As of Apache 2.4.26 nested <If> directives are allowed.

The Apache 2.4 ChangeLog has the following change noted:

Evaluate nested If/ElseIf/Else configuration blocks. [Luca Toscano, Jacob Champion]

The nested <If> directives in the question should work in Apache 2.4.26 and forward.

While I could not confirm the specific rules in the question, here is a working example of htaccess rules with nested <If> directives:

RewriteEngine On

<If "%{REQUEST_URI} =~ /flintstones$/ ">
    <If "%{QUERY_STRING} == 'character=fred'">
        ErrorDocument 200 "Fred says, \"Yabba Dabba Doo\" <a href=\"flintstones\">back</a>"
    </If>
    <ElseIf "%{QUERY_STRING} == 'character=barney'">
        ErrorDocument 200 "Barney says, \"Uh hee hee hee... Okay Fred!\" <a href=\"flintstones\">back</a>"
    </ElseIf>
    <Else>
        ErrorDocument 200 "Pick a Flintstones character: <a href=\"flintstones?character=fred\">Fred</a> or <a href=\"flintstones?character=barney\">Barney</a>"
    </Else>
    RewriteRule ^ - [R=200,L]   
</If>

Original Answer

An <If> directive cannot be nested inside another <If> directive.

The Apache 2.4 Documentation for the If Directive has the following notice:

Not a scripting language

The name of this directive is very familiar to programmers and admins but it should not be confused with its counterpart in scripting languages. For example, the current implementation does not contemplate the possibility of having a <If> section inside another one (the inner <If> will be ignored).

No reason is given for why they chose not to allow nested If directives.

The only other information about nesting provided in the documentation indicates each section type differs on whether or not it can be nested:

Nesting of sections

Some section types can be nested inside other section types. On the one hand, <Files> can be used inside <Directory>. On the other hand, <If> can be used inside <Directory>, <Location>, and <Files> sections (but not inside another <If>). The regex counterparts of the named section behave identically.

Upvotes: 10

Related Questions