IIS 7.5 Canonical URL Rewrite rules for multiple domains - asp.net

In the context of URL Rewrite 2.0 in IIS 7.5, I want to be able to enforce canonical domain names for multiple domains for a multi-country site, in as few rules as possible. Something like this:
<rule name="UK Host Name">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^company\.co\.uk$" />
<add input="{HTTP_HOST}" pattern="^company\.co$" />
<add input="{HTTP_HOST}" pattern="^company\.org$" />
<add input="{HTTP_HOST}" pattern="^company\.net$" />
<add input="{HTTP_HOST}" pattern="^company\.uk\.com$" />
<add input="{HTTP_HOST}" pattern="^www\.company\.co\.uk$" negate="true" />
</conditions>
<action type="Redirect" url="http://www.company.co.uk/{R:1}" />
</rule>
<rule name="France Host Name">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^company\.fr$" />
<add input="{HTTP_HOST}" pattern="^company-france\.com$" />
<add input="{HTTP_HOST}" pattern="^www\.company\.fr$" negate="true" />
</conditions>
<action type="Redirect" url="http://www.company.fr/{R:1}" />
</rule>
The problem with the above, I believe, is that each of those conditions must be true hence logicalGrouping="MatchAll" but if changed to MatchAny then the last condition (with negate="true") will be ignored, meaning we run the redirect rule even if the user is visiting the correct domain.
The only alternative I can think of is having a separate rewrite rule for every single different domain, but there could be vast numbers of domains and it could get messy. There will be plenty of other rewrite rules and maps as it is.
How can I create more complex sets of conditions, rather than just All or Any?

The trick is to combine the domains you want to match against into one rule with the or | operator so that you only have one 'positive' rule and one 'negative' rule which should MatchAll. E.g.:
<rule name="UK Host Name">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^company\.(co(\.uk)?|org|net|uk\.com)$" />
<add input="{HTTP_HOST}" pattern="^www\.company\.co\.uk$" negate="true" />
</conditions>
<action type="Redirect" url="http://www.company.co.uk/{R:1}" />
</rule>
<rule name="France Host Name">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^company(-france)?\.(fr|com)$" />
<add input="{HTTP_HOST}" pattern="^www\.company\.fr$" negate="true" />
</conditions>
<action type="Redirect" url="http://www.company.fr/{R:1}" />
</rule>
This might eventually give you a slight chance that your regular expression matches too many domain names. E.g. the pattern pattern="^company(-france)?\.(fr|com)$" also matches company.com which might not be desirable. In that case you have to be more specific and e.g. change the pattern to pattern="^company\.fr|company-france\.com$".

Related

Redirect to different domain while preserve subdomains and query parameters and also enforce https using web.config

Using the Web.config only, I need to redirect all traffic to a new domain, yet also:
1) preserve subdomains
2) preserve query parameters
3) if "http" and not "https" change to "https" while doing the above
I can easily handle enforcing HTTPS, and I have seen many references to redirects for domains, but have not found any that preserve the subdomains while changing to the root domain.
<rewrite>
<rules>
<rule name="Redirect HTTP to HTTPS" stopProcessing="true">
<match url="^(.*)$" />
<conditions trackAllCaptures="true">
<add input="{HTTPS}" pattern="^OFF$" />
<add input="{HTTP_HOST}" matchType="Pattern" pattern="^localhost(:\d+)?$" negate="true" />
<add input="{HTTP_HOST}" matchType="Pattern" pattern="^127\.0\.0\.1(:\d+)?$" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther" />
</rule>
</rules>
</rewrite>
'The above works to change http to https, but does not help with the need to change the domain. I have also seen this below which almost works:'
<rule name="redirect" enabled="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" negate="false" pattern="^(.*)\.foo\.com" />
</conditions>
<action type="Redirect" url="https://{C:1}.bar.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
...but removes the subdomain:
http://x.foo.com > https://.bar.com
Examples of what it needs to do:
http://x.foo.com > https://x.bar.com
https://y.foo.com > https://y.bar.com
https://x.foo.com/blah.aspx?param=blue > https://x.bar.com/blah.aspx?param=blue
http://y.foo.com/blah.aspx?param=blue > https://y.bar.com/blah.aspx?param=blue
Okay, I have come up with the following solution that does exactly what I have needed (see above requirements). I did this by adding two independent rule blocks: one to ensure HTTPS, and the other to do a redirect to the other domain if necessary. I sense that this does double the traffic if the visit needs both 1) HTTP to HTTPS and 2) direct to the new domain (from *.foo.com > *.bar.com) but at least it works. Not sure if it could be tweaked into one rule to save hits?
<rewrite>
<rules>
<rule name="Redirect HTTP to HTTPS" stopProcessing="true">
<match url="^(.*)$" />
<conditions trackAllCaptures="true">
<add input="{HTTPS}" pattern="^OFF$" />
<add input="{HTTP_HOST}" matchType="Pattern" pattern="^localhost(:\d+)?$" negate="true" />
<add input="{HTTP_HOST}" matchType="Pattern" pattern="^127\.0\.0\.1(:\d+)?$" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther"/>
</rule>
<rule name="Redirect to new domain" enabled="true">
<match url="(.*)$" />
<conditions trackAllCaptures="true">
<add input="{HTTP_HOST}" negate="false" pattern="^(.*)\.foo\.com" />
</conditions>
<action type="Redirect" url="https://{C:1}.bar.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>

