logo
Apache Lounge
Webmasters

 

About Forum Index Downloads Search Register Log in RSS X


Keep Server Online

If you find the Apache Lounge, the downloads and overall help useful, please express your satisfaction with a donation.

or

Bitcoin

A donation makes a contribution towards the costs, the time and effort that's going in this site and building.

Thank You! Steffen

Your donations will help to keep this site alive and well, and continuing building binaries. Apache Lounge is not sponsored.
Post new topic   Forum Index -> Apache View previous topic :: View next topic
Reply to topic   Topic: Using IF-ELSE with ENV variables
Author
csdude55



Joined: 22 Jan 2023
Posts: 23
Location: USA, Wilkesboro

PostPosted: Sun 22 Jan '23 22:54    Post subject: Using IF-ELSE with ENV variables Reply with quote

Hi all! Long time coder, first time poster to this board.

I'm not sure how Apache handles the order, but when I set an ENV prior to the IF-ELSE it doesn't appear to be read. Or maybe I'm reading it wrong. More below.

Also, when I run a regex in the IF, the %1 isn't being carried into the results.

Example:

Code:
# www.example.com sets %{ENV:linker} = example
RewriteCond %{HTTP_HOST} ^(?:www\.)?([^.]+)\. [NC]
RewriteRule ^ - [E=linker:${lc:%1}]

# expecting %{ENV:tester} = ex
<If "%{ENV:linker} =~ /(ex)ample/i">
 RewriteRule ^ - [E=tester:%1]
</If>


I print all of the $_SERVER variables in PHP for testing. I can see that $_SERVER['linker'] is properly set to "example", but there's no $_SERVER['tester'];

Then I tried this modification:

Code:
RewriteCond %{HTTP_HOST} ^(?:www\.)?([^.]+)\. [NC]
RewriteRule ^ - [E=linker:${lc:%1}]

<If "%{HTTP_HOST} =~ m#^(?:www\.)?(ex)ample\.#i">
 RewriteRule ^ - [E=tester:%1]
</If>


This time $_SERVER['tester'] is set so the IF is true, but tester is empty so %1 has no value.

I tried every variation of reqenv() and env() that I could think of from the docs, but nothing worked like I thought.

Any suggestions?[/code]
Back to top
James Blond
Moderator


Joined: 19 Jan 2006
Posts: 7371
Location: Germany, Next to Hamburg

PostPosted: Mon 23 Jan '23 10:33    Post subject: Reply with quote

There is a good example answer here: https://stackoverflow.com/questions/42137409/apache-2-4-nested-if-directives

if you still have a question please ask again.
Back to top
csdude55



Joined: 22 Jan 2023
Posts: 23
Location: USA, Wilkesboro

PostPosted: Mon 23 Jan '23 22:07    Post subject: Reply with quote

Thanks, James. I'm afraid it doesn't help, though; it just confirms that nested IF-ELSE is OK, but doesn't say anything about using ENV variables or backreferences.

I should have stated before that I'm using 2.4.55

The saga has gotten even more confusing, though. It looks like the IF will actually delete previously assigned ENV? I discovered that if I remove the IF statement then I'll get a value for $_SERVER['linker'], but when I have the IF statement then $_SERVER['linker'] is gone; not empty, but appears to have never been set.
Back to top
tangent
Moderator


Joined: 16 Aug 2020
Posts: 348
Location: UK

PostPosted: Mon 23 Jan '23 22:12    Post subject: Reply with quote

Re your attempt to use regex backreferences to help set environment variables:

The Apache documentation for expr https://httpd.apache.org/docs/current/expr.html says:

The strings $0 ... $9 allow to reference the capture groups from a previously executed, successfully matching regular expressions. They can normally only be used in the same expression as the matching regex, but some modules allow special uses.

So your "RewriteRule ^ - [E=tester:%1] " won't find %1 (nor $1) from expr.

What you can do though, is use SetEnvIfExpr, e.g.

Code:

SetEnvIfExpr "%{HTTP_HOST} =~ m#^(?:www\.)?(ex)ample\.#i" tester=$1

This construct does set environment variables based on expr regex backreferences.

Hope this helps.
Back to top
csdude55



Joined: 22 Jan 2023
Posts: 23
Location: USA, Wilkesboro

PostPosted: Mon 23 Jan '23 22:20    Post subject: Reply with quote

I see. So it'd have to duplicate the regex.

Code:
<If "%{HTTP_HOST} =~ m#^(?:www\.)?(ex)ample\.#i">
  SetEnvIfExpr "%{HTTP_HOST} =~ m#^(?:www\.)?(ex)ample\.#i" tester=$1
</If>


Not exactly fast or logical, but maybe it'll improve in a future release Smile

If I can't read the ENV variable inside of the IF, though, then I think I'm going to have to redo a LOT of my config!
Back to top
tangent
Moderator


