ISAPI Filter

Windows specific forum
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

ISAPI Filter

Post by RichAlgeni »

Has anyone done anything with Microsoft ISAPI filters? I've written a number of extensions that seem to work very well, but I cannot get IIS to call the HttpFilterProc() function. GetFilterVersion() seems to be fine. See below for debug view output.

Here is my barebones program, only enough code to do the minimum needed to run:

Code: Select all

EnableExplicit

#PROGRAM_NAME                        = "ots_isapi_filter.dll"
#PROGRAM_VERSION                     = "1.0.01a." + #PB_Editor_BuildCount
#HSE_VERSION_MAJOR                   =   7; // major version of this spec
#HSE_VERSION_MINOR                   =   0; // minor version of this spec

#HTTP_FILTER_REVISION                = #HSE_VERSION_MINOR | ( #HSE_VERSION_MAJOR << 16 )

#SF_MAX_USERNAME                     =  256 + 1
#SF_MAX_PASSWORD                     =  256 + 1
#SF_MAX_AUTH_TYPE                    =   32 + 1
#SF_MAX_FILTER_DESC_LEN              =  256 + 1

; // These values are returned by the filter entry point when a new request is received indicating their interest in this particular request

#SF_STATUS_REQ_FINISHED              = $8000000
#SF_STATUS_REQ_NEXT_NOTIFICATION     = #SF_STATUS_REQ_FINISHED + 2

Prototype GetServerVariable(hConnID.i, lpszVariableName.i, lpvBuffer.i, lpdwSize.l)
Prototype AddResponseHeaders(hConnID.i, lpszHeaders.i, dwReserved.l)
Prototype WriteClient(hConnID.i, lpvBuffer.i, lpdwBytes.i, dwReserved.l)
Prototype AllocMem(hConnID.i, cbSize.l, dwReserved.l)
Prototype ServerSupportFunction(hConnID.i, sfReq.i, pData.i, ul1.i, ul2.i)

; // pvNotification points to this structure for all request notification types

Structure HTTP_FILTER_CONTEXT
    cbSize.l;                                       // Size of this structure.
    Revision.l;                                     // Version info of this spec.
    *ServerContext;                                 // Reserved for server use.
    ulReserved.l;                                   // Reserved For server use.
    fIsSecurePort.l;                                // A value of TRUE indicates that this event is over a secure port. A value of FALSE indicates that the event is not over a secure port.
    *pFilterContext;                                // Points to any context information that the filter wants to associate with this request.
    GetServerVariable.GetServerVariable;            // Function call.
    AddResponseHeaders.AddResponseHeaders;          // Function call.
    WriteClient.WriteClient;                        // Function call.
    AllocMem.AllocMem;                              // Function call.
    ServerSupportFunction.ServerSupportFunction;    // Function call.
EndStructure

; //  This structure is the notification info for when the server is about to process the client headers

Prototype GetHeader(*pfc.HTTP_FILTER_CONTEXT, lpszName.s, lpvBuffer.i, lpdwSize.l)

; //  Replaces this header value to the specified value.  To delete a header, specified a value of '\0'.

Prototype SetHeader(*pfc.HTTP_FILTER_CONTEXT, lpszName.s, lpszValue.s)

; //  Adds the specified header and value

Prototype AddHeader(*pfc.HTTP_FILTER_CONTEXT, lpszName.s, lpszValue.s)

Structure HTTP_FILTER_PREPROC_HEADERS
    GetHeader.GetHeader;                            // Get header function call.
    SetHeader.SetHeader;                            // Set header function call.
    AddHeader.AddHeader;                            // Add header function call.
    HttpStatus.l;                                   // Status for SEND_RESPONSE.
    dwReserved.l;                                   // Reserved for future use.
EndStructure

#SF_NOTIFY_SECURE_PORT             = $00000001
#SF_NOTIFY_NONSECURE_PORT          = $00000002
#SF_NOTIFY_SEND_RESPONSE           = $00000040
#SF_NOTIFY_PREPROC_HEADERS         = $00004000
#SF_NOTIFY_ORDER_HIGH              = $00080000
#SF_NOTIFY_ORDER_MEDIUM            = $00040000
#SF_NOTIFY_ORDER_LOW               = $00020000
#SF_NOTIFY_ORDER_DEFAULT           = #SF_NOTIFY_ORDER_LOW
#SF_NOTIFY_ORDER_MASK              = #SF_NOTIFY_ORDER_HIGH | #SF_NOTIFY_ORDER_MEDIUM | #SF_NOTIFY_ORDER_LOW

; // Structure passed To GetFilterVersion

