7

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.

Drew Noakes
  • 266,361
  • 143
  • 616
  • 705
Dan Ellis
  • 5,077
  • 7
  • 44
  • 71
  • Possible answer please check this http://stackoverflow.com/questions/1160105/asp-net-mvc-disable-browser-cache – MMK Aug 17 '12 at 10:59

3 Answers3

6

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>
Dan Ellis
  • 5,077
  • 7
  • 44
  • 71
  • Don't use this code! The code above has a nasty bug. If you are trying to do an error redirect (e.g. by using the httpErrors config section) it will get fed in something like `/Error/NotFound?404;http://localhost:81/e/e/e/e`, see the `//` in `http://` and then redirect to the original url, causing an infinite redirect loop. – Martin Capodici Oct 19 '18 at 06:28
3

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.

huysentruitw
  • 25,048
  • 8
  • 76
  • 120
  • Do you know if you can disable caching on a per rule basis? don't like the sound of disabling all the caching... – Dan Ellis Aug 17 '12 at 13:39
  • @Scrooby: maybe first try to add the registry key and see if it solves the problem. If it does, you can see if you can narrow it down. Note that you are only disabling URL rewrite caching, not content caching. This means the webserver has to match each request again. Unless you have 1K+ of simultanous users, this will not be a big problem. – huysentruitw Aug 17 '12 at 13:50
  • @Scrooby: I just had an idea of adding an non-cacheable server variable to the rule, see **Other option #1** in my answer. – huysentruitw Aug 17 '12 at 14:28
  • Thanks for the continued support. Setting the registry key did solve the issue, however, I would still like to find a solution for the single rule. I've tried the HTTP_USER_AGENT but that didn't resolve the issue, just trying a few different ones now. – Dan Ellis Aug 17 '12 at 20:13
  • Maybe the filter is smart and detects the `.*`. F.e. Try `REMOTE_PORT` with pattern `[0-9]+` – huysentruitw Aug 17 '12 at 20:24
  • No luck with that one either unfortunately. I set `logicalGrouping="MatchAll"` too, just to make sure it was matching all of the conditions. – Dan Ellis Aug 17 '12 at 20:42
0

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>
MMK
  • 3,465
  • 1
  • 18
  • 29
  • Hi, thanks for your response. Unfortunately this gave me the same result, sometimes it works, sometimes it doesn't. – Dan Ellis Aug 17 '12 at 12:51
  • IIS Url Rewrite is definitely installed. Your last rule you provided works, but only sometimes. It sounds like it's some kind of caching issue... – Dan Ellis Aug 17 '12 at 13:57
  • 1
    This worked for me. I had to add `appendQueryString="false"` to the ACTION directive or the URL query string would be duplicated. – James Moberg May 03 '19 at 21:01
  • Redirecting an HTTP POST will result in losing data, so you may want to add a negate rule to prevent redirecting form POSTs. `` – James Moberg May 03 '19 at 21:07