Search code examples
apache.htaccesssetenvif

SetEnvIfNoCase not setting variable value properly


I need to access service running at domain (example.com) from two different apps running at different ports of localhost but getting CORS error.

PageURL accessed in browser is:

http://localhost:8081/weather

which internally sending AJAX request to

example.com/getResponse 

I have CORS header configured in Apache of (example.com) as follows:

SetEnvIfNocase Origin "http://localhost:8085" CORS_ALLOW_ORIGIN1=$0
Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN1}e env=CORS_ALLOW_ORIGIN1
SetEnvIfNocase Origin "http://localhost:8081" CORS_ALLOW_ORIGIN2=$0
Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN2}e env=CORS_ALLOW_ORIGIN2

Now Request Headers are:

Accept:*/*
Accept-Encoding: gzip,deflate,br
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Host: example.com
Origin: http://localhost:8081
Referer: http://localhost:8081/weather
User-Agent: Mozilla

Getting Response Header as:

Access-Control-Allow-Origin: $0

Obviously, the error comes back as:

CORS Blocked: Reason: CORS Header does not match '$0'

The presence of Access-Control-Allow-Origin Header in response means SetEnvIfNoCase executes and matches the Origin Request-Header value.

My question is why $0 is not getting replaced by the whole string getting matched?


Solution

  • My question is why $0 is not getting replaced by the whole string getting matched.?

    This is bug-like1 (IMO) behaviour of the SetEnvIf[NoCase] directive. In situations when the 2nd argument doesn't "look like" a regex, the entire match is not captured, no backreferences are generated, and instead $0 is seen as a literal string.

    It is preferable to be explicit and include a capturing group (parenthesised subpattern) and use the $1 backreference instead.

    For example:

    SetEnvIfNocase Origin "^(http://localhost:8085)" CORS_ALLOW_ORIGIN1=$1
    

    1 Or maybe an optimisation?! It behaves like a simple substring().


    Aside:

    SetEnvIfNocase Origin "http://localhost:8085" CORS_ALLOW_ORIGIN1=$0
    Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN1}e env=CORS_ALLOW_ORIGIN1
    SetEnvIfNocase Origin "http://localhost:8081" CORS_ALLOW_ORIGIN2=$0
    Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN2}e env=CORS_ALLOW_ORIGIN2
    

    It's not clear why you would need two expressions (and two variables) here, since these are mutually exclusive events. For example, the same result would be achieved with the following:

    SetEnvIf Origin "^(http://localhost:808[51])" CORS_ALLOW_ORIGIN=$1
    Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN
    

    (A case-insensitive match would also seem to be redundant here.)