Structure HTTP_FILTER_VERSION
    dwServerFilterVersion.l;                        // The ISAPI version in use by the server.
    dwFilterVersion.l;                              // The version number of ISAPI used by the ISAPI filter. The version used by your filter can be set by using the HTTP_FILTER_REVISION definition from the httpfilt.h header file.
    lpszFilterDesc.a[#SF_MAX_FILTER_DESC_LEN];      // String for short description of the ISAPI filter. Length = #SF_MAX_FILTER_DESC_LEN
    dwFlags.l;                                      // Contains flags that indicate for which notification event types the filter should be notified, and what the filter's priority is. The following table lists the valid bitmasks.
EndStructure

; ************************************************************************************
; initialization procedure
; ************************************************************************************

ProcedureDLL.i AttachProcess(instance.i)
EndProcedure

; ************************************************************************************
; DetachProcess
; ************************************************************************************

ProcedureDLL.i DetachProcess(instance.i)
EndProcedure

; ************************************************************************************
; AttachThread
; ************************************************************************************

ProcedureDLL.i AttachThread(instance.i)
EndProcedure

; ************************************************************************************
; DetachThread
; ************************************************************************************

ProcedureDLL.i DetachThread(instance.i)
EndProcedure

; ************************************************************************************
; GetFilterVersion is called when the dll is loaded
; ************************************************************************************

ProcedureDLL.l GetFilterVersion(*pVer.HTTP_FILTER_VERSION)

    Protected logText.s
    Protected notifyVersion.l
    Protected description.s     = "ISAPI Filter written in PureBasic"
    Protected descriptionSize.i = StringByteLength(description, #PB_UTF8)
    Protected netSource.s       = #PROGRAM_NAME + ", version " + #PROGRAM_VERSION + ", GetFilterVersion() > "
    Protected notifyFlags.l     = #SF_NOTIFY_SEND_RESPONSE | #SF_NOTIFY_ORDER_DEFAULT | #SF_NOTIFY_PREPROC_HEADERS

    notifyVersion = #HTTP_FILTER_REVISION
    If  notifyVersion > *pVer\dwServerFilterVersion
        notifyVersion = *pVer\dwServerFilterVersion
    EndIf

    *pVer\dwFilterVersion = notifyVersion
    PokeS(@*pVer\lpszFilterDesc, description, descriptionSize, #PB_UTF8)
    *pVer\dwFlags = notifyFlags

    logText = netSource + "ISAPI Version: 0x" + RSet(Hex(*pVer\dwServerFilterVersion, #PB_Long), 8, "0")
    logText + ", program version: 0x" + RSet(Hex(notifyVersion),  8, "0")
    logText + ", notifications requested: 0x" + RSet(Hex(notifyFlags, #PB_Long),  8, "0")

    OutputDebugString_(logText)

; return true, returning false will cause the dll to be unloaded

    ProcedureReturn #True

EndProcedure

; ************************************************************************************
; This is the main function that is called for each client request pECB contains all needed data
; ************************************************************************************

ProcedureDLL.l HttpFilterProc(*pfc.HTTP_FILTER_CONTEXT, notificationType.l, *pvNotification)

    OutputDebugString_(#PROGRAM_NAME + ", version " + #PROGRAM_VERSION + ", HttpFilterProc() called by " + Str(notificationType))

    ProcedureReturn #SF_STATUS_REQ_NEXT_NOTIFICATION

EndProcedure

; ************************************************************************************
; TerminateFilter is called before unloading the dll.
; ************************************************************************************

ProcedureDLL.l TerminateFilter(dwFlags)

    OutputDebugString_(#PROGRAM_NAME + ", version " + #PROGRAM_VERSION + ", TerminateFilter() called")

    ProcedureReturn #True

EndProcedure
; IDE Options = PureBasic 5.70 LTS (Windows - x64)
; ExecutableFormat = Shared dll
; CursorPosition = 115
; FirstLine = 105
; EnableThread
; Executable = ots_iisapi_filter.dll
; DisableDebugger
; HideErrorLog
; DisableCompileCount = 2
; EnableBuildCount = 8
; EnableExeConstant
All it should do is output strings to DebugView. As Freak has previously documented, you need to run DebugView in Administrator mode, and check Capture Global Win32, to see the output. It SHOULD list a call to GetFilterVersion(), then calls to HttpFilterProc() for each page requested, based upon the notifications requested. All I get is the call to GetFilterVersion():

Code: Select all

[14268] ots_isapi_filter.dll, version 1.0.01a.7, GetFilterVersion() > ISAPI Version: 0x000A0000, program version: 0x00070000, notifications requested: 0x00020043
Any help would be appreciated, and I will post my entire program if I can get it running.
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: ISAPI Filter

Post by RichAlgeni »

I should add, there are NO errors in the Event Log.
Post Reply