An ISAPI server extension DLL is loaded the first time a client references it
in a GET or POST request. An ISAPI filter DLL is loaded (based on a
Registry entry) when the WWW service is started. The filter is then in the loop for
all HTTP requests, so you can read and/or change any data that enters or
leaves the server.
Writing an ISAPI Filter DLL
The ISAPI Extension Wizard makes writing filters as easy as writing server extensions. Choose Generate A Filter Object, and Step 2 looks like this.
The list of options under Which Notifications Will Your Filter
Process? refers to seven places where your filter can get control during the processing
of an HTTP request. You check the boxes, and the wizard generates the code.
The MFC ISAPI Filter Classes
There are two MFC classes for ISAPI filters,
CHttpFilter and CHttpFilterContext.
CHttpFilter
With the help of the ISAPI Extension Wizard, you derive a class from CHttpFilter for each ISAPI filter you create. There's just one object of this class. The class has virtual functions for each of seven notifications. The list of filters in the order in which IIS calls them is below.
virtual DWORD OnReadRawData(CHttpFilterContext* pCtxt, PHTTP_FILTER_RAW_DATA pRawData); virtual DWORD OnPreprocHeaders(CHttpFilterContext* pCtxt, PHTTP_FILTER_PREPROC_HEADERS pHeaderInfo); virtual DWORD OnUrlMap(CHttpFilterContext* pCtxt, PHTTP_FILTER_URL_MAP pMapInfo); virtual DWORD OnAuthentication(CHttpFilterContext* pCtxt, PHTTP_FILTER_AUTHENT pAuthent); virtual DWORD OnSendRawData(CHttpFilterContext* pCtxt, PHTTP_FILTER_RAW_DATA pRawData); virtual DWORD OnLog(CHttpFilterContext* pfc, PHTTP_FILTER_LOG pLog); virtual DWORD OnEndOfNetSession(CHttpFilterContext* pCtxt);
If you override a function, you get control. It would be inefficient, however, if IIS made virtual function calls for every notification for each transaction. Another virtual function, GetFilterVersion, is called once when the filter is loaded. The ISAPI Extension Wizard always overrides this function for you, and it sets flags in the function's pVer parameter, depending on which notifications you want. Here's a simplified sample with all the flags set:
BOOL CMyFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer) { CHttpFilter::GetFilterVersion(pVer); pVer->dwFlags |= SF_NOTIFY_ORDER_LOW | SF_NOTIFY_NONSECURE_PORT | SF_NOTIFY_LOG | SF_NOTIFY_AUTHENTICATION | SF_NOTIFY_PREPROC_HEADERS | SF_NOTIFY_READ_RAW_DATA | SF_NOTIFY_SEND_RAW_DATA | SF_NOTIFY_URL_MAP | SF_NOTIFY_END_OF_NET_SESSION; return TRUE; }
If you had specified URL mapping requests only, the wizard would
have set only the SF_NOTIFY_URL_MAP flag and it would have overridden
only OnUrlMap. IIS would not call the other virtual functions, even if they
were overridden in your derived class.
CHttpFilterContext
An object of this second MFC class exists for each server transaction, and each of the notification functions gives you a pointer to that object. The CHttpFilterContext member functions you might call are GetServerVariable, AddResponseHeaders, and WriteClient.