I have two IIS websites set up on the same IIS server. Website A contains most of the content and this is what users are shown when requesting our address (e.g. www.websitea.com). Website B is a separate project that contains just a part of the whole content, so it is internal (bound in IIS to websiteb.com), but through a URL Rewrite, users can get to it by typing www.websitea.com/websiteb.
The URL rewrite looks like this in website A's web.config:
<rewrite>
<rules>
<clear />
<rule name="Website B rewrite rule" stopProcessing="true">
<match url="^websiteb(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{CACHE_URL}" pattern="^(https?)://" />
</conditions>
<action type="Rewrite" url="{C:1}://websiteb.com{R:1}" />
</rule>
</rules>
</rewrite>
The {CACHE_URL} and {C:1} bits are to keep the protocol used. E.g. a user requesting www.websitea.com/websiteb/foo.html on HTTP gets "rewritten" to websiteb.com/foo.html on HTTP, and a request to websitea.com/websiteb/bar.html on HTTPS gets "rewritten" to websiteb.com/bar.html on HTTPS.
Now, for some Website B pages we want the user to use HTTPS only - this is set in our SomePageViewModel's ShouldBeHttps property. So the following code is used in an ActionFilterAttribute:
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.HttpContext.Request.IsSecureConnection)
return;
var result = filterContext.Result as ViewResult;
if (result != null)
{
if ((result.Model as SomePageViewModel).ShouldBeHttps)
{
HandleNonHttpsRequest(filterContext);
}
}
}
protected virtual void HandleNonHttpsRequest(ActionExecutedContext filterContext)
{
if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException("The method must be a GET");
string url = filterContext.HttpContext.Request.Url.ToString().Replace("http:", "https:");
filterContext.Result = new RedirectResult(url);
}
Let's say www.websitea.com/websiteb/securepage.html will result in a true value in the ShouldBeHttps property.
Now, when I test it directly on the server by going to websiteb.com/securepage.html on HTTP, I get correctly redirected (status code 302) to websiteb.com/securepage.html on HTTPS.
I would expect that when I go to www.websitea.com/websiteb/securepage.html on HTTP, I will be redirected to www.websitea.com/websiteb/securepage.html on HTTPS. However, my browsers end up in a redirect loop (ERR_TOO_MANY_REDIRECTS). I can see in Fiddler in TextView tab that it seems to be correctly set up:
<html>
<head>
<title>Object moved</title>
</head>
<body>
<h2>Object moved to <a href="https://www.websitea.com/websiteb/securepage.html">here</a>.</h2>
</body>
</html>
But the Headers tab shows:
Response Headers
HTTP/1.1 302 Found
(...)
Transport
Location: http://www.websitea.com/websiteb/securepage.html
So instead of going to https, it is again http and that hits the filter again, and so on.
Is there anything I'm missing? Is it some IIS setting?