ISAPI Filter Ascii and Unicode Now works!!!

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

ISAPI Filter Ascii and Unicode Now works!!!

Post by RichAlgeni »

Modified to use Justin's tip on structures!: Align #PB_Structure_AlignC

Modified to add 'Align 4' on the HTTP_FILTER_VERSION, and remove the constant #SF_NOTIFY_READ_RAW_DATA, as it is no longer used.

ots_iisapi_filter_ascii.pb

Code: Select all

; ------------------------------------------------------------
; Program name: ots_iisapi_filter_ascii.pb
; Written by:   Rich Algeni, Jr.
; Date written: 09/11/2015
;
; Purpose: 64 bit Internet Information Server Ascii Filter API Dll
; ------------------------------------------------------------

EnableExplicit

XIncludeFile "D:\development\Source Code Repository For Rich Algeni\PureBasic\iis_api\httpFilt_ascii.pbi"

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

ProcedureDLL.i AttachProcess(instance.i)

    Protected logText.s  = "ots_iisapi_filter AttachProcess() Ascii version completed successfully"

    OutputDebugString_(logText)

    ProcedureReturn #True

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.i GetFilterVersion(*pVer.HTTP_FILTER_VERSION)

    Protected logText.s     = "ots_iisapi_filter GetFilterVersion()"
    Protected descriptionSize.l
    Protected notificationMask.l
    Protected description.s = "ISAPI Ascii Filter written in PureBasic"
    Protected descripSize.l = Len(description)

    notificationMask =  #SF_NOTIFY_SECURE_PORT             | 
                        #SF_NOTIFY_NONSECURE_PORT          |
                        #SF_NOTIFY_PREPROC_HEADERS         |
                        #SF_NOTIFY_AUTHENTICATION          |
                        #SF_NOTIFY_URL_MAP                 |
                        #SF_NOTIFY_ACCESS_DENIED           |
                        #SF_NOTIFY_SEND_RESPONSE           |
                        #SF_NOTIFY_SEND_RAW_DATA           |
                        #SF_NOTIFY_LOG                     |
                        #SF_NOTIFY_END_OF_REQUEST          |
                        #SF_NOTIFY_END_OF_NET_SESSION      |
                        #SF_NOTIFY_AUTH_COMPLETE

    descriptionSize  = StringByteLength(description, #PB_Ascii)

; make the length of the description the same number of characters as #SF_MAX_FILTER_DESC_LEN

    PokeL(@*pVer\dwFilterVersion, #HTTP_FILTER_REVISION)
    PokeS(@*pVer\lpszFilterDesc,  description, descriptionSize, #PB_Ascii)
    PokeL(@*pVer\dwFlags,         notificationMask)

    logText + ", ISAPI Server Version: 0x" + RSet(Hex(*pVer\dwServerFilterVersion, #PB_Long), 8, "0")
    logText + ", ISAPI Client Version: 0x" + RSet(Hex(*pVer\dwFilterVersion, #PB_Long), 8, "0")
    logText + ", notifications requested: 0x" + RSet(Hex(notificationMask, #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.i HttpFilterProc(*pfc.HTTP_FILTER_CONTEXT, notificationType.l, *pvNotification)

    Protected logText.s = "ots_iisapi_filter HttpFilterProc() > notificationType = " + Str(notificationType)

    OutputDebugString_(logText)

; return get next notification

    ProcedureReturn #SF_STATUS_REQ_NEXT_NOTIFICATION

EndProcedure

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

ProcedureDLL.i TerminateFilter(dwFlags.l)

    Protected logText.s = "ots_iisapi_filter TerminateFilter() > process terminating"

    OutputDebugString_(logText)

; return true

    ProcedureReturn #True

EndProcedure
; IDE Options = PureBasic 5.46 LTS (Windows - x64)
; ExecutableFormat = Shared dll
; CursorPosition = 73
; FirstLine = 62
; Folding = --
; EnableThread
; UseIcon = ..\OTS\ots.ico
; Executable = ots_iisapi_filter.dll
; DisableDebugger
; HideErrorLog
; CurrentDirectory = \
; CompileSourceDirectory
; Compiler = PureBasic 5.46 LTS (Windows - x64)
; EnableCompileCount = 5
; EnableBuildCount = 5
; EnableExeConstant
httpfile_ascii.pbi

Code: Select all

; *************************************************************
; *  Module Name: httpFilt_ascii.pbi
; *
; *  Abstract   : This module contains the Microsoft HTTP Ascii Filter header for PureBasic
; *************************************************************
; *************************************************************

; *************************************************************/
; *   Manifest Constants
; *************************************************************/

#HSE_VERSION_MAJOR                  =  10; // 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 can be used with the pfnSFCallback function supplied in the filter context Structure

; //  Sends a complete HTTP server response header including the status, server version, message time and MIME version.
; //  Server extensions should append other information at the end, such as Content-type, Content-length etc followed by an extra '\r\n'.
; //  pData - Zero terminated string pointing to optional status string (i.e., "401 Access Denied") or NULL for the default response of "200 OK".
; //  ul1 - Zero terminated string pointing to optional data to be appended and set with the header. If NULL, the header will be terminated with an empty line.

#SF_REQ_SEND_RESPONSE_HEADER        = 0

; //  If the server denies the HTTP request, add the specified headers to the server error response.
; //  This allows an authentication filter to advertise its services w/o filtering every request. Generally the headers will be
; //  WWW-Authenticate headers with custom authentication schemes but no restriction is placed on what headers may be specified.
; //  pData - Zero terminated string pointing to one or more header lines with terminating '\r\n'.

#SF_REQ_ADD_HEADERS_ON_DENIAL       = #SF_REQ_SEND_RESPONSE_HEADER + 1

; //  Only used by raw data filters that return SF_STATUS_READ_NEXT
; //  ul1 - size in bytes for the next read

#SF_REQ_SET_NEXT_READ_SIZE          = #SF_REQ_SEND_RESPONSE_HEADER + 2

; //  Used to indicate this request is a proxy request
; //  ul1 - The proxy flags to set
; //  0x00000001 - This is a HTTP proxy request

#SF_REQ_SET_PROXY_INFO              = #SF_REQ_SEND_RESPONSE_HEADER + 3

; //  Returns the connection ID contained in the ConnID field of an ISAPI Application's Extension Control Block.
; //  This value can be used as a key to cooridinate shared data between Filters and Applications.
; //  pData - Pointer to DWORD that receives the connection ID.

#SF_REQ_GET_CONNID                  = #SF_REQ_SEND_RESPONSE_HEADER + 4

; // Used to set a SSPI security context + impersonation token derived from a client certificate.
; // pData - certificate info ( PHTTP_FILTER_CERTIFICATE_INFO )
; // ul1 - CtxtHandle*
; // ul2 - impersonation handle

#SF_REQ_SET_CERTIFICATE_INFO        = #SF_REQ_SEND_RESPONSE_HEADER + 5

; // Used to get an IIS property as defined in SF_PROPERTY_IIS
; // ul1 - Property ID

#SF_REQ_GET_PROPERTY                = #SF_REQ_SEND_RESPONSE_HEADER + 6

; // Used to normalize an URL
; // pData - URL to normalize

#SF_REQ_NORMALIZE_URL               = #SF_REQ_SEND_RESPONSE_HEADER + 7

; // Disable Notifications
; // ul1 - notifications to disable

#SF_REQ_DISABLE_NOTIFICATIONS       = #SF_REQ_SEND_RESPONSE_HEADER + 8

; //////////////////////////////////////////////////////////////////////////////////////////////////////////////

#SF_PROPERTY_SSL_CTXT               = 0
#SF_PROPERTY_INSTANCE_NUM_ID        = #SF_PROPERTY_SSL_CTXT + 1

; //////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

; // The filter has handled the HTTP request.  The server should disconnect the session.

#SF_STATUS_REQ_FINISHED             = $8000000

; // Same as SF_STATUS_FINISHED except the server should keep the TCP session open if the option was negotiated.

#SF_STATUS_REQ_FINISHED_KEEP_CONN   = #SF_STATUS_REQ_FINISHED + 1

; // The next filter in the notification chain should be called.

#SF_STATUS_REQ_NEXT_NOTIFICATION    = #SF_STATUS_REQ_FINISHED + 2

; // This filter handled the notification. No other handles should be called for this particular notification type.

#SF_STATUS_REQ_HANDLED_NOTIFICATION = #SF_STATUS_REQ_FINISHED + 3

; // An error occurred. The server should use GetLastError() and indicate the error to the client.

#SF_STATUS_REQ_ERROR                = #SF_STATUS_REQ_FINISHED + 4

; // The filter is an opaque stream filter and we're negotiating the session parameters. Only valid for raw read notification.

#SF_STATUS_REQ_READ_NEXT            = #SF_STATUS_REQ_FINISHED + 5

; //////////////////////////////////////////////////////////////////////////////////////////////////////////////

; // Bitfield indicating the requested resource has been denied by the server due to a logon failure, an ACL on a resource, an ISAPI Filter or an
; // ISAPI Application/CGI Application.
; // SF_DENIED_BY_CONFIG can appear with SF_DENIED_LOGON if the server configuration did not allow the user to logon.

#SF_DENIED_LOGON            = $00000001
#SF_DENIED_RESOURCE         = $00000002
#SF_DENIED_FILTER           = $00000004
#SF_DENIED_APPLICATION      = $00000008
#SF_DENIED_BY_CONFIG        = $00010000

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

; // see https://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx for variable types

; // bool      = .l
; // int       = .i
; // pointer   = .i
; // byte      = .c
; // dword     = .l
; // dword32   = .l
; // dwordlong = .i
; // dword64   = .i
; // float     = .f

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

Structure HTTP_FILTER_CONTEXT Align #PB_Structure_AlignC
    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 the Read And send raw Data notification types

Structure HTTP_FILTER_RAW_DATA Align #PB_Structure_AlignC
    *pvInData;                                      // Points to the data buffer.
    cbInData.l;                                     // Number of valid data bytes.
    cbInBuffer.l;                                   // Total size of buffer.
    dwReserved.l;                                   // Reserved for future use.
EndStructure

; // Retrieves the specified header value. Header names should include the trailing ':'.  The special values
; // 'method', 'url' and 'version' can be used to retrieve the individual portions of the request line.

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

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

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

; // Adds the specified header and value.

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

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

Structure HTTP_FILTER_PREPROC_HEADERS Align #PB_Structure_AlignC
    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

; //  Authentication information for this request.

Structure HTTP_FILTER_AUTHENT Align #PB_Structure_AlignC
    pszUser.a;                                      // String for username and password, empty strings for the anonymous user.
    cbUserBuff.l;                                   // The size of the buffer pointed to by pszUser. This is guaranteed to be at least SF_MAX_USERNAME.
    pszPassword.a;                                  // String containing the password for this request.
    cbPasswordBuff.l;                               // The size of the buffer pointed to by pszPassword. This is guaranteed to be at least SF_MAX_PASSWORD.
EndStructure

; //  Indicates the server is going to use the specific physical mapping for the specified URL.  Filters can modify the physical path in place.

Structure HTTP_FILTER_URL_MAP Align #PB_Structure_AlignC
    pszURL.a;                                       // String for the URL that is being mapped to a physical path.
    pszPhysicalPath.a;                              // String for the buffer where the physical path is stored.
    cbPathBuff.l;                                   // The size of the buffer pointed to by pszPhysicalPath.
EndStructure

; //  Indicates the server is going to use the specific physical mapping for the specified URL.  Filters can modify the physical path in place.
; //  Additional members beyond those from HTTP_FILTER_URL_MAP are informational.

Structure HTTP_FILTER_URL_MAP_EX Align #PB_Structure_AlignC
    pszURL.a;                                       // String for the URL that is being mapped to a physical path.
    pszPhysicalPath.a;                              // String for the buffer where the physical path is stored.
    cbPathBuff.l;                                   // The size of the buffer pointed to by pszPhysicalPath.
    dwFlags.l
    cchMatchingPath.l
    cchMatchingURL.l
    pszScriptMapEntry.a
EndStructure

Structure HTTP_FILTER_ACCESS_DENIED Align #PB_Structure_AlignC
    pszURL.a;                                       // String for the URL that is being mapped to a physical path.
    pszPhysicalPath.a;                              // String for the buffer where the physical path is stored.
    dwReason.l;                                     // Bitfield of SF_DENIED flags due to a logon failure, an ACL on a resource, an ISAPI Filter or an ISAPI Application/CGI Application.
EndStructure

; //  The log information about to be written to the server log file. The string pointers can be replaced but the memory must remain valid until
; //  the next notification

Structure HTTP_FILTER_LOG Align #PB_Structure_AlignC
    pszClientHostName.a;                            // String for the client's host name.
    pszClientUserName.a;                            // String for the client's user name.
    pszServerName.a;                                // String for the server name.
    pszOperation.a;                                 // String for the HTTP operation type.
    pszTarget.a;                                    // String for the target of the HTTP command.
    pszParameters.a;                                // String for the parameters passed to the HTTP command.
    dwHttpStatus.l;                                 // The HTTP return status.
    dwWin32Status.l;                                // The Win32 error code.
    dwBytesSent.l;                                  // The number of bytes sent from the server to the client.
    dwBytesRecvd.l;                                 // The number of bytes received by the server from the client.
    msTimeForProcessing.l;                          // The time in milliseconds required to process the client request.
EndStructure

; // Called once the client request has been authenticated.

Prototype GetUserToken(*pfc.HTTP_FILTER_CONTEXT, phToken.i)

Structure HTTP_FILTER_AUTH_COMPLETE_INFO Align #PB_Structure_AlignC
    GetHeader.GetHeader;                            // Get header function call.
    SetHeader.SetHeader;                            // Set header function call.
    AddHeader.AddHeader;                            // Add header function call.
    GetUserToken.GetUserToken;                      // Get user token function call.
    HttpStatus.l;                                   // Status for SEND_RESPONSE.
    fResetAuth.l;                                   // Boolean reserved for future use.
    dwReserved.l;                                   // Reserved for future use.
EndStructure

; //  Notification Flags
; //
; //  SF_NOTIFY_SECURE_PORT
; //  SF_NOTIFY_NONSECURE_PORT
; //
; //      Indicates whether the application wants to be notified for transactions that are happenning on the server port(s) that support data encryption
; //      (such as PCT and SSL), on only the non-secure port(s) or both.
; //
; //  SF_NOTIFY_READ_RAW_DATA
; //
; //      Applications are notified after the server reads a block of memory from the client but before the server does any processing on the
; //      block.  The data block may contain HTTP headers and entity data.

#SF_NOTIFY_SECURE_PORT             = $00000001
#SF_NOTIFY_NONSECURE_PORT          = $00000002
#SF_NOTIFY_PREPROC_HEADERS         = $00004000
#SF_NOTIFY_AUTHENTICATION          = $00002000
#SF_NOTIFY_URL_MAP                 = $00001000
#SF_NOTIFY_ACCESS_DENIED           = $00000800
#SF_NOTIFY_SEND_RESPONSE           = $00000040
#SF_NOTIFY_SEND_RAW_DATA           = $00000400
#SF_NOTIFY_LOG                     = $00000200
#SF_NOTIFY_END_OF_REQUEST          = $00000080
#SF_NOTIFY_END_OF_NET_SESSION      = $00000100
#SF_NOTIFY_AUTH_COMPLETE           = $04000000

; //  Filter ordering flags
; //
; //  Filters will tend to be notified by their specified ordering.  For ties, notification order is determined by load order.
; //
; //  SF_NOTIFY_ORDER_HIGH - Authentication or data transformation filters
; //  SF_NOTIFY_ORDER_MEDIUM
; //  SF_NOTIFY_ORDER_LOW  - Logging filters that want the results of any other filters might specify this order.

#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 Align #PB_Structure_AlignC
    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

CompilerIf #PB_Compiler_Thread = 0
    CompilerError "ISAPI Filters must be compiled with threadsafe enabled!"
CompilerEndIf

CompilerIf #PB_Compiler_Unicode = 1
    CompilerWarning "Must be compiled without Unicode!!!"
CompilerEndIf
=======================================================
ots_iisapi_filter_unicode.pb

Code: Select all

; ------------------------------------------------------------
; Program name: ots_iisapi_filter_unicode.pb
; Written by:   Rich Algeni, Jr.
; Date written: 09/11/2015
;
; Purpose: 64 bit Internet Information Server Unicode Filter API Dll
; ------------------------------------------------------------

EnableExplicit

XIncludeFile "D:\development\Source Code Repository For Rich Algeni\PureBasic\iis_api\httpFilt_unicode.pbi"

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

ProcedureDLL.i AttachProcess(instance.i)

    Protected logText.s  = "ots_iisapi_filter AttachProcess() Unicode version completed successfully"

    OutputDebugString_(logText)

    ProcedureReturn #True

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.i GetFilterVersion(*pVer.HTTP_FILTER_VERSION)

    Protected logText.s     = "ots_iisapi_filter GetFilterVersion()"
    Protected descriptionSize.l
    Protected notificationMask.l
    Protected description.s = "ISAPI Unicode Filter written in PureBasic"
    Protected descripSize.l = Len(description)

    notificationMask =  #SF_NOTIFY_SECURE_PORT             | 
                        #SF_NOTIFY_NONSECURE_PORT          |
                        #SF_NOTIFY_PREPROC_HEADERS         |
                        #SF_NOTIFY_AUTHENTICATION          |
                        #SF_NOTIFY_URL_MAP                 |
                        #SF_NOTIFY_ACCESS_DENIED           |
                        #SF_NOTIFY_SEND_RESPONSE           |
                        #SF_NOTIFY_SEND_RAW_DATA           |
                        #SF_NOTIFY_LOG                     |
                        #SF_NOTIFY_END_OF_REQUEST          |
                        #SF_NOTIFY_END_OF_NET_SESSION      |
                        #SF_NOTIFY_AUTH_COMPLETE

    descriptionSize  = StringByteLength(description, #PB_UTF8)

; make the length of the description the same number of characters as #SF_MAX_FILTER_DESC_LEN

    PokeL(@*pVer\dwFilterVersion, #HTTP_FILTER_REVISION)
    PokeS(@*pVer\lpszFilterDesc,  description, descriptionSize, #PB_UTF8)
    PokeL(@*pVer\dwFlags,         notificationMask)

    logText + ", ISAPI Server Version: 0x" + RSet(Hex(*pVer\dwServerFilterVersion, #PB_Long), 8, "0")
    logText + ", ISAPI Client Version: 0x" + RSet(Hex(*pVer\dwFilterVersion, #PB_Long), 8, "0")
    logText + ", notifications requested: 0x" + RSet(Hex(notificationMask, #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.i HttpFilterProc(*pfc.HTTP_FILTER_CONTEXT, notificationType.l, *pvNotification)

    Protected logText.s = "ots_iisapi_filter HttpFilterProc() > notificationType = " + Str(notificationType)

    OutputDebugString_(logText)

; return get next notification

    ProcedureReturn #SF_STATUS_REQ_NEXT_NOTIFICATION

EndProcedure

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

ProcedureDLL.i TerminateFilter(dwFlags.l)

    Protected logText.s = "ots_iisapi_filter TerminateFilter() > process terminating"

    OutputDebugString_(logText)

; return true

    ProcedureReturn #True

EndProcedure
; IDE Options = PureBasic 5.72 (Windows - x64)
; ExecutableFormat = Shared dll
; CursorPosition = 96
; FirstLine = 62
; Folding = --
; EnableThread
; UseIcon = ..\OTS\ots.ico
; Executable = ots_iisapi_filter.dll
; DisableDebugger
; HideErrorLog
; CurrentDirectory = \
; CompileSourceDirectory
; EnableCompileCount = 5
; EnableBuildCount = 5
; EnableExeConstant
httpFilt_unicode.pbi

Code: Select all

; *************************************************************
; *  Module Name: httpFilt_unicode.pbi
; *
; *  Abstract   : This module contains the Microsoft HTTP Unicode Filter header for PureBasic
; *************************************************************
; *************************************************************

; *************************************************************/
; *   Manifest Constants
; *************************************************************/

#HSE_VERSION_MAJOR                  =  10; // 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 can be used with the pfnSFCallback function supplied in the filter context Structure

; //  Sends a complete HTTP server response header including the status, server version, message time and MIME version.
; //  Server extensions should append other information at the end, such as Content-type, Content-length etc followed by an extra '\r\n'.
; //  pData - Zero terminated string pointing to optional status string (i.e., "401 Access Denied") or NULL for the default response of "200 OK".
; //  ul1 - Zero terminated string pointing to optional data to be appended and set with the header. If NULL, the header will be terminated with an empty line.

#SF_REQ_SEND_RESPONSE_HEADER        = 0

; //  If the server denies the HTTP request, add the specified headers to the server error response.
; //  This allows an authentication filter to advertise its services w/o filtering every request. Generally the headers will be
; //  WWW-Authenticate headers with custom authentication schemes but no restriction is placed on what headers may be specified.
; //  pData - Zero terminated string pointing to one or more header lines with terminating '\r\n'.

#SF_REQ_ADD_HEADERS_ON_DENIAL       = #SF_REQ_SEND_RESPONSE_HEADER + 1

; //  Only used by raw data filters that return SF_STATUS_READ_NEXT
; //  ul1 - size in bytes for the next read

#SF_REQ_SET_NEXT_READ_SIZE          = #SF_REQ_SEND_RESPONSE_HEADER + 2

; //  Used to indicate this request is a proxy request
; //  ul1 - The proxy flags to set
; //  0x00000001 - This is a HTTP proxy request

#SF_REQ_SET_PROXY_INFO              = #SF_REQ_SEND_RESPONSE_HEADER + 3

; //  Returns the connection ID contained in the ConnID field of an ISAPI Application's Extension Control Block.
; //  This value can be used as a key to cooridinate shared data between Filters and Applications.
; //  pData - Pointer to DWORD that receives the connection ID.

#SF_REQ_GET_CONNID                  = #SF_REQ_SEND_RESPONSE_HEADER + 4

; // Used to set a SSPI security context + impersonation token derived from a client certificate.
; // pData - certificate info ( PHTTP_FILTER_CERTIFICATE_INFO )
; // ul1 - CtxtHandle*
; // ul2 - impersonation handle

#SF_REQ_SET_CERTIFICATE_INFO        = #SF_REQ_SEND_RESPONSE_HEADER + 5

; // Used to get an IIS property as defined in SF_PROPERTY_IIS
; // ul1 - Property ID

#SF_REQ_GET_PROPERTY                = #SF_REQ_SEND_RESPONSE_HEADER + 6

; // Used to normalize an URL
; // pData - URL to normalize

#SF_REQ_NORMALIZE_URL               = #SF_REQ_SEND_RESPONSE_HEADER + 7

; // Disable Notifications
; // ul1 - notifications to disable

#SF_REQ_DISABLE_NOTIFICATIONS       = #SF_REQ_SEND_RESPONSE_HEADER + 8

; //////////////////////////////////////////////////////////////////////////////////////////////////////////////

#SF_PROPERTY_SSL_CTXT               = 0
#SF_PROPERTY_INSTANCE_NUM_ID        = #SF_PROPERTY_SSL_CTXT + 1

; //////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

; // The filter has handled the HTTP request.  The server should disconnect the session.

#SF_STATUS_REQ_FINISHED             = $8000000

; // Same as SF_STATUS_FINISHED except the server should keep the TCP session open if the option was negotiated.

#SF_STATUS_REQ_FINISHED_KEEP_CONN   = #SF_STATUS_REQ_FINISHED + 1

; // The next filter in the notification chain should be called.

#SF_STATUS_REQ_NEXT_NOTIFICATION    = #SF_STATUS_REQ_FINISHED + 2

; // This filter handled the notification. No other handles should be called for this particular notification type.

#SF_STATUS_REQ_HANDLED_NOTIFICATION = #SF_STATUS_REQ_FINISHED + 3

; // An error occurred. The server should use GetLastError() and indicate the error to the client.

#SF_STATUS_REQ_ERROR                = #SF_STATUS_REQ_FINISHED + 4

; // The filter is an opaque stream filter and we're negotiating the session parameters. Only valid for raw read notification.

#SF_STATUS_REQ_READ_NEXT            = #SF_STATUS_REQ_FINISHED + 5

; //////////////////////////////////////////////////////////////////////////////////////////////////////////////

; // Bitfield indicating the requested resource has been denied by the server due to a logon failure, an ACL on a resource, an ISAPI Filter or an
; // ISAPI Application/CGI Application.
; // SF_DENIED_BY_CONFIG can appear with SF_DENIED_LOGON if the server configuration did not allow the user to logon.

#SF_DENIED_LOGON            = $00000001
#SF_DENIED_RESOURCE         = $00000002
#SF_DENIED_FILTER           = $00000004
#SF_DENIED_APPLICATION      = $00000008
#SF_DENIED_BY_CONFIG        = $00010000

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

; // see https://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx for variable types

; // bool      = .l
; // int       = .i
; // pointer   = .i
; // byte      = .c
; // dword     = .l
; // dword32   = .l
; // dwordlong = .i
; // dword64   = .i
; // float     = .f

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

Structure HTTP_FILTER_CONTEXT Align #PB_Structure_AlignC
    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 the Read And send raw Data notification types

Structure HTTP_FILTER_RAW_DATA Align #PB_Structure_AlignC
    *pvInData;                                      // Points to the data buffer.
    cbInData.l;                                     // Number of valid data bytes.
    cbInBuffer.l;                                   // Total size of buffer.
    dwReserved.l;                                   // Reserved for future use.
EndStructure

; // Retrieves the specified header value. Header names should include the trailing ':'.  The special values
; // 'method', 'url' and 'version' can be used to retrieve the individual portions of the request line.

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

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

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

; // Adds the specified header and value.

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

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

Structure HTTP_FILTER_PREPROC_HEADERS Align #PB_Structure_AlignC
    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

; //  Authentication information for this request.

Structure HTTP_FILTER_AUTHENT Align #PB_Structure_AlignC
    pszUser.a;                                      // String for username and password, empty strings for the anonymous user.
    cbUserBuff.l;                                   // The size of the buffer pointed to by pszUser. This is guaranteed to be at least SF_MAX_USERNAME.
    pszPassword.a;                                  // String containing the password for this request.
    cbPasswordBuff.l;                               // The size of the buffer pointed to by pszPassword. This is guaranteed to be at least SF_MAX_PASSWORD.
EndStructure

; //  Indicates the server is going to use the specific physical mapping for the specified URL.  Filters can modify the physical path in place.

Structure HTTP_FILTER_URL_MAP Align #PB_Structure_AlignC
    pszURL.a;                                       // String for the URL that is being mapped to a physical path.
    pszPhysicalPath.a;                              // String for the buffer where the physical path is stored.
    cbPathBuff.l;                                   // The size of the buffer pointed to by pszPhysicalPath.
EndStructure

; //  Indicates the server is going to use the specific physical mapping for the specified URL.  Filters can modify the physical path in place.
; //  Additional members beyond those from HTTP_FILTER_URL_MAP are informational.

Structure HTTP_FILTER_URL_MAP_EX Align #PB_Structure_AlignC
    pszURL.a;                                       // String for the URL that is being mapped to a physical path.
    pszPhysicalPath.a;                              // String for the buffer where the physical path is stored.
    cbPathBuff.l;                                   // The size of the buffer pointed to by pszPhysicalPath.
    dwFlags.l
    cchMatchingPath.l
    cchMatchingURL.l
    pszScriptMapEntry.a
EndStructure

Structure HTTP_FILTER_ACCESS_DENIED Align #PB_Structure_AlignC
    pszURL.a;                                       // String for the URL that is being mapped to a physical path.
    pszPhysicalPath.a;                              // String for the buffer where the physical path is stored.
    dwReason.l;                                     // Bitfield of SF_DENIED flags due to a logon failure, an ACL on a resource, an ISAPI Filter or an ISAPI Application/CGI Application.
EndStructure

; //  The log information about to be written to the server log file. The string pointers can be replaced but the memory must remain valid until
; //  the next notification

Structure HTTP_FILTER_LOG Align #PB_Structure_AlignC
    pszClientHostName.a;                            // String for the client's host name.
    pszClientUserName.a;                            // String for the client's user name.
    pszServerName.a;                                // String for the server name.
    pszOperation.a;                                 // String for the HTTP operation type.
    pszTarget.a;                                    // String for the target of the HTTP command.
    pszParameters.a;                                // String for the parameters passed to the HTTP command.
    dwHttpStatus.l;                                 // The HTTP return status.
    dwWin32Status.l;                                // The Win32 error code.
    dwBytesSent.l;                                  // The number of bytes sent from the server to the client.
    dwBytesRecvd.l;                                 // The number of bytes received by the server from the client.
    msTimeForProcessing.l;                          // The time in milliseconds required to process the client request.
EndStructure

; // Called once the client request has been authenticated.

Prototype GetUserToken(*pfc.HTTP_FILTER_CONTEXT, phToken.i)

Structure HTTP_FILTER_AUTH_COMPLETE_INFO Align #PB_Structure_AlignC
    GetHeader.GetHeader;                            // Get header function call.
    SetHeader.SetHeader;                            // Set header function call.
    AddHeader.AddHeader;                            // Add header function call.
    GetUserToken.GetUserToken;                      // Get user token function call.
    HttpStatus.l;                                   // Status for SEND_RESPONSE.
    fResetAuth.l;                                   // Boolean reserved for future use.
    dwReserved.l;                                   // Reserved for future use.
EndStructure

; //  Notification Flags
; //
; //  SF_NOTIFY_SECURE_PORT
; //  SF_NOTIFY_NONSECURE_PORT
; //
; //      Indicates whether the application wants to be notified for transactions that are happenning on the server port(s) that support data encryption
; //      (such as PCT and SSL), on only the non-secure port(s) or both.
; //
; //  SF_NOTIFY_READ_RAW_DATA
; //
; //      Applications are notified after the server reads a block of memory from the client but before the server does any processing on the
; //      block.  The data block may contain HTTP headers and entity data.

#SF_NOTIFY_SECURE_PORT             = $00000001
#SF_NOTIFY_NONSECURE_PORT          = $00000002
#SF_NOTIFY_PREPROC_HEADERS         = $00004000
#SF_NOTIFY_AUTHENTICATION          = $00002000
#SF_NOTIFY_URL_MAP                 = $00001000
#SF_NOTIFY_ACCESS_DENIED           = $00000800
#SF_NOTIFY_SEND_RESPONSE           = $00000040
#SF_NOTIFY_SEND_RAW_DATA           = $00000400
#SF_NOTIFY_LOG                     = $00000200
#SF_NOTIFY_END_OF_REQUEST          = $00000080
#SF_NOTIFY_END_OF_NET_SESSION      = $00000100
#SF_NOTIFY_AUTH_COMPLETE           = $04000000

; //  Filter ordering flags
; //
; //  Filters will tend to be notified by their specified ordering.  For ties, notification order is determined by load order.
; //
; //  SF_NOTIFY_ORDER_HIGH - Authentication or data transformation filters
; //  SF_NOTIFY_ORDER_MEDIUM
; //  SF_NOTIFY_ORDER_LOW  - Logging filters that want the results of any other filters might specify this order.

#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 Align #PB_Structure_AlignC
    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

CompilerIf #PB_Compiler_Thread = 0
    CompilerError "ISAPI Filters must be compiled with threadsafe enabled!"
CompilerEndIf

CompilerIf #PB_Compiler_Unicode = 0
    CompilerWarning "Must be compiled in Unicode!!!"
CompilerEndIf
The good news: both ascii and unicode modes work with IIS 10. IIS 10 seems to be much less buggy than previous IIS versions.

The BEST news: This now works! It takes a bit to go through all of the notifications I loaded, so that will be the next item I work on. Cutting it down to do just what I need.

I am using the OS call OutputDebugString_() to send data to Sysinternals debugview process. Remember to click on 'Capture Global Win32.'

Rich
Last edited by RichAlgeni on Thu Jul 23, 2020 12:13 am, edited 2 times in total.
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: ISAPI Filter Ascii and Unicode

Post by RichAlgeni »

Here is the debug output:

Code: Select all

[13252] ots_iisapi_filter AttachProcess() Ascii version completed successfully
[13252] ots_iisapi_filter GetFilterVersion(), ISAPI Server Version: 0x000A0000, ISAPI Client Version: 0x000A0000, notifications requested: 0x0400FFC3
[13252] ots_iisapi_filter TerminateFilter() > process terminating
[13252] ots_iisapi_filter AttachProcess() Unicode version completed successfully
[13252] ots_iisapi_filter GetFilterVersion(), ISAPI Server Version: 0x000A0000, ISAPI Client Version: 0x000A0000, notifications requested: 0x0400FFC3
[13252] ots_iisapi_filter TerminateFilter() > process terminating
dige
Addict
Addict
Posts: 1253
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Re: ISAPI Filter Ascii and Unicode

Post by dige »

I've read that ISAPI is outdated and is no longer being developed. Maybe this is the reason why the IIS10 does not work anymore?
"Daddy, I'll run faster, then it is not so far..."
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: ISAPI Filter Ascii and Unicode

Post by RichAlgeni »

Actually, I figured it out!!! I had to use Align 4 on the HTTP_FILTER_VERSION Structure.

Code: Select all

Structure HTTP_FILTER_VERSION Align 4
    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
I will edit above to correct.
Justin
Addict
Addict
Posts: 832
Joined: Sat Apr 26, 2003 2:49 pm

Re: ISAPI Filter Ascii and Unicode Now works!!!

Post by Justin »

You should use Align #PB_Structure_AlignC on all the winapi structures.
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: ISAPI Filter Ascii and Unicode Now works!!!

Post by RichAlgeni »

Justin wrote:You should use Align #PB_Structure_AlignC on all the winapi structures.
Would that be applicable to all of the structures in the pbi include file?
Justin
Addict
Addict
Posts: 832
Joined: Sat Apr 26, 2003 2:49 pm

Re: ISAPI Filter Ascii and Unicode Now works!!!

Post by Justin »

Yes, but only the converted winapi structures, not your own structures.
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: ISAPI Filter Ascii and Unicode Now works!!!

Post by RichAlgeni »

Very good! I will modify this post nce again. Thanks!
Post Reply