Bug 64526

Summary: InheritDownBefore won't keep vhost-context rules from re-executing after per-dir rules
Product: Apache httpd-2 Reporter: Raphaël Droz <raphael.droz>
Component: mod_rewriteAssignee: Apache HTTPD Bugs Mailing List <bugs>
Status: NEW ---    
Severity: normal    
Priority: P2    
Version: 2.4.41   
Target Milestone: ---   
Hardware: PC   
OS: Linux   

Description Raphaël Droz 2020-06-15 16:53:35 UTC
A web application depends on htaccess rules (which may also be `Include`d for performance reasons), mainly to set its entry-point.

I want to strip some query parameters and avoid making specific assumptions about application's particular "routing" (htaccess).
 

Example:

```
<VirtualHost *:80>
    ServerName localhost
    DocumentRoot /var/www/foo

    LogLevel rewrite:trace8

    RewriteEngine On
    RewriteOptions InheritDownBefore

    # Strips utm_* parameters
    RewriteCond %{QUERY_STRING} (.*)(?:^|&)(?:utm_(?:source|medium|campaign|term|content)|v|ver|rev)=(?:[^&]*)((?:&|$).*)
    RewriteCond %1%2 (^|&)([^&].*|$)
    RewriteRule ^(.*)$ $1?%2 [N]

    <Directory "/var/www/foo">
	Require all granted
        # Written here for clarity, but could be within a htaccess
        # echo ok > /var/www/foo/bar.php
	RewriteEngine On
	RewriteCond %{REQUEST_URI} !^/bar\.php
	RewriteRule .* bar.php [L]
    </Directory>
</VirtualHost>
```

Expected:
- [vhost] strip utm_* parameters
- [per-dir] redirect (internal) from * to bar.php

Actual:
- [vhost] strip utm_* parameters
- [per-dir] redirect (internal) from * to bar.php
- [vhost] strip utm_* parameters
- [per-dir] redirect (internal) from bar.php to bar.php


Note:
- InheritDownBefore typical use is when directory-rules can't be changed. Using [END] instead of [L] is not an option. (In my case it's an actual htaccess I `Include`)

Aggravating factor:
- [NS] flag to the vhost-context utm_* stripper rule WON'T keep rule from re-executing.

Workaround:
- RewriteRule ^/bar\.php - [S=1]
# To insert just after "RewriteOptions InheritDownBefore" in the above example.
# But this implies previous knowledge of the entry point filename.


Somehow related problem:
With the above example, if "/" is reached, per-dir rules are not processed at all, probably because "/" exists on the filesystem what leads to a 403 before per-dir rules get a change to be executed.

Stated another way:
If a virtual-host's rule is executed, even if the REQUEST_URI is left 
unchanged, per-dir rules won't be considered.

As such, I've found no other way to force the per-dir rewrite process to keep going other than... artificially redirecting '/' to a non-existing path.
Eg:
`RewriteRule / /___not_exists` (as a final rule in the vhost-context rule).
Comment 1 Eric Covener 2020-06-15 17:04:50 UTC
Hello, a few notes:

1) Inherit stuff is, as far as I can recall, only intended to inherit between directory sections or between global/vhost scopes.  Are you sure it influences the behavior here?

The repetition almost appears more like the typical "run directory scope rewrites and re-inject the result" looping.


2) Does [PT] help on your vhost scope rewriterule? It is doing URL-to-URL mapping and without [PT] it will in fact probe the first path in the substitution to try to figure out what you're doing
Comment 2 Raphaël Droz 2020-06-15 18:41:04 UTC
1) You're absolutely right! `InheritDownBefore` does not play a role here. With or without it (or even with "RewriteOptions IgnoreInherit" in the directory-context) : vhost's RewriteRules always run.


2) [PT] does help for the "/" issue, thank you!



So in the end how to protect against the _"run directory scope rewrites and re-inject the result" looping_ scenarios while avoiding "Rewrite-guard" rule like:
`RewriteRule ^/index\.php - [S=1]` ?

If it's a re-injection/REDIRECTION (as the logs mention in "[rid#7fbd44690c38/initial/redir#1]"), why [NS] appears not to work? Isn't these actual "subreq"?