Creating an HTTP Handler for NonHTML Content

Some of the most interesting HTTP handlers don't generate HTML. Instead, they render different types of content, such as images. This approach gives you the flexibility to retrieve or generate your content programmatically, rather than relying on fixed files. For example, you could read the content for a large ZIP file from a database record and use Response.BinaryWrite() to send it to the client. Or, you could get even more ambitious and use your HTTP handler to dynamically create a ZIP archive that combines several smaller files. Either way, to the client who is using your HTTP handler, it seems as though the browser is downloading an ordinary file. But in actuality, the content is being served using ASP.NET code.

The following example demonstrates an HTTP handler that deals with image files. This handler doesn't create the image content dynamically (for that trick, refer to Chapter 29), but it does use code to perform another important task. Whenever an image is requested, this HTTP handler checks the referrer header of the request. The referrer header provides the host name, which indicates whether the link to the image originates from one of the pages on your site, or whether it stems from a page on someone else's site. If the page that's using the image is on another site, you have a potential problem. Not only is this page stealing your image, it's also creating more work for your web server. That's because every time someone views the third-party site, the image is requested from your server. If the stolen image appears on a popular site, this could generate a significant amount of extra work and reduce the bandwidth you have available to serve your own pages.

This problem—sites that steal bandwidth by linking to resources on your server—is known informally as leeching. It's a common headache for popular websites that serve large amounts of non-HTML content (for example, photo-sharing sites such as Flickr). Many websites combat this problem using the same technique as the HTTP handler described previously—namely, they refuse to serve the image or they substitute a dummy image if the referrer header indicates that a request originates from another site.

Here's an HTTP handler that implements this solution in ASP.NET. In order for this code to work as written, you must import the System.Globalization namespace and the System.IO namespace.

Public Class ImageGuardHandler Implements IHttpHandler

Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Dim response As HttpResponse = context.Response Dim request As HttpRequest = context.Request Dim imagePath As String = Nothing

' Check whether the page requesting the image is from your site. If request.UrlReferrer IsNot Nothing Then

' Perform a case-insensitive comparison of the referrer. If [String].Compare(request.Url.Host, request.UrlReferrer.Host, _ True, Culturelnfo.InvariantCulture) = 0 Then ' The requesting host is correct. ' Allow the image to be served (if it exists). imagePath = request.PhysicalPath If Not File.Exists(imagePath) Then response.Status = "Image not found" response.StatusCode = 404 Return End If End If End If

If imagePath Is Nothing Then

' No valid image was allowed.

' Return the warning image instead of the requested image. ' Rather than hard-code this image, you could ' retrieve it from the web.config file ' (using the <appSettings> section or a custom ' section).

imagePath = context.Server.MapPath("~/Images/notAllowed.gif") End If

' Set the content type to the appropriate image type. response.ContentType = "image/" + Path.GetExtension(imagePath).ToLower()

' Serve the image. response.WriteFile(imagePath) End Sub

Public Readonly Property IsReusable() As Boolean Get

Return True End Get End Property End Class

For this handler to protect image files, you need to register it to deal with the appropriate file types. Here's the web.config settings that set this up for the .gif and .png file types (but not .jpg):

<httpHandlers>

type="ImageGuardHandler"/> <add verb="*" path="*.png"

type="ImageGuardHandler"/> </httpHandlers>

This works for the integrated Visual Studio web server; however, when you deploy your website, you'll need to take an extra step. Namely, you'll need to add a file mapping in IIS that tells IIS all .gif requests are handled by ASP.NET.

■ Note This solution to leeching is far from perfect, but it serves to stop casual leechers. A programming-savvy user can easily circumvent it with a little JavaScript code. Some web developers create much more elaborate systems. For example, you can dynamically generate a timestamp code and append it to your image links whenever a page is requested. Your HTTP handler can then refuse to serve images if the time-stamp is out of date, which suggests the link has been copied and is being reused on another page long after its creation time. However, none of these techniques can stop someone from creating a copy of the picture and serving it directly from their site.

Based on this example, you can probably imagine a variety of different ways you can use HTTP handlers. For example, you could render a custom image, perform an ad hoc database query, or return some binary data. These examples extend the ASP.NET architecture but bypass the web-page model. The result is a leaner, more efficient component.

You can also create HTTP handlers that work asynchronously. This means they create a new thread to do their work, instead of using one of the ASP.NET worker threads. This improves scalability in situations where you need to perform a task that takes a long time but isn't CPU-intensive. A classic example is waiting to read an extremely slow network resource. ASP.NET allows only a fixed number of worker threads (typically 25) to run at once. Once this limit is reached, additional requests will be queued, even if the computer has available CPU time.

With asynchronous handlers, additional requests can be accepted, because the handler creates a new thread to process each request rather than using the worker process. Of course, there is a risk with this approach. Namely, if you create too many threads for the computer to manage efficiently, or if you try to do too much CPU-intensive work at once, the performance of the entire web server will be adversely affected. Asynchronous HTTP handlers aren't covered in this book, but in Chapter 11 you'll learn how to use asynchronous pages, which use asynchronous HTTP handlers behind the scenes.

0 0

Post a comment

  • Receive news updates via email from this site