EDIT: [Solved] Finally found the solution in the documentation; posted an answer. In short: the DPI flag.

EDIT: at the bottom, added an easy way to reproduce the problem online.

I've spent a few hours debugging some rewrites. All is well except one behavior that stumps me.

Somehow, when fed a url with two or more subdirectories, mod_rewrite automatically appends all subdirectories (except the first) to the rewritten url. Here is the simplest example I could reduce it to. This is in an htaccess at DOCUMENT_ROOT.

  • url: http://localhost/stripthis/stripthat
  • RewriteRule ^ RewriteWasHere_
  • Output: RewriteWasHere_/stripthat

Where did that stripthat come from? Could some option upstream be causing this?

I have tried to strip the subfolders with a variety of rules. For instance:

  • url: http://localhost/stripthis/stripthat
  • RewriteRule ^/?([^/]+) RewriteWasHere_$1
  • Output: RewriteWasHere_stripthis/stripthat

Strangely, this happens both on a local xampp x Apache 2.4.7 and a remote CentOS x Apache 2.2.

I have been inspecting the rewritten urls by outputting them to a script, but here's a way to reproduce the problem online.

How to Reproduce This Online

For the rules, paste this:

# the `(?!)` negative lookaheads are just to make triple sure
# we're not running the same rules multiple times
RewriteRule ^(?!m[yo])([^/]+) my_$1
#RewriteRule ^(?!mo])\D*(\d+) mo_$1:$1:$1
  1. Run: the output is http://example.com/my_a/123/b
  2. Uncomment the second line.
  3. Run: the output is http://example.com/mo_123:123:123/b
  4. Comment out the second line, change the first line to RewriteRule ^(?!m[yo])([^/]+).*$ my_$1: the problem goes away on this site, but not on my servers.

Any insights would be deeply appreciated.

  • +1 Interesting problem, I will try to reproduce it on my Apache. – anubhava Jun 24 '14 at 21:32
  • @anubhava I spent a couple hours playing with it... Even if you think you are stripping everything with a ReWriteRule (?!hey) hey, it the next rule you are still able to find digits in the subpath with ReWriteRule (?!ho)\D*(\d+) ho_$1_digits – zx81 Jun 24 '14 at 21:43
  • @anubhava Found it! Went back to the documentation, and... the DPI flag (discardpathinfo) takes care of it. Thank you so much for your time, though. :) – zx81 Jun 24 '14 at 22:38

[DPI] (discardpathinfo)

After hours of tests and puzzlement, I went back to the documentation and found the solution: the [DPI] flag.

The DPI flag causes the PATH_INFO portion of the rewritten URI to be discarded.

This flag is available in version 2.2.12 and later.

In per-directory context, the URI each RewriteRule compares against is the concatenation of the current values of the URI and PATH_INFO.

The current URI can be the initial URI as requested by the client, the result of a previous round of mod_rewrite processing, or the result of a prior rule in the current round of mod_rewrite processing.

In contrast, the PATH_INFO that is appended to the URI before each rule reflects only the value of PATH_INFO before this round of mod_rewrite processing. As a consequence, if large portions of the URI are matched and copied into a substitution in multiple RewriteRule directives, without regard for which parts of the URI came from the current PATH_INFO, the final URI may have multiple copies of PATH_INFO appended to it.

Use this flag on any substitution where the PATH_INFO that resulted from the previous mapping of this request to the filesystem is not of interest. This flag permanently forgets the PATH_INFO established before this round of mod_rewrite processing began. PATH_INFO will not be recalculated until the current round of mod_rewrite processing completes. Subsequent rules during this round of processing will see only the direct result of substitutions, without any PATH_INFO appended.

  • +1 very nice find on this under utilized flag. – anubhava Jun 24 '14 at 22:43
  • 1
    @anubhava It's amazing. I can barely believe that the solution is so simple. I was getting really sad that after spending days creating a nice debugging workflow for mod_rewrite, something so basic was not working. :) As they say, hallelujah! – zx81 Jun 24 '14 at 22:47

Perhaps you are missing the trailing $ in your RewriteRule expression, hence stuff isn't matched fully?

You might want to consider switching to nginx; it has a very clear and reasonable documentation, without the bloat and nondeterminism that Apache is quite famous for.

  • 1
    Apache is extremely widely used, and recommending the requester switch to an entirely new application is counter-productive. – Andrew M. Jun 24 '14 at 18:05
  • Thanks for your suggestion. I finally found the answer: the DPI flag. – zx81 Jun 24 '14 at 22:55

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.