Explain about ISAPI DLL and ISAPI Filter


ISAPI (Internet Server Application Program Interface) is a set of Windows program calls that let you write a Web server application that will run faster than a common gateway interface (CGI) application. A disadvantage of a CGI application (or "executable file," as it is sometimes called) is that each time it is run, it runs as a separate process with its own address space, resulting in extra instructions that have to be performed, especially if many instances of it are running on behalf of users. Using ISAPI, you create a dynamic link library (DLL) application file that can run as part of the Hypertext Transport Protocol (HTTP) application's process and address space. The DLL files are loaded into the computer when HTTP is started and remain there as long as they are needed; they don't have to be located and read into storage as frequently as a CGI application.
A special kind of ISAPI DLL is called an ISAPI filter, which can be designated to receive control for every HTTP request. You can create an ISAPI filter for encryption or decryption, for logging, for request screening, or for other purposes.

Introduction

Unless you have been a caveman, you have seen a number of web sites that whenever is browsed, the navigation ends up to a DLL file residing in a scripting directory of that dominium! Something like the following pseudo URL:
http://www.mydomain.com/script/example.dll?ID=p05874&Tx=870250AZT6
What does this DLL suppose to do and what does it have to do with today's paper?
These DLLs are created using the Internet Server API, or ISAPI for short. ISAPI is developed to provide a benefit or two, over the shortcomings of Common Gateway Interface, CGI. Although we surprisingly experience new web sites developed exclusively by CGI scripts nowadays, however, ISAPI DLLs have got something to offer that CGI could never bring us this way or that way.
I am going to start off this paper by describing the underlying details that any ISAPI programmer has to know, to be able to develop a better ISAPI extension. From then on, I will go through a development of a useful ISAPI extension step by step. The extension is supposed to validate a given credit card. Yeah! This is also my answer to those people who asked me the algorithm involved validating a credit card over and over again. Gotta go!

What is ISAPI?

Internet Server Application Programming Interface (ISAPI), is an API developed to provide the application developers with a powerful way to extend the functionality of Internet Information Server (IIS). Although ISAPI extensions by no means are limited to IIS, they are extensively used in conjunction with MS-IIS.

CGI vs. ISAPI

Developing a CGI program involves creating an EXE with C, C++, and/or Perl programming languages. This EXE file will be executed and terminated for every request received, causing an excessive memory usage, whenever users hit the same page over and over again!
This excessive memory usage that could bring the server completely down, has been solved under ISAPI extensions. An ISAPI extension is a regular DLL file that exposes 3 special functions that is called by the calling process (i.e., IIS) and therefore, will be loaded to memory once, no matter how many clients are going to use it at the same time. (It would be a good idea if you could take a look at a reference, to see how memory management is done under Windows 2000. The Visual C++ 6.0 Bible, Chapter 18, The Memory Management, describes it well!)

ISAPI fundamentals

Since the ISAPI extension and the calling process (IIS) live at the same address space, they could contact each other, directly. This means a great potential to bring the whole IIS down, and in some cases, the entire web server! Take a look at the following figure:

