Adding an ISAPI extension interface means you can change the filter's behavior without having to unload it, restart IIS, and recompile it. But before you rush out to modify SmartRedir, we should mention a few words of caution. There is a good chance that the ISAPI filter functions and the ISAPI extension functions will be invoked by multiple clients at the same time. Access to all global variables should be strictly controlled. If one client invokes the ISAPI extension and tries to modify the User-Agent string while the ISAPI filter tries to use the global variable, you may run into some problems. To prevent this, access to all global variables should be controlled via synchronization objects of some sort. Windows NT® uses synchronization objects to control multiple threads that are accessing the same variable (or other shared data) at the same time. For SmartRedir, access to global variables can be guarded with a synchronization object called a critical section. Critical sections are objects that allow only a single thread to own the M at any one time. You'd want to create a critical section and write code to take ownership of the critical section before manipulating the global variables.
Figure 4 contains skeleton code that you can use to add an ISAPI extension interface to the SmartRedir sample. It has all the necessary steps to give you a solid idea of what you will need to do.
Advanced Filters
You can do many things with ISAPI filters. You can implement a custom authentication scheme by handling the SF_NOTIFY_AUTHENTICATION event. Both the Basic or NTLM authentication methods control access based on valid Windows NT accounts; that is, if an account does not exist for the supplied credentials, the user won't gain access to the secure resource. You can write a filter that accesses the user name and password for a request (they are members of the HTTP_FILTER_AUTHENT structure), and then performs authentication based on a proprietary user account database instead of the Windows NT user accounts. Once the check of the database is successful, the filter replaces the supplied user name and password with the name and password of a valid Windows NT account.
Suppose that when the browser brings up a dialog box to enter the user name and password for accessing a password-protected URL, you want the user to be able to enter a user name and password such as "JoeUser" and "password." If there is no valid Windows NT account for JoeUser, without your custom authentication filter, IIS could not authenticate the user. Your custom authentication filter validates the "JoeUser" and "password" credentials itself, and then replaces the M with a valid Windows NT account and password. In this manner, the JoeUser credentials will have allowed the client to access the protected resource.
Another popular use for ISAPI filters is in custom logging software. You can create a filter that gets the SF_
NOTIFY_LOG notification. ISAPI filters can also be used to encode and decode the raw data that is being sent across the socket. In fact, this is how SSL is implemented. A filter called SSPIFILT.DLL hooks the SF_NOTIFY_READ_RAW_DATA and the SF_NOTIFY_SEND_RAW_DATA notifications to decode or encode the data accordingly.
Another feature that could be implemented using ISAPI filters is your own authentication scheme. You could do this by hooking the SF_NOTIFY_ACCESS_DENIED notification and building the appropriate HTTP headers to perform your custom authentication handshake. When the response comes back, you need to hook the SF_NOTIFY_PREPROC_
HEADERS event to read the custom response headers and react appropriately. In this way you could add something like the new Digest Authentication scheme that is being considered as part of the HTTP specification.
One more common use for ISAPI filters is simply monitoring the various events to track down problems on your server. For instance, if you are writing an ISAPI extension and you want to see the exact response data that is generated, you could write an ISAPI filter that hooks the SF_
NOTIFY_SEND_RAW_DATA event and displays the data being sent. This could be very useful while debugging.
Now that you're busy thinking about all the powerful things you could do with your very own ISAPI filter, let's step back and look at another way to customize IIS. Let's take a look at writing your own script interpreter.
Custom Script Interpreters
Using the built-in SSI facility available with IIS, you can create dynamic pages based on HTML-like template files. Consider the following scenario: XYZ Corporation needs to build a set of Web pages from predefined templates, similar to SSI. XYZ Corporation advertises garden supplies on the Web. The pages would consist of the item names and prices. Since there could be hundreds of different items on a page, updating the price of each would be a huge headache for the Webmaster. Just imagine opening an HTML file, looking for each item, and changing its price.
If the prices change often, the work of editing such a document becomes unacceptable. A smarter solution would be to use certain tags in the initial documents, such as SHOVEL_PRICE, SCOOPER_PRICE, and so on, to indicate where the appropriate information should be inserted. When a request for this page arrives, you might be able to dynamically replace the tags with the actual prices. You could store the real values in either a database or just in a flat file. You could implement this in several ways: using the Internet Database Connector, writing your own ASP pages, or even by writing a raw data filter that would replace the Outgoing placeholders with the appropriate values. You could also write your own custom SSI processor.
But with all the Other tools available, isn't creating something from scratch a waste of time? Not necessarily. If you happen to already have a proprietary mechanism for creating templates to display information, you could write your own script interpreter to read your file format and create appropriate HTML. You could even use custom script maps to take files in your own proprietary file format and convert it into HTML that can be displayed in a browser.
Script interpreters are ISAPI extension DLLs just like any other ISAPI extensions, with one exception. Instead of referring to the extension DLL explicitly in the URL, an association is made with certain file extensions and the ISAPI extension DLL so that IIS will run the ISAPI extension when a request is received for a file with the specified extension. Adding a new entry for a particular file type will inform IIS to invoke your custom DLL for this file type. Of course, IIS already has a number of mappings for certain file types such as ASP.
SSIDemo
We wrote an ISAPI extension, SSIDemo.dll (see Figure 5), and associated files with the .bpi extension with it. As soon as a request for a file with the extension .bpi arrives, IIS will load SSIDemo.dll just like any ISAPI extension request. The request for http://MyServer/MyTestFile.bpi does not refer to the SSIDemo.dll directlyit refers to the .bpi filebut IIS now knows to load SSIDemo.dll for this file extension. Once the DLL is loaded, you can access the full file path of MyTestFile.bpi through the lpszPathTranslated member of the Extension Control Block structure. At this point, you can open the file, read through it, and send
its modified version to the client with the WriteClient callback function.
Let's look at the details of SSIDemo. This sample replaces all tags in a template file (here, the files have the .bpi extension). Each of our template file's "tags" have a text string associated with it. the Se tag/string associations are stored in a special file that you can edit to create any associations you desire. The file name and location are configured via the registry:
|