Joined: 16 Aug 2020
Posts: 348
Location: UK

PostPosted: Mon 23 Jan '23 22:38    Post subject: Reply with quote

Reading established ENV variables within subsequent IF statements should be fine.

I sort of agree with your concern, but think the issue here is you can't reasonably expect regex back references from expr logic in an IF match statement, to be available to (or be honoured by) other module code enclosed within said logical blocks.

If you look at all the expr builtin functions, you'll see they're all read or lookup related, and don't write anything outside the expr scope.

Maybe that's why the developers came up with SetEnvIfExpr.
Back to top
tangent
Moderator


Joined: 16 Aug 2020
Posts: 348
Location: UK

PostPosted: Mon 23 Jan '23 23:05    Post subject: Reply with quote

I've just read your last post more carefully, and wondered, why you've duplicated the regex?

You don't need the initial IF condition, since that's covered by the SetEnvIfExpr statement, or am I missing something?
Back to top
csdude55



Joined: 22 Jan 2023
Posts: 23
Location: USA, Wilkesboro

PostPosted: Tue 24 Jan '23 0:32    Post subject: Reply with quote

Quote:
Reading established ENV variables within subsequent IF statements should be fine.


Any suggestions on why this fails, then?

Code:
RewriteRule ^ - [E=foo:bar]

<If "-n %{ENV:foo}">
  RewriteRule ^ - [E=lorem:ipsum]
</If>


I've tried with reqenv('foo'), env(), and every other option listed in the docs, but they all fail.

Using -z matches, though, which means that either the IF doesn't recognize the ENV, or I'm referring to it incorrectly.


Quote:
I've just read your last post more carefully, and wondered, why you've duplicated the regex?


What I'm posting here has been super simplified, just trying to figure out the format. The final config would be more complex, running several RewriteRules when the IF succeeds and then several alternatives when it fails.

It's also for my own education. In production I have 82kb of data in the config files, and perfecting this style might help me cut that down quite a bit. Which, in theory, would result in faster processing.

It's starting to look like I might have to have a RewriteCond for each of those rules, though, instead of a single all-encompassing IF :-/[/quote]
Back to top
csdude55



Joined: 22 Jan 2023
Posts: 23
Location: USA, Wilkesboro

PostPosted: Tue 24 Jan '23 8:09    Post subject: Reply with quote

Somewhat of an update...

I found that this will kinda work:

Code:
RewriteRule ^ - [E=foo:bar]

<FilesMatch "\.php$">
  <If "-n %{ENV:foo}">
    RewriteRule ^ - [E=lorem:ipsum]
  </If>

  RewriteRule ^ - [E=this:that]
</FilesMatch>


This will print $_SERVER['foo'] and $_SERVER['lorem']...

... but not $_SERVER['this'] :-/

Thoughts?
Back to top
James Blond
Moderator


Joined: 19 Jan 2006
Posts: 7371
Location: Germany, Next to Hamburg

PostPosted: Tue 24 Jan '23 10:21    Post subject: Reply with quote

it might be easier to set the env inside the vhost config

Code:

<VirtualHost *:80>
    ServerName example.com
    # ... other stuff

    SetEnv vhostname example.com
    Header add X-Server-Name %{vhostname}e
</virtualhost>
<VirtualHost *:80>
    ServerName example.lan
    # ... other stuff

    SetEnv vhostname example.lan
    Header add X-Server-Name %{vhostname}e
</virtualhost>

Back to top
tangent
Moderator


Joined: 16 Aug 2020
Posts: 348
Location: UK

PostPosted: Tue 24 Jan '23 22:04    Post subject: Reply with quote

@csdude55 - further to your latest post (and James reply), which I've only just been able to respond to.

Through testing, I agree there are some inconsistencies with IF statements seeing Apache defined environment variables, depending on whether they are at a global level, or within a virtual host. Indeed, an IF env test within a vhost seems to circumvent an IF env test that otherwise works at the global level.

The expr documentation does have a section on "Environment variable ordering" which along with your findings suggests this approach is somewhat of a minefield.

Historically, I've stuck to mod_rewrite logic for environment variable manipulation, using rewrite conditions with appropriate flags, accepting you can't create configuration logic that reads as elegantly as IF-ELSE blocks, but at least it works as expected.
Back to top
James Blond
Moderator


Joined: 19 Jan 2006
Posts: 7371
Location: Germany, Next to Hamburg

PostPosted: Fri 27 Jan '23 22:02    Post subject: Reply with quote

I haven't tested it with the IF statements, but with all other things in apache: .htaccess overrides vhost that overrides global.

.htaccess
vhost
global
Back to top


Reply to topic   Topic: Using IF-ELSE with ENV variables View previous topic :: View next topic
Post new topic   Forum Index -> Apache