Bandwidth Leeching Prevention with Http Handlers
page 3 of 4
by Joseph Chahine
Feedback
Average Rating: 
Views (Total / Last 10 Days): 21447/ 70

Explanation

Let's examine how Microsoft's most popular web server parses Http requests. When Internet Information Services (IIS) receives an Http request, it parses the extension of the file targeted by the URL. Usually, file extensions are associated with assemblies containing methods and functions that will process requests. Mappings from file extensions to assemblies are saved in the IIS metabase. When ASP.NET is installed, it adds entries to the metabase associating some file extensions including .aspx and .asmx with the "aspnet_isapi.dll" assembly file.

The "HTTP_REFERER" server variable can tell when a request is made from another website. If someone puts the URL of an image, for example, into a web browser, or follows a direct link from an email, there won't be a referrer.

In .NET, an Http Handler class should implement the "IHttpHandler" interface as per the following code listing.

To go in tandem with this article's contents, it is recommended that you try to implement and test an Http Handler yourself. It's an easy task. Start by opening Visual Studio .NET. Create a Class Library project and name it "HttpHandlersLibrary." Delete the "Class1.vb" (or "Class1.cs") file created by default and create a class called "FileTypeHandler.vb" (or "FileTypeHandler.cs"). Replace the contents of the already created class by the contents of the following listing and rebuild the project. In the bin folder, the "HttpHandlersLibrary.dll" assembly file will be created.

 

Listing 1 - VB Code

Imports System
Imports System.Web
 
