Rewrite rules in ISS's web.config - iis

I'm just trying to get some code running on ISS that has been running on Apache for a long time.
A particular mod_rewrite rule is proving difficult to get working.
In Apache I've used:
RewriteRule ^media/(js|css|img|font)/(.+)\.(\d+)\.(js|css|png|jpg|gif)$ /media/$1/$2.$4
[L]
To turn a URL like /media/css/style.1367406756.css into /media/css/style.css, letting me put timestamps in the files to avoid caching issues.
In my web.config file I've added:
<rule name="Cache bust assets" stopProcessing="true">
<match url="^(.*)$"/>
<conditions>
<add input="{URL}" pattern="^media/(js|css|img|font)/(.+)\.(\d+)\.(js|css|png|jpg|gif)$"/>
</conditions>
<action type="Rewrite" url="/media/{R:1}/{R:2}.{R:4}" appendQueryString="true" />
</rule>
Which, looks like it should work. (It's alongside another rule, which works fine, so it's not that the server isn't parsing it or anything).
I don't get any errors, other than visiting /media/css/style.1367406756.css gives me a 404 error.
How Can I make this work?

You use {R:N} back references in your action when you should use {C:N} since the information comes from the conditions. See Using Back-references in Rewrite Rules for more information.
You can see this error if you open the iismanager console:
To get your rule to work you have 2 solutions.
First you can change your action to (using {C:N}):
<action type="Rewrite" url="/media/{C:1}/{C:2}.{C:4}" appendQueryString="true" />
Or (and I do think it is a better solution), you can use the Import mod_rewrite Rules tool.
In the iismanager console, click on Import Rules... (on the right tab) and paste your apache rule:
This will create for you the following rule:
<rule name="Imported Rule 1" stopProcessing="true">
<match url="^media/(js|css|img|font)/(.+)\.(\d+)\.(js|css|png|jpg|gif)$" ignoreCase="false" />
<action type="Rewrite" url="/media/{R:1}/{R:2}.{R:4}" />
</rule>

Related

IIS URL Redirect failing

I need to redirect URLs of the form:
http://server1.name.here/path1/path2/?num=123456
to:
http://server2.name.here/path3/path2/?num=123456
using the IIS URL Rewrite Module 2.0 on IIS 8.5. I've used a DNS alias to handle the server name redirection.
I've been using the user interface to configure the path rewrite but despite trying several variations and extensive research I cannot get my rewrite to work, which is slightly embarrassing as I feel this should be a simple rewrite. The web.config produced by the URL rewite user interface is:
<rewrite>
<rules>
<rule name="path rewrite" patternSyntax="ECMAScript" stopProcessing="false">
<match url="path1/path2/" ignoreCase="true" />
<conditions>
<add input="{QUERY_STRING}" pattern="num=[0-9]+" />
</conditions>
<action type="Rewrite" url="path3/path2/" appendQueryString="true" logRewrittenUrl="true" />
</rule>
</rules>
</rewrite>
When I try to open server1.name.here/path1/path2/?num=123456 I get a "403 - Forbidden: Access is denied." and the logs show no evidence that my URL is being rewritten or even flagged by the rewrite rule.
I'm sure I'm missing something obvious, can anyone enlighten me as to what I've got wrong?
Many Thanks Eden

IIS Rewrite Rule - how to manipulate {HTTP_HOST} string

I've just started using iis rewrite rules for the first time and I'm struggling with what I imagine is an easy rule.
Basically, I wish to use this rule
<rule name="redirect">
<match url="^(one$|two$|three$)" />
<action type="Redirect" url="{HTTP_HOST}{REQUEST_URI}" />
</rule>
But have the redirect {HTTP_HOST} string minus the extension [.co.uk / .com etc.].
e.g.
bigsite.co.uk/one
would redirect to:
bigsite.co.uk/bigsite/one
How does one go about this - for I can only find Tolower / UrlEncode / UrlDecode string manipulators?
[Ultimately, I would also like to then use a rewrite rule to hide the fact that the redirect has occurred, i.e. the address would remain as bigsite.co.uk/one after the redirect.]
Well I eventually came up with this (hope it may help someone):
<rule name="redirect">
<match url="^(one$|two$|three$)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(www.)?(.*).co.uk" />
</conditions>
<action type="Redirect" url="{C:2}{REQUEST_URI}" />
</rule>
...not sure if there is a better way, but it works perfectly for me - thanks all, PP

IIS Rewrite Map not working

I'm rebuilding a site using iis urlrewriting on both static and dynamic pages. The redirects are all working well. The rewrite module is working perfectly.
Since the site structure is changing, I need to be able to redirect "old" defunct urls to new pages. So, for example, www.sitename.com/research.asp needs to be redirected to www.sitename.com/news
I've followed the instructions to set up a rule using a rewrite map and placed the rule near the top of my webconfig file (just under the CanonicalHostNameRule). But whatever permutations I've tried in the rule, I just can get it to work. The redirects don't happen - I just get a 404 for the (non-existent) .asp page. The map just seems to be getting ignored entirely. Just to re-iterate, all my other rules are working fine.
I've tried turning off all other rules and just working with this one, but no luck. Equally, I've trawled this forum and others for suggestions (using REQUEST_URI rather than Filename, restarting IIS, recycling App. Pools, etc etc), but nothing seems to work. The "Redirect" url="{C:1}" just sends me back to the old asp page I'm trying to get redirected away from, if that makes sense. Nothing in FailedRequestTracing seems to help, either.
Am I missing something very obvious here?
The Rule:
<rule name="Redirect Rule" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny" trackAllCaptures="false">
<add input="{StaticRedirects:{REQUEST_FILENAME}}" pattern="(.+)" />
</conditions>
<action type="Redirect" url="{C:1}" appendQueryString="false" redirectType="Permanent" />
</rule>
The Map:
<rewriteMaps>
<rewriteMap name="StaticRedirects">
<add key="research.asp" value="news" />
<add key="blog.asp" value="news" />
<add key="mentors.asp" value="interviews" />
<add key="regulars.asp" value="opinion" />
</rewriteMap>
</rewriteMaps>
NB - there are lots of other static redirects to add to this once it actually works, which is why I wanted to use a map.

Remove multiple forward slashes

I've noticed that with .NET MVC sites, you're able to hit URLs with multiple forward slashes, for example:
http://www.example.com//category
http://www.example.com//category//product
The URL loads fine and everything works, however, I've been asked to stop this from happening.
I've been trying to use IIS URL Rewrites to get it working:
<rewrite>
<rules>
<rule name="Remove multiple slashes" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{UNENCODED_URL}" matchType="Pattern" pattern="^(.*)//(.*)$" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{C:1}/{C:2}" />
</rule>
</rules>
</rewrite>
However, the results seem very temperamental. Sometimes the product URL will redirect, sometimes it won't and the same thing happens with the category. It's almost like the URL is being cached by the application.
Does anyone know if I can disable any caching that's in place, or if there is another way to get around this multiple slash issue?
Any help is much appreciated.
In the end, I have resorted to using a code behind redirect to get it working.
The issues I was having using the IIS URL Rewrites was due to the way IIS caches the redirects. When I disabled caching completely, as WouterH suggested, it worked. However, I'm not comfortable disabling caching in this way as it could introduce performance issues.
My fix was to use a code behind redirect in the Global.asax.cs file:
protected void Application_BeginRequest(object sender, EventArgs e)
{
string requestUrl = Request.ServerVariables["REQUEST_URI"];
string rewriteUrl = Request.ServerVariables["UNENCODED_URL"];
if (rewriteUrl.Contains("//") && !requestUrl.Contains("//"))
Response.RedirectPermanent(requestUrl);
}
I would have liked to use IIS URL Rewrite to get this working, unfortunately I didn't have the time to continue down that line.
Interestingly, the below method did work, however, the HTTP_X_REWRITE_URL is added by the Helicon ISAPI Rewrite which I'm running locally, but is not available on our production server.
<rewrite>
<rules>
<rule name="Remove multiple slashes" stopProcessing="true">
<match url=".*" />
<action type="Redirect" url="{REQUEST_URI}" />
<conditions>
<add input="{HTTP_X_REWRITE_URL}" pattern="([^/]*)/{2,}([^/]*)" />
</conditions>
</rule>
</rules>
</rewrite>
URL Rewrite Module
As IIS automatically normalizes url's with double slashes, you can try to redirect to the normalized url like this:
<rewrite>
<rules>
<rule name="Remove multiple slashes" stopProcessing="true">
<match url=".*" />
<action type="Redirect" url="{REQUEST_URI}" />
<conditions>
<add input="{UNENCODED_URL}" pattern="(.*?)[/]{2,}$" />
</conditions>
</rule>
</rules>
</rewrite>
You can also try to disable caching of the URL rewrite module:
Disabling internal caching of rewrite rules
To disable caching of inbound rewrite rules in URL Rewrite Module run
the following command from an elevated command prompt:
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp\Rewrite /v
RewriteCacheEnabled /t REG_DWORD /d 0
I have a small feeling that you'll have to restart the webserver after this change :)
Other option #1: non-cacheable server variable
This idea just popped into my mind:
use a non-cacheable server variable in the rule, f.e. try with HTTP_USER_AGENT
<rewrite>
<rules>
<rule name="Remove multiple slashes" stopProcessing="true">
<match url=".*" />
<action type="Redirect" url="{REQUEST_URI}" />
<conditions>
<add input="{UNENCODED_URL}" pattern="(.*?)[/]{2,}$" />
<add input="{HTTP_USER_AGENT}" pattern=".*" />
</conditions>
</rule>
</rules>
</rewrite>
You can explore other server variables here
Other option #2: clear browser cache
During web development, make sure you use Ctrl+F5 to refresh your page, or clear your browser cache after making changes like updating rewrite rules etc. Otherwise you can spend hours of watching to the same problem while it was just your browser that needed to refresh its cache.
Other option #3: IIRF
If you really can't get it to work with the IIS URL Rewrite Module, you can give the open-source ISAPI module IIRF a try. It accepts rules similar to mod_rewrite for Apache.
Try following
<rule name="RemoveMultipleSlashes" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*" />
<action type="Redirect" url="{REQUEST_URI}" />
<conditions>
<add input="{UNENCODED_URL}" pattern="([^/]*)/{2,}([^/]*)" />
</conditions>
</rule>

IIS UrlRewrite problem

I've been using the UrlRewrite IIS plugin for about a month on our production site.
I created a single redirect rule using the supplied template/wizard, the resulting config enrty is as follows:
<rewrite>
<rules>
<rule name="CanonicalHostNameRule1" enabled="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www\.mycompany\.com$" negate="true" />
</conditions>
<action type="Redirect" url="http://www.mycompany.com/{R:1}" />
</rule>
</rules>
</rewrite>
It's been running fine until this morning, when the site started erroring with "too many redirects". As far as I know, nothing in the configuration or infrastructure changed.
I disabled the rule, and the site became functional again (though clearly without any redirecting).
I then re-enabled the rule, and now all is running as expected. I didn't make any changes to the rule other than to temporarily disable it.
Any ideas? Is the plugin buggy?
I'd recommend setting this up:
http://learn.iis.net/page.aspx/467/using-failed-request-tracing-to-trace-rewrite-rules/
This may help you track down the problem if you start getting the "too many directs" error again.
Try this other code, i have on my web and run perfect:
<rule name="Canonical Host Name" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^yourdomain\.com$" />
</conditions>
<action type="Redirect" url="http://www.yourdomain.com/{R:0}" redirectType="Permanent" />
</rule>
The explanation is simple:
Match any URL received to process
The condition is that have anydomaintext.extension (your domain and extension) without prefix
Redirect to same domain with full prefix and put all url.
Other tries was R:1 but quit some of the main url and not run.
The sample from Ruslani:
http://blogs.iis.net/ruslany/archive/2009/04/08/10-url-rewriting-tips-and-tricks.aspx
I tried to use adding www but finally use the sample above.
The fix below worked for me. I discovered my rewrite rule was at out-of-date. The other domain had changed their URL policy and were now redirecting all traffic from otherdomain.com to www.otherdomain.com
<action type="Rewrite" url="http://otherdomain.com/abc/{R:1}" />
to
<action type="Rewrite" url="http://www.otherdomain.com/abc/{R:1}" />
Do you see the difference? By adding the 'www' I preempted the other domain redirection. I basically just complied with their new policy.

Resources