Search code examples
c#query-stringhttpmodulerequest.querystring

Understanding HttpModules and URL manipulation


A project I'm working on integrates with a php app (Revive AdServer FWIW). We control the server it's deployed to, but altering the code I believe is out of the question. Revive has invocation javascript code you deploy to sites where you'd like to serve ads and when the code renders on those sites, it calls the php app and intelligently displays an ad based on the query string passed in.

What we need to do is intercept the call after it's made from one of those sites and before it hits the php app and manipulate the query string. To do this, I've written an HttpModule which we've added to IIS on the php app. Here is the code:

public class AdServerModule : IHttpModule
{
    public void OnBeginRequest(object sender, EventArgs e)
    {
        var context = ((HttpApplication)sender).Context;
        var queryString = context.Request.QueryString;
        var readonlyProperty = queryString.GetType().GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
        readonlyProperty.SetValue(queryString, false, null);
        queryString.Add("foo", "bar");
        readonlyProperty.SetValue(queryString, true, null);
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(OnBeginRequest);
    }
}

In this example, you can see I'm using reflection to add &foo=bar on to the query string of the Request. I'm not sure if I misunderstand what should happen, but I'm expecting to see this somewhere in the Request, but I'm not.

Additionally, I haven't tried to stumble around the php code very much, but I believe it's checking the URL of the request for query strings values so it would seem that I need to change the URL not just manipulate the context.Request.Query string property (which don't seem to be one in the same). I'm wondering if I need to implement a UrlRewriter (which I'm not familiar with doing). In one example I saw, context.RewritePath() was called, but that would seem to cause a infinite loop/stack overflow if used in an HttpModule.

Thanks in advance for any help.


Solution

  • I was able to figure it out. It turns out you do need to use the RewritePath() method. I was originally not using it correctly. Here is my code now:

    public class AdServerModule : IHttpModule
    {
        public void OnBeginRequest(object sender, EventArgs e)
        {
            var context = ((HttpApplication)sender).Context;
            var queryString = context.Request.QueryString;
            var readonlyProperty = queryString.GetType().GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
            readonlyProperty.SetValue(queryString, false, null);
            queryString.Add("foo", "bar");
    
            var path = GetVirtualPath(context);
            context.RewritePath(path, String.Empty, queryString.ToString());
    
            readonlyProperty.SetValue(queryString, true, null);
        }
    
        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(OnBeginRequest);
        }
    
        private static string GetVirtualPath(HttpContext context)
        {
            string path = context.Request.RawUrl;
            var queryStringLength = path.IndexOf("?");
            path = path.Substring(0, queryStringLength >= 0 ? queryStringLength : path.Length);
            path = path.Substring(path.LastIndexOf("/") + 1);
            return path;
        }
    }
    

    You can see where I've added the context.RewritePath() call. Works like a charm!