Public Class FileTypeHandler
    Implements IHttpHandler
 
    '' The ProcessRequest method decides what to do with the request.
    Public Sub ProcessRequest(ByVal Context As System.Web.HttpContext)_
 Implements System.Web.IHttpHandler.ProcessRequest
        If Context.Request.ServerVariables("HTTP_REFERER"Is Nothing Then Exit Sub
 
        '' strFileName holds the full path of the request, 
''for example http://domain/folder/page.aspx
        Dim strFileName As String = Context.Server.MapPath(Context.Request.FilePath)
 
        Dim cfg As New System.Configuration.AppSettingsReader
 
        '' The strDomainNameCollection is an array of comma-separated
        '' values holding the address(es) of your website.
        Dim strDomainNameCollection As String() = CType(cfg.GetValue("DomainName", _
GetType(System.String)), String).ToLower.Split(",")
 
        '' Now we check if the Http Referrer is listed in strDomainNameCollection.
        If Array.IndexOf(strDomainNameCollection, _
 Context.Request.ServerVariables("HTTP_REFERER").ToLower.Split("/")(2)) > -1 Then
            Select Case strFileName.Split(".")(strFileName.Split(".").Length - 1).ToLower
                Case "jpg""jpeg"
                    Context.Response.ContentType = "image/JPEG"
                    Context.Response.WriteFile(strFileName)
                Case "gif"
                    Context.Response.ContentType = "image/GIF"
                    Context.Response.WriteFile(strFileName)
                Case "js"
                    Context.Response.ContentType = "text/javascript"
                    Context.Response.WriteFile(strFileName)
                Case "css"
                    Context.Response.ContentType = "text/css"
                    Context.Response.WriteFile(strFileName)
                Case Else
            End Select
        End If
    End Sub
 
 
    '' This property tells the server whether or not the handler object can be reused.
    Public ReadOnly Property IsReusable() As Boolean _
 Implements System.Web.IHttpHandler.IsReusable
        Get
            Return True
        End Get
    End Property
 
End Class

Listing 2 - C# Code

using System;
using System.Web;
 
namespace HttpHandlersLibrary
{
  public class FileTypeHandler: IHttpHandler
  {
    /// The ProcessRequest method decides what to do with the request.  
    public void ProcessRequest(System.Web.HttpContext Context)
    {
      if (Context.Request.ServerVariables["HTTP_REFERER"] == null)
      {
        return ;
      }
 
      /*strFileName holds the full path of the request, for example
       http://domain/folder/page.aspx*/
      string strFileName = Context.Server.MapPath(Context.Request.FilePath);
 
      System.Configuration.AppSettingsReader cfg = new
        System.Configuration.AppSettingsReader();
 
       /// The strDomainNameCollection is an array of comma-separated
       /// values holding the address(es) of your website.
      string[]strDomainNameCollection = System.Convert.ToString(cfg.GetValue(
        "DomainName", typeof(System.String))).ToLower().Split(Convert.ToChar(
        ","));
 
      /// Now we check if the Http Referrer is listed in strDomainNameCollection.
      if (Array.IndexOf(strDomainNameCollection,
        Context.Request.ServerVariables["HTTP_REFERER"].ToLower().Split
        (Convert.ToChar("/"))[2]) >  - 1)
      {
        switch (strFileName.Split(Convert.ToChar("."))[strFileName.Split
          (Convert.ToChar(".")).Length - 1].ToLower())
        {
          case "jpg":
            Context.Response.ContentType = "image/JPEG";
            Context.Response.WriteFile(strFileName);
            break;
          case "jpeg":
            Context.Response.ContentType = "image/JPEG";
            Context.Response.WriteFile(strFileName);
            break;
          case "gif":
            Context.Response.ContentType = "image/GIF";
            Context.Response.WriteFile(strFileName);
            break;
          case "js":
            Context.Response.ContentType = "text/javascript";
            Context.Response.WriteFile(strFileName);
            break;
          case "css":
            Context.Response.ContentType = "text/css";
            Context.Response.WriteFile(strFileName);
            break;
          default:
            break;
        }
      }
    }
 
/* This property tells the server whether or not the handler object can be reused.*/
    public bool IsReusable
    {
      get
      {
        return true;
      }
    }
 
  }
}

Now use Visual Studio .NET to create an ASP.NET Web Application project in the following location http://localhost/TestingHttpHandlers. Delete the "WebForm1.aspx" file and create a Web Page called "Default.aspx." Drag and drop into this page a .jpg or .jpeg or .gif picture that you've already included in the solution.

Now you need to map the file extensions to the new Http Handler(s) assembly(ies) in IIS. For this purpose, go to the Internet Information Services manager console (you can do this by typing in your Run command "inetmgr.msc" without the quotes), right click the already created website (or virtual directory), select the "Home Directory" (or "Virtual Directory") tab, click the "Configuration" button (see Figure 1) and select the "Mappings" tab in the pop-up, click the "Add" button (see Figure 2) and browse to select the "HttpHandlersLibrary.dll" file previously created, input ".jpg" (without the quotes) in the "Extension" field and click the "OK" button (see Figure 3). Follow the same way to add mappings for .jpeg, .gif, .css, and .js extensions.

Figure 1

 

Figure 2

 

Figure 3

 

One more thing to do is to add the "HttpHandlers" entry in the Web.config file. This informs the .NET Framework about the mappings between handlers and file extensions. The same way we did above to map file extensions to assemblies in IIS, we need to map file extensions to handler classes since the "HttpHandlersLibrary.dll" assembly can hold multiple classes implementing the IHttpHandler interface.

Listing 3

<configuration>
    <system.web>
        <HttpHandlers>
            <add verb="*"
 path="*.jpg" type="HttpHandlersLibrary.FileTypeHandler, HttpHandlersLibrary"/>
            <add verb="*"
 path="*.jpeg" type="HttpHandlersLibrary.FileTypeHandler, HttpHandlersLibrary"/>
            <add verb="*"
 path="*.gif" type="HttpHandlersLibrary.FileTypeHandler, HttpHandlersLibrary"/>
            <add verb="*"
 path="*.js" type="HttpHandlersLibrary.FileTypeHandler, HttpHandlersLibrary"/>
            <add verb="*"
 path="*.css" type="HttpHandlersLibrary.FileTypeHandler, HttpHandlersLibrary"/>
        </HttpHandlers>
    </system.web>
 
    <appSettings>
        <add key="DomainName"
 value="127.0.0.1,localhost"/>
    </appSettings>
</configuration>

If you're using Visual Studio .NET 2003 make sure to write "httpHandlers" with a lower case starting "h" character.

You need to add for each file extension a sub-entry in the "HttpHandlers" section. The path contains the extensions each preceded by a wildcard. The type has the following format "NamespaceName.ClassName, AssemblyName." Make sure to respect the casing in "Web.config" since it's a case-sensitive file.

Note the "appSettings" section of the "Web.config" file, I have included in it the domain address(es) considered as trusted.

Now it's time to test what you've done so far.

Run the web application locally, you'll see that the image will show up in the page. If you now try to access the image directly through http://localhost/TestingHttpHandlers/ImageName.jpg, you'll get a blank page since the "HTTP_REFERER" server variable is not defined. Same thing will happen if you try to directly access this image from another computer since the "HTTP_REFERER" will hold the address of the latter computer which is not listing in the "DomainName" key in the "appSettings" section.


View Entire Article

User Comments

No comments posted yet.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2021 ASPAlliance.com  |  Page Processed at 2021-03-07 4:35:26 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search