IIS manager url rules for similar urls

I have two urls: http://...../m?PageView=View1&Language=English&AName=AAA and another http://...../m?PageView=View2TName=T1&AName=XYZ. Both this urls are for separate section/functionality. But as the number and pattern of parameters are same one url work and another does not.
I want to write url redirect and rewrite rules for two similar urls. I have written first rule as below.
<rule name="RedirectUserFriendlyURL12" stopProcessing="true">
<match url="^m/$" />
<conditions>
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern="^View=([^=&]+)&Language=([^=&]+)&AName=([^=&]+)$" />
</conditions>
<action type="Redirect" url="m/{C:1}/{C:2}/{C:3}" appendQueryString="false" />
</rule>
<rule name="RewriteUserFriendlyURL12" stopProcessing="true">
<match url="^m/([^/]+)/([^/]+)/([^/]+)/?$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="m?View={R:1}&Language={R:2}&AName={R:3}" />
</rule>
and another url has same number of parameters but different name as below. Here is 2nd rule.
<rule name="RedirectUserFriendlyURL12" stopProcessing="true">
<match url="^m/$" />
<conditions>
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern="^View=([^=&]+)&TName=([^=&]+)&AName=([^=&]+)$" />
</conditions>
<action type="Redirect" url="m/{C:1}/{C:2}/{C:3}" appendQueryString="false" />
</rule>
<rule name="RewriteUserFriendlyURL12" stopProcessing="true">
<match url="^m/([^/]+)/([^/]+)/([^/]+)/?$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="m?View={R:1}&TName={R:2}&AName={R:3}" />
</rule>
When I have above two rules in web.config, one url works properly i.e. rediected and rewritten But another one does not work.
How can I differentiate both the rules so it works for both the urls.
I solved my issue. I have kept only one rule only, first one.
But in my controller code actually I had to map parameters accordingly. Means not TName parameter value I have to access, I have to access language parameter only for View-2 also, as value of TName is getting passed in Language parameter when rules get apply.
I could have use two rules but then I would have to change the redirect target URL. Like redirect
^View=([^=&]+)&TName=([^=&]+)&AName=([^=&]+)$ to m/{C:1}/tname/{C:2}/{C:3}
Then rewrite back from
^m/([^/]+)/tname/([^/]+)/([^/]+)/?$ to m?View={R:1}&TName={R:2}&AName={R:3}.
But I didn't wanted to have this above thing.

"non-www to www" and "https" rewrite rule in web.config but not localhost ASP.NET MVC

I have the following rewrite rule in the web.config of my ASP.NET MVC 5 project:
<rule name="Redirect example.com to www.example.com and enforce https" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^[^www]" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://www.example.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
The rule redirects non-www to www and http to https (so something like http://example.com/hey will redirect to https://www.example.com/hey) and works fine. It however also works on localhost, and I can't seem to be able to work around it — I've tried negation rules and regular expressions containing | but can't seem to be able to find the correct combinations. Am I approaching this the wrong way?
In conditions block you can use attribute negate="true". If this attribute is set and condition is matched, then rewrite rule is not applied.
The description of negate attribute from IIS.net:
A pattern can be negated by using the negate attribute of the
element. When this attribute is used, the rule action is performed
only if the current URL does not match the specified pattern.
Since you are using MatchAny, adding additional attribute will not match, because at least one of the conditions will be met anyway. I recommend using 2 specific rewrite rules with logicalGrouping="MatchAll", where each one is responsible just for single case:
<rule name="enforce https" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTPS}" pattern="off" />
<add input="{HTTP_HOST}" matchType="Pattern"
pattern="^localhost(:\d+)?$" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="Redirect example.com to www.example.com"
enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^[^www]" />
<add input="{HTTP_HOST}" matchType="Pattern"
pattern="^localhost(:\d+)?$" negate="true" />
</conditions>
<action type="Redirect" url="https://www.example.com/{R:1}"
appendQueryString="true" redirectType="Permanent" />
</rule>

