URL Rewriting - Multi-Domain - Remove Folder In Path on Primary Domain - url

This challenge is related to URL Rewriting in using both a primary domain with a fictitious folder and as many secondary domains (without the fictitious folder) as needed. The idea is that the site will have a default domain that anyone can use, but also will allow users to use their own domain. Both also need the extensions removed at the end. I’ll outline how it should work. I have almost everything working except one thing and I’m hoping someone can assist or shed some light. This is a VS 2012 application that uses IIS.
PRIMARY DOMAIN URLS
www.primarydomain.com/anyfictitiousname/page1
www.primarydomain.com/anyfictitiousname2/page2
www.primarydomain.com/anyfictitiousname3/somepath/page3
REWRITTEN PRIMARY DOMAIN URLS
www.primarydomain.com/page1.aspx (or better yet www.primarydomain.com/page1.aspx?i=anyfictitiousname)
www.primarydomain.com/page2.aspx (or better yet www.primarydomain.com/page2.aspx?i=anyfictitiousname2)
www.primarydomain.com/somepath/page3.aspx (or better yet www.primarydomain.com/somepath/page3.aspx?i=anyfictitiousname3)
SECONDARY DOMAIN URLS
www.secondarydomain1.com/page1
www.secondarydomain2.com/page2
www.secondarydomain3.com/somepath/page3
REWRITTEN SECONDARY DOMAIN URLS
www.secondarydomain1.com/page1.aspx
www.secondarydomain2.com/page2.aspx
www.secondarydomain3.com/somepath/page3.aspx
All of the above actually work with my current rewriting code (which I’ve listed below), except when using the primary domain and not including the file at the end of the URL, it falls apart. Essentially, if I assign the URL “www.primarydomain.com/personname” to a user, I want to be able to go to that address to load the default page rather than having to type “www. primarydomain.com/personname/default” if that makes sense. What ends up happening is the following:
www.primarydomain.com/personname => www.primarydomain.com/personname.aspx
www.primarydomain.com/personname/ => www.primarydomain.com/personname/.aspx
What I want to happen in this case is the following:
www.primarydomain.com/personname => www.primarydomain.com/default.aspx (or better yet www.primarydomain.com/default.aspx?i=personname)
www.primarydomain.com/personname/ => www.primarydomain.com/default.aspx (or better yet www.primarydomain.com/default.aspx?i=personname)
I’m new to URL rewriting, so I’m not sure of the correct approach, but essentially after the first rule is performed or as a part of the first rule, if {R:2} is nothing or “/”, I’d like to rewrite it as “default.aspx”. Even if a redirect is performed in which “default.aspx” is added to the URL, that is okay too, but I don’t want to have to make the end-user type the file path at the end when entering the URL into the browser. Here is my current rewriting code. Any help is greatly appreciated!
<rewrite>
<rules>
<rules>
<rule name="Handle Primary URLs" stopProcessing="true">
<match url="^([_0-9a-z-]+)/(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^(mydomain.com|www.mydomain.com)$" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="{R:2}.aspx?q={R:1}" appendQueryString="true" />
</rule>
<rule name="remove aspx">
<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>
</rules>
</rules>
</rewrite>

Related

IIS URL Rewrite with wild card

I need to change current URL pattern (hotels/{City}) to more SEO friendly one villa-{city} and I need to add a wild card for cities. Any city name should allow by the site and previous URL pattern need to rewrite as new pattern. I tried the below rewrite and its working for redirection but it effects on other URL patterns like "hotels/{name}/{code}" too. How can I overcome this redirection effecting on other patterns?
Can someone help me with this?
I would like to know how can we determine whether we use {R:0} Or {R:1} for conditions and the purpose of adding "^" to patterns
<rule name="HotelToVilla" stopProcessing="true">
<match url="hotels/(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="localhost:23617" />
</conditions>
<action type="Redirect" url="http://localhost:23617/villa-{R:1}" appendQueryString="false" redirectType="Permanent" />
</rule>

IIS URL Rewriting best practices for matching

I'm deploying an Angular 5.x app that runs inside ASP.NET MVC. When doing this, I've considered the following options:
Deploy it at "/" inside the web sites index.cshtml page
Create it's own controller (so deploy it at "/myapp/")
Create another virtual directory just for the Angular app.
The problem with the first item is that I have the Angular routes as well as other URL's that all hang off of "/".
The second item may be ok but I'm not sure how well rewriting back to "/subpage/" works. Opinions?
The third would make the URL Rewriting easy but would mess with the SAML based auth.
Assuming I go with the first or second choice, is there a good way to white list or black list a set of URLs for the rewrite rule. So that I can either say that this rule applies to all my angular routes or that it does not apply to my non-angular URLs.
Per LexLi's suggestion, I'm trying:
<rewrite>
<rules>
<rule name="Angular Routes" stopProcessing="true">
<match url=".*" ignoreCase="true"/>
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="Account/*" negate="true" ignoreCase="true" />
<add input="{REQUEST_URI}" pattern="SAML/*" negate="true" ignoreCase="true" />
<add input="{REQUEST_URI}" pattern="Sites/*" negate="true" ignoreCase="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
However, the .* in the match is not working. If I put something more specific in, it does work.