You see whatever problem your extension encounters, it could affect the entire web server process, if it's not handled properly. As illustrated above, communicating between the extension and IIS is done via a pointer to a structure of type ECB, or Extension Control Block that is declared as follows:
typedef struct _EXTENSION_CONTROL_BLOCK
{
   DWORD     cbSize;                 // size of this struct.
   DWORD     dwVersion;              // version info of this spec
   HCONN     ConnID;                 // Context number not to be modified!
   DWORD     dwHttpStatusCode;       // HTTP Status code
   CHAR      lpszLogData[HSE_LOG_BUFFER_LEN];// null terminated log info

   LPSTR     lpszMethod;             // REQUEST_METHOD
   LPSTR     lpszQueryString;        // QUERY_STRING
   LPSTR     lpszPathInfo;           // PATH_INFO
   LPSTR     lpszPathTranslated;     // PATH_TRANSLATED

   DWORD     cbTotalBytes;           // Total bytes indicated from client
   DWORD     cbAvailable;            // Available number of bytes
   LPBYTE    lpbData;                // pointer to cbAvailable bytes

   LPSTR     lpszContentType;        // Content type of client data

   BOOL (WINAPI * GetServerVariable) (HCONN hConn,
   LPSTR      lpszVariableName,
   LPVOID     lpvBuffer,
   LPDWORD    lpdwSize );

   BOOL (WINAPI * WriteClient)  (HCONN ConnID,
   LPVOID     Buffer,
   LPDWORD    lpdwBytes,
   DWORD      dwReserved );

   BOOL (WINAPI * ReadClient)  (HCONN ConnID,
   LPVOID     lpvBuffer,
   LPDWORD    lpdwSize );

   BOOL (WINAPI * ServerSupportFunction)( HCONN hConn,
   DWORD      dwHSERequest,
   LPVOID     lpvBuffer,
   LPDWORD    lpdwSize,
   LPDWORD    lpdwDataType ); 

}EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK; 
Whatever information either the calling process or the extension wants to pass to the other, is done through this control block. We will shortly have a look at this ECB structure. For now, let's see how IIS works in conjunction with your extension, to serve the visitor of your web site.
Whenever an extension is accessed (e.g., http://www.mydomain.com/script/example.dll?ID=p05874 & Tx=870250AZT6), IIS checks to see whether the example.dll is loaded into memory. If it is not, then it initiates the loading process. Once the DLL is loaded into memory, a worker thread starts running to manage our extension, and thereafter the entry point (DLLMain function) is called. When the DLLMain finishes, the server makes a call to GetExtensionVersion function to perform two tasks:
  1. Exchange version information
  2. Get a short text description of the extension
The server then calls the HttpExtensionProc function passing a copy of the ECB's pointer to start the actual ISAPI extension. This is the function that makes writing data back to the client, possible! We will examine this, shortly.
The third and the last entry point in an ISAPI extension DLL is the TerminateExtension function that is called whenever the extension is going to be unloaded from the memory. All the cleanup code can be done in this function.
In brief, an ISAPI extension is a regular DLL that exposes 3 functions to interact with the server:
  1. GetExtensionVersion
  2. HttpExtensionProc
  3. TerminateExtension (optional)
Having this information in hand, let's start with the DLLMain, the entry point of any DLL!

DLLMain, the entry point

As indicated by Microsoft, "the DllMain function is an optional entry point into a dynamic-link library (DLL). If the function is used, it is called by the system when processes and threads are initialized and terminated, or upon calls to the LoadLibrary and FreeLibrary functions", that is prototyped as follows:
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwCallReason, 
                                            LPVOID lpReserved);
If you provide your extension with this function, it will be called upon the initialization and the termination process of your extension. The state is indicated by the dwCallReason parameter that could be one the following predefined values:
  • DLL_PROCESS_ATTACHED
  • DLL_THREAD_ATTACH
  • DLL_THREAD_DETACH
  • DLL_PROCESS_DETACH
Describing each of these parameters in detail is beyond the scope of this paper, so I simply refer you to Microsoft's Developer Network to read more about this function.
Anyhow, we could save the hModule parameter for later use in our extension (if this suites us) and simply return TRUE from this function. We usually do not have anything to do in this function, while developing an extension!

GetExtensionVersion, the actual entry point

This function is actually the first entry point that is called by IIS to determine the information about the extension. To understand this better, let's have a look at it's prototype:
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer);
Upon the activation of this function, we are supposed to fill out the extension information within the pVer parameter passed to the function. This pointer is of type HSE_VERSION_INFO that is declared as follows:
typedef struct _HSE_VERSION_INFO
{
   DWORD dwExtensionVersion;
   CHAR lpszExtensionDesc[HSE_MAX_EXT_DLL_NAME_LEN];
}HSE_VERSION_INFO, *LPHSE_VERSION_INFO;
where dwExtensionVersion is the extension version and lpszExtensionDescription is the description of the extension. If we return TRUE from this function, we notify IIS that our extension is ready to be used. Otherwise, IIS will not use the extension.

HttpExtensionProc, the main entry point

The amazing part of any ISAPI extension starts when the extension procedure (HttpExtensionProc) is called. As far as you could remember, this is the procedure that makes writing data back to the client possible! To see how this happens, lets start by having a look at the prototype of HttpExtensionProc:
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB);
where pECB is a pointer to an extension control block, that makes the intercommunication between the server and the extension possible. You decide what the web page should contain and how to present it to the user in this entry point. But how?
Do you recall the members of the ECB's structure? ECB contains a method, prototyped as follows:
BOOL WriteClient(HCONN ConnID, LPVOID Buffer, LPDWORD lpdwBytes, 
                                                        DWORD dwSync);