URL Rewrite in IIS 7 causes redirect loop

I have tried various methods found on the web (including some SO answers) for getting URL rewrite in IIS 7 to work so that I can turn mysite.com/somepage.aspx into mysite.com/somepage, for example. The last thing I've tried is the video at this link: https://www.youtube.com/watch?v=bBNJE7XA1m0. After applying these changes in IIS, I now can request mysite.com/somepage and get to mysite.com/somepage.aspx with the .aspx removed in the address bar. Partial success.
When I try to directly request mysite.com/somepage.aspx, however, I get into a redirect loop. I am hoping there is some simple mistake in my settings. Here is the web.config section created by making changes in IIS:
<rewrite>
<rules>
<rule name="HideAspxExtension">
<match url="^(.*)$" />
<conditions logicalGrouping="MatchAny">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}.aspx" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="{R:0}.aspx" />
</rule>
<rule name="RedirectingAspxExtension" stopProcessing="true">
<match url="^(.*).aspx$" />
<conditions logicalGrouping="MatchAny">
<add input="{URL}" pattern="^(.*).aspx$" />
</conditions>
<action type="Redirect" url="{R:1}" />
</rule>
</rules>
</rewrite>
I have tried to apply this setting to multiple applications and I get the same results. What I do not have is another server to test on.
These are rules I've used before:
<rule name="StripAspx">
<match url="^(.+)\.aspx$" />
<action type="Redirect" url="{R:1}" redirectType="Permanent" />
</rule>
<!-- Rewrite the .aspx for internal processing-->
<rule name="RewriteASPX" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="{R:1}.aspx" />
</rule>
The main differences I can see are:
These have the removal of the .aspx first (in rewrite rules, order matters). This also means that in these rules the stopProcessing directive is on the rewrite to .aspx, not the redirect away from it.
These don't have <add input="{REQUEST_FILENAME}.aspx" matchType="IsFile" />

IIS Rewrite Rule - How to include root documents

I have a simple IIS rule to redirect HTTPS to HTTP:
<rule name="HTTPS" enabled="true" stopProcessing="true">
<match url=".*\.(asp)$" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="on" />
<add input="{REQUEST_URI}" negate="true" pattern="^/ecards/user*" ignoreCase="true" />
</conditions>
<action type="Redirect" url="http://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
The matching url will only work on .asp files, but how can I also get it to work for root directories?
E.g.
example.com
example.com/
example.com/test
example.com/test/
I don't want to just have the match URL as:
<match url="(.*)" />
Because then other non .asp files get rewritten.
One way to include directories in your rule is to exclude everything else.
Assuming that everything else has a file extension (e.g. .php, .css. .js, etc.) you can negate all input that has the . in the path.
I changed your code a bit to make a working demo locally (I don't have HTTPS locally to test so instead of redirecting to HTTP I set it to redirect to About.aspx) and the two rules are:
<rule name="HTTPS" enabled="true" stopProcessing="true">
<match url=".*\.(asp)$" ignoreCase="false" />
<action type="Redirect" url="/About.aspx" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="NEWRULE" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{REQUEST_URI}" negate="true" pattern=".*\.(.)$" ignoreCase="true" />
<add input="{REQUEST_URI}" negate="true" pattern="^/About*" ignoreCase="true" />
</conditions>
<action type="Redirect" url="/About.aspx" appendQueryString="true" redirectType="Permanent" />
</rule>
So, based on your original code sample, a new rule that will work for you would be similar to this:
<rule name="IncludeDirectories" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{REQUEST_URI}" negate="true" pattern=".*\.(.)$" ignoreCase="true" />
<add input="{HTTPS}" pattern="on" />
<add input="{REQUEST_URI}" negate="true" pattern="^/ecards/user*" ignoreCase="true" />
</conditions>
<action type="Redirect" url="http://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
Note: The above approach is rather aggressive. You could replace this condition:
<add input="{REQUEST_URI}" negate="true" pattern=".*\.(.)$" ignoreCase="true" />
with the following:
<add input="{REQUEST_URI}" negate="true" pattern=".*\.(php|css|js|jpg|gif|png)$" ignoreCase="true" />
Where you exclude specific extensions. You add as many as you want.
Edit: If you want to have specific pages still with HTTPS maybe the following rule will be helpful (haven't tested it though). The previous rule sends to HTTP all URLs except those that have /ecards/user where this one sends to HTTPS those that have /ecards/user. I believe there will be no conflict.
<rule name="HTTPS2Admins" enabled="true" stopProcessing="true">
<match url="/ecards/user(.*)" />
<conditions>
<add input="{HTTP}" pattern="on" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/ecards/user{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>

Resources