IIS URL Rewriting rule - exclude ALL files and a specific path

I want to create a URL rewrite rule that adds a / on URLs that don't have one so for example:
www.domain.com/news/latest will get redirected to www.domain.com/news/latest/
The rule below does exactly that, but the problem I am having is two fold:
This rewrite rule is getting applied to things like image files.
So For example domain.com/globalassets/icons/image.svg gets changed to domain.com/globalassets/icons/image.svg/ causing a 404 its not happening with CSS files which is strange, maybe because I am adding them using the RegisterBundles method in MVC?
This is a ASP.NET MVC based website using a CMS (episerver) so I want to ignore any redirects in the Admin area so I added a second rule, but again its doing this to the CSS and images breaking the admin area.
This is what I have got so far, can anyone help me get this rule working correctly?
<rewrite>
<rules>
<rule name="Exclude Slash Episerver " stopProcessing="true">
<match url="^episerver/" />
<action type="None" />
</rule>
<rule name="Add trailing slash" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}/" />
</rule>
</rules>
</rewrite>
Common SEO rewrite rules for IIS such as this one are documented here.
In particular, with the Trailing Slash rule you are missing the logicalGrouping="MatchAll" attribute:
Conditions are defined within a <conditions> collection of a rewrite rule. This collection has an attribute called logicalGrouping that controls how conditions are evaluated. If a rule has conditions, then the rule action is performed only if rule pattern is matched and:
All conditions were evaluated as true, provided that logicalGrouping="MatchAll" was used.
At least one of the conditions was evaluated as true, provided that logicalGrouping="MatchAny" was used.
Without this setting, it is adding a trailing slash to your file names because it is matching when any of your negated rules match rather than all of them.
The entire Trailing Slash rule from the above link is:
<rule name="Trailing Slash" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{URL}" pattern="WebResource.axd" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}/" />
</rule>

IIS Rewrite module - how to redirect maintaining path and querystring but adding an extra querystring parameter?

