regexapache.htaccessmod-rewritemod-headers

Rewrite rule not working properly on Apache 2.2.15


On my local Linux machine I'm running an Apache 2.2.15 server. I would like to set an .htaccess RewriteRule in order to set a response header whenever a certain URL query string (?print=pdf&redirect=false) is matched.

Example URL:

www.example.com/page1/?print=pdf&redirect=false 

I tried in different ways but I have no idea what I'm doing wrong. As you can see I tried to set an evironment variable that needs to be set when the query string is matched but it doesn work. Here is what I have:

RewriteCond %{QUERY_STRING}e ^print=pdf&redirect=false$
RewriteRule ^(.*)$ - [E=IS_CANONICAL:1,L]
Header set Link "https://%{HTTP_HOST}e%{REQUEST_URI}e; rel=\"canonical\"" env=IS_CANONICAL

UPDATE: Full .htaccess here:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

RewriteCond %{QUERY_STRING}e ^print=pdf&redirect=false$
RewriteRule ^(.*)$ - [E=IS_CANONICAL:1,L]
Header set Link "https://%{HTTP_HOST}e%{REQUEST_URI}e; rel=\"canonical\"" env=IS_CANONICAL

Solution

  • <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    </IfModule>
    
    RewriteCond %{QUERY_STRING}e ^print=pdf&redirect=false$
    RewriteRule ^(.*)$ - [E=IS_CANONICAL:1,L]
    Header set Link "https://%{HTTP_HOST}e%{REQUEST_URI}e; rel=\"canonical\"" env=IS_CANONICAL
    

    There are a few issues with the directives as posted:

    1. The mod_rewrite rule that sets the IS_CANONICAL environment variable is in the wrong place and is probably not even being processed for the required request (unless the URL-path happened to map to a physical asset). This rule needs to go before the preceding rewrite to your front-controller (index.php). ie. Before the entire rule block and <IfModule> wrapper.

    2. %{QUERY_STRING}e - The trailing e in the RewriteCond TestString matches a literal e. You are using mod_headers syntax in the mod_rewrite directive. It should be just %{QUERY_STRING} (no e) here.

    3. If the URL on which you are expecting to receive this query string is subject to an internal rewrite (ie. it does not map to a physical asset and is routed through your front-controller) then you will need to test for REDIRECT_IS_CANONICAL in the Header directive instead of IS_CANONICAL. This is because any env var set during the first pass by the rewrite engine is renamed by prefixing with REDIRECT_ before the Header directive is processed. (NB: This does not apply to LiteSpeed servers.)

    4. You should not use the L flag on the rule that sets the env var. Otherwise the request will not be routed through your front-controller.

    Minor points:

    1. No need to match against ^(.*)$ in the RewriteRule pattern here since you only need the rule to be successful. A simple ^ (start of string anchor) is sufficient and more more efficient.

    2. The first block of directives are wrapped in an <IfModule> section, but your rule that sets the env var is not. This is inconsistent (and defeats the point in having the <IfModule> wrapper in the first place). If this code is your own then you should probably not be using the <IfModule> wrapper at all here. Otherwise, if this is part of your framework (it looks like the standard WordPress code block) then you should leave it as it is.

    Try the following instead:

    RewriteCond %{QUERY_STRING} ^print=pdf&redirect=false$
    RewriteRule ^ - [E=IS_CANONICAL:1]
    Header set Link "https://%{HTTP_HOST}e%{REQUEST_URI}e; rel=\"canonical\"" env=REDIRECT_IS_CANONICAL
    
    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    </IfModule>
    

    You do not need to repeat the RewriteEngine directive before the first rule since it already occurs later in the file. (For readability the RewriteEngine directive should occur once at the top of the file. However, it is actually the last occurrence of this directive that controls the entire file. So, including an additional RewriteEngine directive before the first rule does not actually do anything.)

    The location of the Header (mod_headers) directive is not important (it could occur at the end of the file). Since different Apache modules are processed independently and at different times during the request. However, it is logical to keep this together with the mod_rewrite rule that sets the env var.