There are several workarounds for this, each of which has its pros and cons. As a disclaimer, I tested them only in the context of .htaccess .
Workaround 1. Check for an empty REDIRECT_STATUS
Add a RewriteCond check to see if %{ENV:REDIRECT_STATUS} empty. If it is empty, then the current request is not an internal redirect.
Pros
- The most direct way to determine internal redirection.
Against
Lack of documentation. The Custom Error Response page briefly describes this variable:
REDIRECT_ environment variables are created from environment variables that existed before the redirect. They are renamed with the prefix REDIRECT_ , i.e. HTTP_USER_AGENT becomes REDIRECT_HTTP_USER_AGENT . REDIRECT_URL , REDIRECT_STATUS and REDIRECT_QUERY_STRING guaranteed to be set, and the remaining headers will be set only if they existed before the error condition.
I tried every other REDIRECT_ variable in RewriteCond , but all of them, except REDIRECT_STATUS , were empty for internal redirects. Why REDIRECT_STATUS is special in mod_rewrite remains a mystery.
Example
# Forbid rule. Prohibit direct access to target.html. RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteRule ^target.html$ - [F] # Rewrite rule. Rewrite source.html to target.html. RewriteRule ^source.html$ target.html
Credits for this approach are moving to rewriting URLs: an internal server error .
Workaround 2. Stop rewriting rule processing using END
Unlike the L flag, END stops rewriting rules even for internal redirects.
Pros
- Plain. Only an additional flag.
Against
- It does not give you enough control over which rules to process and what to skip.
Example
# Forbid rule. Prohibit direct access to target.html. RewriteRule ^target.html$ - [F] # Rewrite rule. Rewrite source.html to target.html. RewriteRule ^source.html$ target.html [END]
See the END flag for more information.
Workaround 3. Match source URL in THE_REQUEST file
%{THE_REQUEST}
The full string of the HTTP request sent by the browser to the server (for example, "GET / index.html HTTP / 1.1").
THE_REQUEST does not change with internal redirects, so you can match it.
Pros
- It can be used to match the source URL even in the second round of URL processing.
Against
Much more complicated than other approaches. Forces to use RewriteCond , where one RewriteRule would be enough.
Matches a full URL that has not been canceled (decoded), unlike most other variables.
It is inconvenient to use in several RewriteRule s. RewriteCond can be copied over each RewriteRule or a value can be exported to an environment variable (see example). Both hacker alternatives.
Example
# Forbid rule. Prohibit direct access to target.html. RewriteCond %{THE_REQUEST} "^[^ ]+ ([^ ?]*)" # extract path from request line RewriteCond %1 ^/rwtest/target.html$ RewriteRule ^ - [F] # Rewrite rule. Rewrite source.html to target.html. RewriteRule ^source.html$ target.html
Or export the path to the environment variable and use it in multiple RewriteRule s.
# Extract the original URL and save it to ORIG_URL. RewriteCond %{THE_REQUEST} "^[^ ]+ ([^ ?]*)" # extract path from request line RewriteRule ^ - [E=ORIG_URL:%1] # Forbid rule. Prohibit direct access to target.html. RewriteCond %{ENV:ORIG_URL} ^/rwtest/target.html$ RewriteRule ^ - [F] # Rewrite rule. Rewrite source.html to target.html. RewriteCond %{ENV:ORIG_URL} ^/rwtest/source.html$ RewriteRule ^ target.html
mksios
source share