What I basically need is to manage a large set of URL rewrites and redirects. The redirects are easy to do but the rewrites should be proxyed through the ARR proxy in IIS. As far as I can tell the IIS rewrite module uses the native setUrl API in IIS to get the ARR proxy to forward the request. I'm not up to the task of writing a native module so I thought it might be possible to write a managed module to do the same.
@CarlosAg: Just to expand my comment on your answer. Heres the rules and providers I need to set up to make the rewrite module do what I want. Is it just me or doesn't it seem a little like manipulating the rewrite module into doing something it wasn't supposed to do?
<rewrite>
<providers>
<provider name="CustomRewrite" type="MyRewriteProviders.RewriteProvider, MyRewriteProviders, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e72501f8a0edfe78" />
<provider name="CustomRedirectTemporary" type="MyRewriteProviders.RedirectTemporaryProvider, MyRewriteProviders, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e72501f8a0edfe78" />
<provider name="CustomRedirectPermanent" type="MyRewriteProviders.RedirectPermanentProvider, MyRewriteProviders, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e72501f8a0edfe78" />
</providers>
<rules>
<clear />
<rule name="Set Http">
<match url="." />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<serverVariables>
<set name="RequestProtocol" value="http" />
</serverVariables>
<action type="None" />
</rule>
<rule name="Set Https">
<match url="." />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTPS}" pattern="ON" />
</conditions>
<serverVariables>
<set name="RequestProtocol" value="https" />
</serverVariables>
<action type="None" />
</rule>
<rule name="Custom Rewrite">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{CustomRewrite:{RequestProtocol}://{HTTP_HOST}/{URL}}" pattern="(.+)" />
</conditions>
<action type="Rewrite" url="{C:1}" logRewrittenUrl="true" />
</rule>
<rule name="Custom Redirect (Temporary)" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{CustomRedirectTemporary:{RequestProtocol}://{HTTP_HOST}/{URL}}" pattern="(.+)" />
</conditions>
<action type="Redirect" url="{C:1}" redirectType="Found" appendQueryString="false" />
</rule>
<rule name="Custom Redirect (Permanent)" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{CustomRedirectPermanent:{RequestProtocol}://{HTTP_HOST}/{URL}}" pattern="(.+)" />
</conditions>
<action type="Redirect" url="{C:1}" appendQueryString="false" />
</rule>
</rules>
</rewrite>
And the provider's code:
using System;
using System.Collections.Generic;
using Microsoft.Web.Iis.Rewrite;
namespace MyRewriteProviders
{
public enum ActionType
{
Rewrite,
RedirectPermanent,
RedirectTemporary
}
public abstract class BaseProvider : IRewriteProvider
{
protected abstract ActionType Action { get; }
public void Initialize(IDictionary<string, string> settings, IRewriteContext rewriteContext) {}
public string Rewrite(string value)
{
return RewriteEngine.RewriteUri(value, ActionType.Rewrite);
}
}
public class RewriteProvider : BaseProvider
{
protected override ActionType Action
{
get { return ActionType.Rewrite; }
}
}
public class RedirectTemporaryProvider : BaseProvider
{
protected override ActionType Action
{
get { return ActionType.RedirectTemporary; }
}
}
public class RedirectPermanentProvider : BaseProvider
{
protected override ActionType Action
{
get { return ActionType.RedirectPermanent; }
}
}
public static class RewriteEngine
{
public static string RewriteUri(string uri, ActionType action)
{
// Not actual rule engine implementation... just to demonstrate what it would do.
var ub = new UriBuilder(uri);
// Simulate a match on a rewrite rule
if (string.Equals(ub.Host, "rewrite.com", StringComparison.InvariantCultureIgnoreCase) && action == ActionType.Rewrite)
{
ub.Host = "rewrite-rewritten.com";
return ub.ToString();
}
// Simulate a match on a temporary redirect rule
if (string.Equals(ub.Host, "redirect.com", StringComparison.InvariantCultureIgnoreCase) && action == ActionType.RedirectTemporary)
{
ub.Host = "redirect-rewritten.com";
return ub.ToString();
}
// No rules matched. This will make the condition in the rewrite rule not match.
return string.Empty;
}
}
}
Apart from that, you need to setup IIS to allow the custom server variable and you need to sign and register the providers in the gac... This seems just a little more complicated than simply to be able to manipulate the request url like you are from the native api.
I've ended up using the ManagedFusion rewriter. The main reason is that this module seems fairly extensible and it also sports a built-in proxy. Whether it performs or not, only time, and a couple of tests, will tell.