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:- Exchange version information
- Get a short text description of the extension
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:
GetExtensionVersion
HttpExtensionProc
TerminateExtension
(optional)
DLLMain
, the entry point of any DLL!DLLMain, the entry point
As indicated by Microsoft, "theDllMain
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
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.
Note: |
---|
ISAPI filter DLLs cannot be requested explicitly, like ISAPI extensions can. |
The following steps outline the interaction between ISAPI filters and IIS:
- 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.
- 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.
- 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. - 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.
- 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.
- 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.
0 comments:
Post a Comment