Search code examples
apachemod-rewriteapache2.4

Compare two backreferences in RewriteCond


This is the old URI pattern /release-(\w+)/(\w+)/(.*), where first and second regex pattern are always the same, with the following examples:

  • /release-foo/foo/(.*)
  • /release-bar/bar/(.*)
  • etc

They are consolidated under one folder (i.e. /release), in the new version:

ROOT
└── release
    ├── foo
    │   ├── ...
    │   └── ...
    ├── bar
    │   ├── ...
    │   └── ...
    └── ...

With this RewriteRule config:

RewriteRule "^/release-(\w+)/(\w+)/(.*)$"  "/release/$1/$3" [L]

all of these redirects work:

  • /release-foo/foo/(.*) => /release/foo/(.*): This is intended
  • /release-foo/bar/(.*) => /release/foo/(.*): This should NOT be allowed
  • /release-foo/baz/(.*) => /release/foo/(.*): This should NOT be allowed

My question is what can I put as the RewriteCond here? Is this even possible at all?

RewriteCond expr "$2 == $1"   <-- what do I need to put here?
RewriteRule "^/release-(\w+)/(\w+)/(.*)$"  "/release/$1/$3"     [L]

RewriteCond expr "$2 != $1"   <-- what do I need to put here?
RewriteRule "^/release-(\w+)/(\w+)/(.*)$"  "/release-$1/$1/$3"  [R,L]

What I'm trying to do is check two backreferences in RewriteCond that if $2 is equal to $1 (e.g. /release-foo/foo/) let it be processed. But if they are different (e.g. /release-foo/bar/) externally redirect it to the correct URI. I will need RewriteCondotherwise it will stuck in infinite loop.

I've tried almost everything from Expressions in Apache HTTP Server, even hard-coding doesn't work, like this:

RewriteCond expr "$2 == 'foo'"

Any pointer is very appreciated.


Solution

  • An advanced/neat trick is that you can use \1 as a backreference within the expression.

    RewriteRule "^/release-(\w+)/\1/(.*)$"  "/release/$1/$2" [L]
    

    As far as if you actually wanted a condition to compare the two backreferences, as opposed to eliminating the need for the condition, there is a similar trick:

    RewriteCond "$1<>$2" "^(.*)<>\1$" 
    

    The <> has no meaning and is just a very unlikely to appear in your capture and acts as aseparator or pseudo-operator.