Using this member function, you can send the data present in the given Buffer to the client that is identified by its ConnID, the one that made the request. For example, to send A BIG RED ROSE to a client, you could simply make the following calls:
char szBigRedRos[] = 
  "<font color='#FF0000' size='3'><b>A BIG RED ROSE</b></font>";
DWORD dwSize = strlen(szBigRedRos);
pECB->WriteClient(pECB->ConnID, szBigRedRose, dwSize, 0);




ISAPI filters are DLL files that can be used to modify and enhance the functionality provided by IIS. ISAPI filters always run on an IIS server, filtering every request until they find one they need to process. The ability to examine and modify both incoming and outgoing streams of data makes ISAPI filters powerful and flexible.
Filters are registered at either the site level or the global level (that is, global filters apply to all sites on the IIS server), and are initialized when the worker process is started. A filter listens to all requests to the site on which it is installed.
Both ISAPI filters and ISAPI extensions can only be developed using C/C++. Visual Studio comes with wizards that make ISAPI development fast and easy.
ISAPI filters can be registered with IIS to modify the behavior of a server. For example, filters can perform the following tasks:
  • Change request data (URLs or headers) sent by the client
  • Control which physical file gets mapped to the URL
  • Control the user name and password used with anonymous or basic authentication
  • Modify or analyze a request after authentication is complete
  • Modify a response going back to the client
  • Run custom processing on "access denied" responses
  • Run processing when a request is complete
  • Run processing when a connection with the client is closed
  • Perform special logging or traffic analysis.
  • Perform custom authentication.
  • Handle encryption and compression.
NoteNote:
ISAPI filter DLLs cannot be requested explicitly, like ISAPI extensions can.
Every ISAPI filter is contained in a separate DLL that must export two entry-point functions, GetFilterVersionand HttpFilterProc, and optionally export the TerminateFilter function. The metabase property, FilterLoadOrder, contains a list of all filters that IIS loads when the Web service is started.

The following steps outline the interaction between ISAPI filters and IIS:

  1. When IIS initially loads an ISAPI filter, it also creates and partially populates an HTTP_FILTER_VERSION structure. It then calls the filter's GetFilterVersion function, passing a pointer to the new structure as a parameter.
  2. The ISAPI filter populates the HTTP_FILTER_VERSION structure with version information and descriptive information. More importantly, the filter also uses HTTP_FILTER_VERSION to specify which event notifications it should receive, and to declare the general priority level for the filter. In addition, the filter also indicates whether it is interested in events from secure ports only, unsecure ports only, or both.
  3. Each HTTP transaction between IIS and a client browser triggers several distinct events. Every time an event occurs for which an ISAPI filter is registered, IIS calls the filter's HttpFilterProc entry-point function.
    If more than one ISAPI filter is registered for a given event, IIS notifies the filters that the event occurred. The filters, which are marked as high, medium, or low priority, are notified according to priority in descending order. If more than one ISAPI filter is declared the same general priority level, IIS uses the order in which the filters appear in the FilterLoadOrder property to resolve the tie.
  4. The ISAPI filter uses the notification type information, passed by IIS as a parameter to HttpFilterProc, to determine which particular data structure is pointed to by the other HttpFilterProc parameter, pvNotification. The ISAPI filter then uses the data contained in that data structure, as well as in the context structure HTTP_FILTER_CONTEXT, to perform any custom processing.
  5. Once processing is complete, the filter returns one of the SF_STATUS status codes to IIS, and IIS continues processing the HTTP request or response until another event occurs for which ISAPI filters are registered.
  6. When the Web service is stopped or unloaded, IIS calls TerminateFilter in all ISAPI filters as part of its shutdown sequence, for any filters that implemented and exported the function. TerminateFilter is typically used to perform cleanup and de-allocation of allocated resources.
GetFilterVersion is called exactly once, when the ISAPI filter is initially loaded. Any per-connection initializations the developer wants to perform must be managed internally within the context of the HttpFilterProc function call.

0 comments:

Post a Comment