2

I am using apache RewriteMap with a text file to map some old urls to new urls, in my file (red.map) I have

/old-awful-url.html   /new-lovely-shiny-url.html

Then in my apache config I have:-

RewriteEngine On
RewriteMap      migration       txt:/home/red.map
RewriteCond     ${migration:$1} /.+
RewriteRule     ^(/.*)  ${migration:$1} [L,R=301]

This works fine but now I would like to add a wildcard to the condition to match also some older urls that have the same end but have /cgi-bin/scriptname in front, eg I also want to match /cgi-bin/scriptname/old-awful-url.html

I tried changing to the RewriteCond to:-

RewriteCond     ^.*${migration:$1} /.+

Thinking this would match anything in front of the url in the file, with and without the cgi part, I've tried a few combinations with no success, is this possible?

hjpotter92
  • 78,589
  • 36
  • 144
  • 183
Andrew Smith
  • 117
  • 9

1 Answers1

1

You'd need to set /cgi-bin/scriptname as optional pattern in your RewriteRule directive itself. And, the RewriteCond directive is entirely unnecessary here.

RewriteEngine On
RewriteMap migration txt:/home/red.map

RewriteRule ^(?:/cgi-bin/scriptname)?(/.*) ${migration:$1} [L,R=301]

However, this'd fail in case you want the rewritten URL to include the /cgi-bin/scriptname part again. For that, you'd need to break the rules into two (or more?):

RewriteEngine On
RewriteMap migration txt:/home/red.map

RewriteCond ${migration:$1} .
RewriteRule ^(/.*) ${migration:$1} [L,R=301]

RewriteCond ${migration:$2} .
RewriteRule ^/(cgi-bin/scriptname)(/.*) /$1${migration:$2} [L,R=301]
hjpotter92
  • 78,589
  • 36
  • 144
  • 183
  • 1
    Hi @hjpotter92, I think, the RewriteCond is necessary to handle the case, that the lookup returns an empty string on mismatch. Otherwise, the RewriteRule in your first snippet would be triggered even on mismatch (and redirect to document root, instead of a proper 404). Your second snippet probably doesn't work in this order, since the first rule's pattern also matches `cgi-bin/scriptname`. – martin Nov 23 '16 at 10:03
  • @martin The map takes care of that itself. – hjpotter92 Nov 23 '16 at 10:54
  • In my experience, RewriteRule doesn't care if the map lookup was successful or not. On Apache/2.4.10 (Debian) the following config always triggers the first rewrite: `RewriteRule (.*) http://example.com/${map:nonexistant_key} [R=301,L] \n RewriteRule (.*) http://fallback.com [R=301,L]` – martin Nov 23 '16 at 13:16
  • @martin Because your rewritten path has the proper url defined, it will always trigger the `R=301`. Whereas, in my case above, I am simply using a relative rewrite; which is overlooked if the map doesn't have a matching entry. – hjpotter92 Nov 24 '16 at 05:06
  • @hjpotter92 Strange - is your expected behaviour (ignoring of empty substitution) documented somewhere? Because that is not what happens here: `RewriteRule (.*) ${manual_map:nonexistant_key} [R=301,L]` leads to log: 'map lookup FAILED: map=manual_map[dbm] key=nonexistant_key \n rewrite '/foo' -> '' \n explicitly forcing redirect with https://myservername.com/` -> redirect to document root. – martin Nov 24 '16 at 11:07
  • @martin Strange! It is doing the redirection on my local server too. It didn't when I wrote the answer. I'll look into this in detail when I get some time. However, I'll update the answer in any case. – hjpotter92 Nov 24 '16 at 15:56