Search code examples
c#asp.netiis-6ihttphandlerweb-config

HttpHeader Duplicate Paths


I am using IHttpHeader to redirect 403 requests to a 404. This is running on a .Net 3.5 Web Forms and IIS 6 setup.

<add verb="*" path="products/" type="RequestCheck.NoAccessHandler, RequestCheck, Version=1.0.0.0, Culture=neutral" />

The site is also running with a CMS system handled by another department, and all of their files are under a marketing folder, in which they also have a products folder.

Directory structure

\Root
    \products
    \marketing
        \products
            default.asp

Before I realized this marketing folder existed (we don't get to see it in development) the following code was working fine.

    public void ProcessRequest(HttpContext context)
    {
        context.Response.StatusCode = (int)HttpStatusCode.NotFound;
        context.Response.Redirect("~/NotFound.aspx");
    }

We have a link in the navigation similar to this

http://mysite/marketing/products

Which of course now redirects to the NotFound.aspx page, since it is going to products/ If you navigate directly to the default.asp inside of it, you can get to the page.

The easy fix is to just update the navigation to use the following url

http://mysite/marketing/products/default.asp

This isn't a fix for us, because they want me to handle it in code. So I changed my handler to the following.

    public void ProcessRequest(HttpContext context)
    {
        var url = context.Request.Url.ToString().ToLower();
        if (url.Contains("/mtgmktg/")) // ignore any requests coming for the CMS folders
        {
            return;
        }
        else // everything else gets a 404
        {
            context.Response.StatusCode = (int)HttpStatusCode.NotFound;
            context.Response.Redirect("~/NotFound.aspx");
        }
    }

And this...

    public void ProcessRequest(HttpContext context)
    {
        var url = context.Request.Url.ToString().ToLower();
        if (!url.Contains("/mtgmktg/")) // ignore any requests coming for the CMS folders
        {
            // everything else gets a 404
            context.Response.StatusCode = (int)HttpStatusCode.NotFound;
            context.Response.Redirect("~/NotFound.aspx");
        }
    }

but both of these just send me to a blank page, it doesn't render anything. Then I tried this...

Bad Code

    public void ProcessRequest(HttpContext context)
    {
        var url = context.Request.Url.ToString().ToLower();
        if (url.Contains("/mtgmktg/")) // ignore any requests coming for the CMS folders
        {
            context.Response.Redirect(url); // This causes an infinite loop
        }
        else // everything else gets a 404
        {
            context.Response.StatusCode = (int)HttpStatusCode.NotFound;
            context.Response.Redirect("~/NotFound.aspx");
        }
    }

Now it just goes to a "This page can't be displayed"

I have also tried removing the marketing folder through the config, but that just gets ignored. I tried putting this before and after my add above. neither one does anything.

<remove verb="*" path="marketing/" />
OR
<remove verb="*" path="marketing/products/" />

Does anyone have any other ideas? Remember, I cannot change the link in the navigation.

Update 1

The blank page is because I didn't pay attention to what I did... The last code sample causes an infinite loop, crashing the page. So I need to rollback to one of the previous samples that are causing the blank page.


Solution

  • Try one of these approaches.

    1. Change the path that you use when registering the handler. Add a leading /

      <add verb="*"
          path="/products/"
          type="RequestCheck.NoAccessHandler, RequestCheck, Version=1.0.0.0, Culture=neutral"
      />
      
    2. Add the handler within a <location></location> block. The location block goes directly into the <configuration></configuration> element in the web config:

      <configuration>
          ... other stuff in the web.config ....
          <location path="products">
              <system.web>
                  <httpHandlers>
                      <add verb="*"
                          path="products/"
                          type="RequestCheck.NoAccessHandler, RequestCheck, Version=1.0.0.0, Culture=neutral"
                      />
                  </httpHandlers>
              </system.web>
          </location>
      </configuration>
      

    Note 1: The call to context.Response.Redirect overrides the status code set on the line above. What the browser ends up seeing is a 302 (=redirect) response. The line:

    context.Response.StatusCode = (int)HttpStatusCode.NotFound;
    

    can be removed if you are anyway going to perform a redirect...

    Note 2: Your approach with trying to check the path and avoid redirecting in some cases will not work. If I read your question right, you want .../marketing/products/ to be handled by ...marketing/products/Default.aspx. But .aspx files are handled by a different IHttpHandler. By the time your code runs, your custom handler has already been selected as the handler for the request. IT is the responsible for generating a response. It's too late then to try to hand the request over to a different handler. So when you simply return from the ProcessRequest method, you are abandoning the request without sending a response. Therefore the empty page.