views:

112

answers:

2

Ok, so I'm doing a mod_rewrite, and I'm in a situation to where I need to match any subdomain except for one. It starts out looking like this.

RewriteCond %{HTTP_HOST} ^([^\.]+)\.example\.com$ [NC]

So that matches and captures a single subdomain, no periods. But let's say I don't want to match the submdomain named 'dog'. I tried to do this with a negative lookahead like so.

RewriteCond %{HTTP_HOST} ^((?!dog)[^\.]+)\.example\.com$ [NC]

This works, for the most part. dog.example.com no longer matches, which is good. However, doggies.example.com also no longer matches. That is not good.

I was able to fix this by using a negative lookahead combined with a negative look-behind like so.

RewriteCond %{HTTP_HOST} ^((?!dog)[^\.]+(?<!dog))\.example\.com$ [NC]

This works. It works perfectly, as far as I can tell. The thing is, I can't believe that is the best way to achieve this match. A lookahead and a look-behind? Really? What is the "correct" way to achieve an equivalent expression?

A: 

You can simplify things a lot using the negation operator of RewriteCond, like this:

RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com$ [NC]
RewriteCond %{HTTP_HOST} !^dog\. [NC]
Vinko Vrsalovic
That's ok, but my problem is more complex than that since I have other conditions for multiple subdomains.
Apreche
Well, explain that in your question. People do not usually read minds, you know?
Vinko Vrsalovic
By the way, you can have a single negation for all your conditions in a single rule RewriteCond %{HTTP_HOST} !(^dog\.|^cat\.). But, then again, without knowing your complex situation is hard to tell if that'll help
Vinko Vrsalovic
Or `^(dog|cat)\.`
Gumbo
+3  A: 

If you want to use a negative lookahead, you need to anchor the expression to the dot:

RewriteCond %{HTTP_HOST} ^((?!dog\.)[^.]+)\.example\.com$ [NC]

Otherwise anything that starts with dog wouldn’t be allowed.

The same applies to the negative lookbehind:

RewriteCond %{HTTP_HOST} ^([^\.]+(?<!^dog))\.example\.com$ [NC]

Anchoring it to the start of the string with ^ will ensure that something that just ends with dog like catdog will still be allowed.

Another solution similar to what Vinko Vrsalovic mentioned is to test what the first submatch holds:

RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$ [NC]
RewriteCond %1 !^dog$
Gumbo
+1, you evil beaver :-)
Vinko Vrsalovic
Yes, thank you!
Apreche