managedfusion/managedfusion-rewriter — pull request #6 by AlphaGit (2013-10-11 21:56:57+00:00)
Title: Fixed proxy issues without trailing slash

(From http://stackoverflow.com/q/19301437/147507)

## Description of problem

I'm using ManagedFusion Rewriter as a reverse proxy. The configuration is fairly simple:

RewriteRule ^/api/(.*) http://www.example.com/api/$1 [P]

This will work pretty much for any URL. However, if the URL happens to *not* end on a trailing slash, it will fail.

A request like this will go fine perfectly: `GET api/report/`

2013-10-10T11:27:11 [Rewrite] Input: http://localhost:50070/api/report/
2013-10-10T11:27:11 [Rule 0] Input: /api/report/
2013-10-10T11:27:11 [Rule 0] Rule Pattern Matched
2013-10-10T11:27:11 [Rule 0] Output: http://www.example.com/api/report/
2013-10-10T11:27:11 [Rewrite] Proxy: http://www.example.com/api/report/
2013-10-10T11:27:11 **********************************************************************************
2013-10-10T11:27:11 [Proxy] Request: http://www.example.com/api/report/
2013-10-10T11:27:12 [Proxy] System.Net.HttpWebResponse
2013-10-10T11:27:12 [Proxy] Received '200 OK'
2013-10-10T11:27:12 [Proxy] Response: http://localhost:50070/api/report/
2013-10-10T11:27:12 [Proxy] Response is being buffered
2013-10-10T11:27:12 [Proxy] Responding '200 OK'

However, a request like this will return a 404 without even making the request on the proxied URL: `GET api/report/1`

2013-10-10T11:27:13 [Rewrite] Input: http://localhost:50070/api/report/1
2013-10-10T11:27:13 [Rule 0] Input: /api/report/1
2013-10-10T11:27:13 [Rule 0] Rule Pattern Matched
2013-10-10T11:27:13 [Rule 0] Output: http://www.example.com/api/report/1
2013-10-10T11:27:13 [Rewrite] Proxy: http://www.example.com/api/report/1
(the log file finishes right here)

This is my whole configuration file:

RewriteEngine On
RewriteLog "log.txt"
RewriteLogLevel 9
RewriteRule ^/api/(.*) http://www.example.com/api/$1 [P]

## Description of solution

The class ManagedFusion.Rewriter.RewriterModule contains the following two methods:

private void context_PostResolveRequestCache(object sender, EventArgs e)
{
var context = new HttpContextWrapper(((HttpApplication)sender).Context);

// check to see if this is a proxy request
if (context.Items.Contains(Manager.ProxyHandlerStorageName))
context.RewritePath("~/RewriterProxy.axd");
}

private void context_PostMapRequestHandler(object sender, EventArgs e)
{
var context = new HttpContextWrapper(((HttpApplication)sender).Context);

// check to see if this is a proxy request
if (context.Items.Contains(Manager.ProxyHandlerStorageName))
{
var proxy = context.Items[Manager.ProxyHandlerStorageName] as IHttpProxyHandler;

context.RewritePath("~" + proxy.ResponseUrl.PathAndQuery);
context.Handler = proxy;
}
}

As the names imply, the first one is the handler of `PostResolveRequestCache`, while the second one is the handler for `PostMapRequestHandler`.

In both of my example requests, the `PostResolveRequestCache` handler was being invoked and working fine. However, for my failing request, `PostMapRequestHandler` was not being executed.

This made me think that maybe, for some reason, rewriting a specific resource that does not look like a directory to a resource that looks like a file through the usage of `RewritePath` was preventing the actual actual handler from being picked up, thus preventing the raising of `PostMapRequestHandler`.

As such, I upgraded the Rewriter project from .NET 3.5 to 4.5 and replaced these lines:

if (context.Items.Contains(Manager.ProxyHandlerStorageName))
context.RewritePath("~/RewriterProxy.axd");

by these ones

if (context.Items.Contains(Manager.ProxyHandlerStorageName)) {
var proxyHandler = context.Items[Manager.ProxyHandlerStorageName] as IHttpHandler;
context.RemapHandler(proxyHandler);
}

With this, all the requests were being properly picked up by the handler and started working.

---

As a side note, I had some mistakes in the original rules, instead of

RewriteRule ^/api/(.*) http://www.example.com/api/$1 [P]

It should have been:

RewriteRule ^/api/(.*) http://www.example.com/api/$1 [QSA,P,NC]

- `QSA` to append the query string of the original request
- `NC` to match the regex case insensitive