I've been banging my head against a brick wall attempting to get some IIS redirect rules to work. I've searched and read stuff here on Stack Overflow and on IIS.net but it just doesn't work at all.
I'm trying it on my local (real) IIS, I have the rewrite 2.0 module installed and have tried doing a repair install on it. I've done an iisreset at an admin cmd line more times than I care to mention.
In my hosts file I have set-up 127.0.0.1 for the URL my.test.com.
What I want to achieve is given a sub-domain URL redirect to the main domain URL with an extra querystring parameter whilst maintaining the existing path and querystring values if they exist.
I setup 3 rules as follows that are in the root folder of the website:
<system.webServer>
<rewrite>
<rules>
<rule name="PathAndQueryString" enabled="true" stopProcessing="true">
<match url="(/\w*)(\?\w*=\w*)([&\w*=\w*]*)" />
<action type="Redirect" url="https://www.test.com{R:1}{R:2}{R:3}&param=value" appendQueryString="false" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="my.test.com" />
</conditions>
</rule>
<rule name="Querstring" enabled="true" stopProcessing="true">
<match url="(\?\w*=\w*)([&\w*=\w*]*)" />
<action type="Redirect" url="https://www.test.com{R:1}{R:2}&param=value" appendQueryString="false" />
<conditions>
<add input="{HTTP_HOST}" pattern="my.test.com" />
</conditions>
</rule>
<rule name="DomainOnly" enabled="true" stopProcessing="true">
<match url=".*" />
<action type="Redirect" url="https://www.test.com?param=value" appendQueryString="false" />
<conditions>
<add input="{HTTP_HOST}" pattern="my.test.com" />
</conditions>
</rule>
</rules>
</rewrite>
</system.webServer>
Unfortunately despite testing the patterns and confirming the {R:x} captures are correct when I try to test this using Edge, Chrome, Firefox and IE for all of them IIS acts like the rules don't exist.
Tests:
https://my.test.com >> https://www.test.com?param=value
https://my.test.com/SomePath >> https://www.test.com/SomePath
https://my.test.com/SomePath?AParam=AValue >>
https://www.test.com/SomePath?AParam=AValue&param=value
None of the above tests work, they get served without a redirect.
I've also tried putting the condition pattern used as part of the Match URL pattern but it didn't work with that either; in fact I moved it to the condition after reading a Stack Overflow post which said when rules are in the root of the site it doesn't include the host, but still nothing works.
Any help would be much appreciated.
UPDATE 1: For the path and querystring rule tried removing the bolded part from that start of this pattern (/\w*). Didn't have any effect.
UPDATE 2: Tried enabling the extremely temperamental "Failed Request Tracing" functionality and when it is actually working it says that none of the Match URL patterns are matching, except for the 3rd rule which has now started kicking in and redirecting but is not maintaining the path and other querystring params for obvious reasons.
UPDATE 3: On Edge and IE none of the rules work at all. On Chrome and FF the domain only redirect appears to be working - however if I disable the domain only rule and restart IIS it acts as though the rule is still there - FFS give me strength this crap is really starting to boil my blood now - this should not be that damn difficult.
Before I give the answer, a shout out to Yuk Ding at Microsoft who responded to a copy of this post on the iis.net forums and provided most of the answer.
So here we go, if you want rewrite rules that redirects from 1 URL to another maintaining the path and querystring if they exist whilst at the same time adding on a hardcoded URL parameter with the appropriate & or ? then here are the rules you will need.
In the rules you are redirecting from my.test.com to www.test.com, but obviously you would need to replace those 2 URLs in the rules below as well as changed the hardcoded parameter "ExtraParam=SomeValue" to what you need.
<system.webServer>
<rewrite>
<rules>
<rule name="DomainOnly" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions trackAllCaptures="true">
<add input="{HTTP_HOST}" pattern="my.test.com" />
<add input="{REQUEST_URI}" pattern="/.+" negate="true" />
</conditions>
<action type="Redirect" url="http://www.test.com?ExtraParam=SomeValue" redirectType="Temporary" />
</rule>
<rule name="PathOnly" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions trackAllCaptures="true">
<add input="{REQUEST_URI}" pattern="/.+" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="\?.+" ignoreCase="true" negate="true" />
<add input="{HTTP_HOST}" pattern="my.test.com" />
</conditions>
<action type="Redirect" url="http://www.test.com{C:0}?ExtraParam=SomeValue" redirectType="Temporary" />
</rule>
<rule name="Querstring" stopProcessing="true">
<match url="(.*)" />
<conditions trackAllCaptures="true">
<add input="{REQUEST_URI}" pattern="/.+" />
<add input="{QUERY_STRING}" pattern=".*" />
<add input="{HTTP_HOST}" pattern="my.test.com" />
</conditions>
<action type="Redirect" url="http://www.test.com{C:0}&ExtraParam=SomeValue" appendQueryString="false" redirectType="Temporary" />
</rule>
</rules>
</rewrite>
In my eyes the URL Rewrite 2.0 module has a bug. The basic crux is that you cannot match anything in the main match pattern you have to do everything with conditions. Thus the fact that you can set a pattern for the match is completely pointless because if you try to match anything other than (.*), i.e. match anything like I originally did it won't do what you want and will effectively cause head-bashing-brick-wall-ness.
The even more annoying thing is that in IIS Manager the UI for this is very unhelpful. You can test your patterns - and I did - and they will work, but all it's really testing is the regEx pattern.
What we really need is a test at the rules level. In other words you enter a URL and it tells you whether any of the rules match and which conditions pass or fail. Yes you can get this information if you enabled the failing request tracing rules but it's all a long winded phaff to enable and works in a haphazard fashion (just try clearing out the old logs and watch as it then stops logged until you turn it off and on again) for something that should be trivial.

Using IIS URL Rewrite to limit content to one of two domains results in redirect loop

I have two domain names for my website, one of which is the ubiquitous cookie-less static content domain. One name is merely an alias for the "main" name (using CNAME), so without additional configuration, any resource could be accessed through either domain. For security reasons in addition to just wanting navigation to be intuitive, I want to make sure that static content and only static content is available through the static domain, and in particular, that static content is NOT available through the main domain.
I accomplished the latter using IIS's URL Rewrite, with the following rule:
<rule name="StaticContentRes" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^maindomain$" />
<add input="{REQUEST_URI}" pattern="^/res/.*$" />
</conditions>
<action type="Redirect" url="https://staticdomain/{R:0}" />
</rule>
This works perfectly fine, and ensures requests for certain static content (all located in the "res" directory) are served only through staticdomain. However, I tried to further enforce that staticdomain be used ONLY for requests to that directory:
<rule name="RegularContent" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTP_HOST}" pattern="^staticdomain$" />
<add input="{REQUEST_URI}" pattern="^/res/.*$" negate="true" />
</conditions>
<action type="Redirect" url="https://maindomain/{R:0}" />
</rule>
Adding this second rule results in an infinite redirect loop whenever either domain is used to serve that directory. I'm completely stumped, as I thought the negate="true" logic was perfectly clean and workable. What can I do so that staticdomain requests are let through only if they're to the "res" dir, without incurring this loop?
As often seems to be the case, I found the issue immediately after posting this question. Having stopProcessing="true" in the first rule meant that the second rule would never be used, since the match patterns in the first rule catches everything. I didn't realize that the added conditions are not taken into account when deciding whether a request has officially matched a rule (for the purposes of stopProcessing), just the match pattern.

Resources