Bug 58168

Summary: Would like full request evaluation support in RewriteCond
Product: Apache httpd-2 Reporter: alexander <alexander>
Component: mod_rewriteAssignee: Apache HTTPD Bugs Mailing List <bugs>
Status: NEW ---    
Severity: enhancement    
Priority: P2    
Version: 2.5-HEAD   
Target Milestone: ---   
Hardware: PC   
OS: Linux   

Description alexander 2015-07-21 23:37:32 UTC
I am trying to handle a situation where I need to do special things to requests that otherwise would have turned into 404:s due to the requested resource doesn't exist. I can do this beautifully in Nginx like so:

location some-regex { error_page 404 = @handle404; }
location @handle404 { ... }

Nginx will evaluate the request fully, and send it to the $handle404 location block if it would have resulted in a 404.

RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule "some-regex" "..."

Apache's mod_rewrite is not capable of telling me if a certain request will result in a 404 or not, all I can do is try to guess by asking Apache to check if the requested file exists on the hard drive under the same path as what is in the URL.

This works if and only if a simple URL scheme like that is used, otherwise if fails. Examples of when it fails:
- If an Alias directive is used for the requested URL
- If the request depends on subsequent rewrites to map to the correct resource on the harddrive
- If the request maps to a dynamic script that exists, but may itself return a 404 status

So my feature request is for support to be added to mod_rewrite so we can do the equivalent of what nginx supports with its error_page directive. Syntactically it could work like this:

RewriteCond %{IS_404} true
RewriteRule "some-regex" "..."

Note, I am aware of Apache's ErrorDocument, but it doesn't support targeting with regular expression, or URL rewriting, which are both things I need. This feature seems like a natural fit in mod_rewrite.
Comment 1 Eric Covener 2015-07-21 23:47:54 UTC
> Note, I am aware of Apache's ErrorDocument, but it doesn't support targeting
> with regular expression, or URL rewriting, which are both things I need.
> This feature seems like a natural fit in mod_rewrite.

ErrorDocument works inside of <LocationMatch> and its argument specifies the new URL-path.   

It's probably easier to extend ErrorDocument then to extend mod_rewrite -- mod_rewrite never runs after a status code has been determined by whichever handler is in charge.  One possible extension would be to make ErrrorDocument take an expression as an argument (as in http://httpd.apache.org/docs/2.4/expr.html)

For static files, you can also work around the DOCUMENT_ROOT issue by putting your rewrites in per-directory context.  The core will have mapped the URL to a filename and %{REQUEST_FILENAME} will be a filesystem path.

There's also FallBackResource.
Comment 2 Eric Covener 2015-07-21 23:50:00 UTC
whoops, ErrroDocument already supports expressions in the final parameter.  Sees like most of the elements are there.
Comment 3 Eric Covener 2015-07-21 23:55:45 UTC
Sorry for the trickle here, but perhaps one thing missing in the ErrorDocument solution is that the status code does not change. It seems like that is relatively straightfoward to implement though.
Comment 4 alexander 2015-07-22 00:30:15 UTC
I see what you mean. I had not considered using ErrorDocument via LocatioMatch, and that does indeed seem to be the way to do it.

However, it doesn't seem to support one crucial thing, which is to provide the current REQUEST_URI to the ErrorDocument argument, although the docs seem to suggest this should be possible:

ErrorDocument 404 /errors%{escape:%{HTTP_URI}}

I would expect the above to internally rewrite the would-be 404 result to
/errors/the-missing-file.txt   (if http://example.org/the-missing-file.txt was requested).

Apache chokes out with the message:
Additionally, a 400 Bad Request error was encountered while trying to use an ErrorDocument to handle the request.

Am I doing something wrong, or is this the one part of the puzzle that is missing, that I should do a feature request for?