- Recompilación en Delphi10 de todos los paquetes de RO para generar las DCU's en Lib\D10 - Recompilación en Delphi10 de todos los paquetes de DA para generar las DCU's en Lib\D10 git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.RemObjects@9 b6239004-a887-0f4b-9937-50029ccdca16
1633 lines
59 KiB
ObjectPascal
1633 lines
59 KiB
ObjectPascal
unit uRODXISAPI;
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// Component: TDXISAPI
|
||
// Author: G.E. Ozz Nixon Jr. (onixon@dxsock.com)
|
||
// ========================================================================
|
||
// Source Owner: DX, Inc. 1995-2002
|
||
// Copyright: All code is the property of DX, Inc. Licensed for
|
||
// resell by Brain Patchwork DX (tm) and part of the
|
||
// DX (r) product lines, which are (c) 1999-2002
|
||
// DX, Inc. Source may not be distributed without
|
||
// written permission from both Brain Patchwork DX,
|
||
// and DX, Inc.
|
||
// License: (Reminder), None of this code can be added to other
|
||
// developer products without permission. This includes
|
||
// but not limited to DCU's, DCP's, DLL's, OCX's, or
|
||
// any other form of merging our technologies. All of
|
||
// your products released to a public consumer be it
|
||
// shareware, freeware, commercial, etc. must contain a
|
||
// license notification somewhere visible in the
|
||
// application.
|
||
// Example is Internet Explorer - Help->About screen
|
||
// shows the licensed code contained in the application.
|
||
// Code Version: (3rd Generation Code)
|
||
// ========================================================================
|
||
// Description:
|
||
// ========================================================================
|
||
// IMPLEMENTATION OF ISAPI 4.0 SPECIFICATIONS (FEBRUARY 2002)
|
||
// Create one instance of the TDXIAPI component in your application. To use:
|
||
// TDXISAPI.RegisterDLL(Path+Filename) - Registers the DLL with our DLLManager!
|
||
// TDXISAPI.Execute(TDXClientThread;Path+Filename) - Executes the DLL
|
||
// TDXISAPI.UnregisterDLL(Path+Filename) - removes from our DLLManager.
|
||
//
|
||
// You must specify the following events!
|
||
// TDXISAPI.GetServerVariable(Session:TDXClientThread;Variable:String;Var Results:String);
|
||
//
|
||
// All other ISAPI callbacks are actually handled internal to this component.
|
||
//
|
||
// To achieve HIGH-SPEED, register all known DLL's at the startup of your
|
||
// application, and then on termination unregister all of these DLL's. Then
|
||
// all you have to do is execute the DLL as needed.
|
||
//
|
||
// MSDN:
|
||
// Important - It is vital that the work performed by ISAPI filters is minimized,
|
||
// because the effects on scalability and performance is potentially quite severe.
|
||
// For example, if your ISAPI filter implemented your own custom encryption scheme,
|
||
// the encryption and decryption would need to take place within your ISAPI filter
|
||
// code, but the reading and writing of the data should be handled by IIS.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
interface
|
||
{$I uRODXSock.def}
|
||
|
||
{.$DEFINE USE_DLL_MGR}
|
||
{$IFNDEF LINUX}
|
||
{$DEFINE SUPPORT_COM}
|
||
{$ENDIF}
|
||
|
||
Uses
|
||
{$IFNDEF LINUX}
|
||
Windows,
|
||
{$ENDIF}
|
||
{$IFDEF SUPPORT_COM}
|
||
ActiveX,
|
||
{$ENDIF}
|
||
Classes,
|
||
uRODXString,
|
||
uRODXServerCore,
|
||
{$IFDEF USE_DLL_MGR}
|
||
DXDLLManager,
|
||
{$ENDIF}
|
||
uRODXSecurity,
|
||
uRODXISAPIFilter,
|
||
uRODXHTTPHeaderTools;
|
||
|
||
Type
|
||
HCONN=Integer;
|
||
{$IFDEF VER100}
|
||
Longword=Cardinal;
|
||
{$ENDIF}
|
||
{$IFDEF LINUX}
|
||
LPDWord=^Longword;
|
||
LPCSTR=PChar;
|
||
{$ENDIF}
|
||
|
||
Const
|
||
HSE_LOG_BUFFER_LEN=80;
|
||
HSE_MAX_EXT_DLL_NAME_LEN=256;
|
||
|
||
type
|
||
TGetServerVariableProc = function ( hConn: HCONN;
|
||
VariableName: PChar;
|
||
Buffer: Pointer;
|
||
Size:LPDWord): BOOLEAN stdcall;
|
||
|
||
TWriteClientProc = function ( ConnID: HCONN;
|
||
Buffer: Pointer;
|
||
var Bytes: Longword;
|
||
dwReserved: Longword ): BOOLEAN stdcall;
|
||
|
||
TReadClientProc = function ( ConnID: HCONN;
|
||
Buffer: Pointer;
|
||
var Size: Longword ): BOOLEAN stdcall;
|
||
|
||
TServerSupportFunctionProc = function ( hConn: HCONN;
|
||
HSERRequest: Longword;
|
||
Buffer: Pointer;
|
||
Size:Pointer{LPDWord};
|
||
DataType: Pointer{LPDWord} ): BOOLEAN stdcall;
|
||
|
||
//
|
||
// passed to extension procedure on a new request
|
||
//
|
||
type
|
||
|
||
PEXTENSION_CONTROL_BLOCK = ^TEXTENSION_CONTROL_BLOCK;
|
||
TEXTENSION_CONTROL_BLOCK = packed record
|
||
cbSize: Longword; // size of this struct.
|
||
dwVersion: Longword; // version info of this spec
|
||
ConnID: HCONN; // Context number not to be modified!
|
||
dwHttpStatusCode: Longword; // HTTP Status code
|
||
// null terminated log info specific to this Extension DLL
|
||
lpszLogData: array [0..HSE_LOG_BUFFER_LEN-1] of Char;
|
||
lpszMethod: PChar; // REQUEST_METHOD
|
||
lpszQueryString: PChar; // QUERY_STRING
|
||
lpszPathInfo: PChar; // PATH_INFO
|
||
lpszPathTranslated: PChar; // PATH_TRANSLATED
|
||
cbTotalBytes: Longword; // Total bytes indicated from client
|
||
cbAvailable: Longword; // Available number of bytes
|
||
lpbData: Pointer; // pointer to cbAvailable bytes
|
||
lpszContentType: PChar; // Content type of client data
|
||
|
||
GetServerVariable: TGetServerVariableProc;
|
||
WriteClient: TWriteClientProc;
|
||
ReadClient: TReadClientProc;
|
||
ServerSupportFunction: TServerSupportFunctionProc;
|
||
end;
|
||
PHSE_VERSION_INFO = ^HSE_VERSION_INFO;
|
||
HSE_VERSION_INFO = packed record
|
||
dwExtensionVersion: Longword;
|
||
lpszExtensionDesc: array [0..HSE_MAX_EXT_DLL_NAME_LEN-1] of Char;
|
||
end;
|
||
THSE_VERSION_INFO = HSE_VERSION_INFO;
|
||
LPHSE_VERSION_INFO = PHSE_VERSION_INFO;
|
||
|
||
Type
|
||
TDX_GetServerVariable=procedure(ClientThread:TDXClientThread;Variable:String;Var Results:String) of object;
|
||
TDX_RedirectHeader=Procedure(ClientThread:TDXClientThread;Location:String;Var Header:String) of object;
|
||
TDX_BuildHeader=Procedure(dwHttpStatusCode:Integer;var Results:String) of object;
|
||
|
||
//Extension Function
|
||
TGetExtensionVersion = function (var Ver: THSE_VERSION_INFO): BOOLEAN stdcall;
|
||
THttpExtensionProc = function (var ECB: TEXTENSION_CONTROL_BLOCK): Longword stdcall;
|
||
TTerminateExtension = function (dwFlags: Longword): BOOLEAN stdcall;
|
||
|
||
TNotificationFiltersProc = Procedure (Notify:Longword; Buf1:Pointer;
|
||
sizeBuf1:Longword; Buf2:Pointer; sizeBuf2:Longword);
|
||
|
||
TDX_FilterGetServerVariable = function (var pfc: THTTP_FILTER_CONTEXT;
|
||
VariableName: PChar; Buffer: Pointer; var Size: Longword ): BOOLEAN of Object;
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This structure is used to send certificate information to the
|
||
// ISAPI extension when the HSE_REQ_GET_CERT_INFO_EX value is set for the
|
||
// dwHSERRequest parameter of the ServerSupportFunction.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
type
|
||
TDXISAPI = class(TDXComponent)
|
||
private
|
||
fGetServerVariable:TDX_GetServerVariable;
|
||
fRedirectHeader:TDX_RedirectHeader;
|
||
fBuildHeader:TDX_BuildHeader;
|
||
fTimeout:Integer;
|
||
// fCertificate:TCERT_CONTEXT_EX;
|
||
protected
|
||
Procedure RegisterFilters(var ResultLog:String);
|
||
Procedure UnRegisterFilters(var ResultLog:String);
|
||
Procedure SetServerVariableProc(value:TFilterGetServerVariableProc);
|
||
Function GetServerVariableProc:TFilterGetServerVariableProc;
|
||
public
|
||
//////////////////////////////
|
||
// Server Event Procedure
|
||
// Not of use to end-user.
|
||
//////////////////////////////
|
||
Procedure ServerStartEvent;
|
||
Procedure ServerStopEvent;
|
||
Procedure ServerRawRead(ReadString:String;Len:Longword);
|
||
Procedure ServerPreprocHeaderEvent(DXHeaderInfo:PHeaderInfo);
|
||
Procedure ConvertedURL2Physical(URL:String;Physical:String);
|
||
//////////////////////////////
|
||
// there are more to be added between converted and end of request in 2.4
|
||
//////////////////////////////
|
||
Procedure ServerEndOfRequest;
|
||
Procedure ServerEndSession;
|
||
|
||
public
|
||
constructor Create(AOwner:TComponent); {$IFNDEF OBJECTS_ONLY} override; {$ENDIF}
|
||
Destructor Destroy; override;
|
||
Function Execute(Session:TDXClientThread;ISAPI,Method,QueryString,
|
||
PathInfo,PathTranslated,POSTContent_Type,POSTData:String;
|
||
POSTDataSize:Integer;Var ResultLog:String):Boolean;
|
||
|
||
Function RegisterDLL(ISAPI:String):Boolean;
|
||
Function UnRegisterDLL(ISAPI:String):Boolean;
|
||
|
||
Function AddFilter(ISAPI:String):Boolean;
|
||
Function RemoveFilter(ISAPI:String):Boolean;
|
||
Function FilterCount:Integer;
|
||
|
||
published
|
||
Property GetVariable:TDX_GetServerVariable read fGetServerVariable
|
||
write fGetServerVariable;
|
||
Property GetVariableFilter:TFilterGetServerVariableProc read GetServerVariableProc
|
||
write SetServerVariableProc;
|
||
Property NeedHeaderForRedirect:TDX_RedirectHeader read fRedirectHeader
|
||
write fRedirectHeader;
|
||
Property NeedHeader:TDX_BuildHeader read fBuildHeader
|
||
write fBuildHeader;
|
||
Property ReadSocketTimeout:Integer read fTimeout
|
||
write fTimeout;
|
||
end;
|
||
|
||
Implementation
|
||
|
||
Uses
|
||
{$IFDEF LINUX}
|
||
{$IFDEF FPC}dynlibs,{$ENDIF}
|
||
Libc,
|
||
{$ENDIF}
|
||
SysUtils(*{, {StrPCopy}
|
||
uRODXHTTPServerCore*);
|
||
|
||
Const
|
||
{from Microsoft's .h files for ISAPI!}
|
||
HSE_VERSION_MAJOR=5;
|
||
HSE_VERSION_MINOR=1;
|
||
HSE_VERSION=$0501;
|
||
HSE_REQ_END_RESERVED=1000;
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// The extension has finished processing and the server should disconnect the
|
||
// client and free up allocated resources.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_STATUS_SUCCESS=1;
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// The extension has finished processing and the server should wait for the next
|
||
// HTTP request if the client supports Keep-Alive connections. The extension
|
||
// can return this only if it was able to send the correct Content-Length header
|
||
// to the client.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_STATUS_SUCCESS_AND_KEEP_CONN=2;
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// The extension has queued the request for processing and will notify the
|
||
// server when it has finished. See HSE_REQ_DONE_WITH_SESSION under
|
||
// ServerSupportFunction.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_STATUS_PENDING=3;
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// The extension has encountered an error while processing the request, so the
|
||
// server can disconnect the client and free up allocated resources. An HTTP
|
||
// status code of 500 is written to the IIS log for the request.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_STATUS_ERROR=4;
|
||
// The following are the values to request services with the
|
||
// ServerSupportFunction().
|
||
// Values from 0 to 1000 are reserved for future versions of the interface
|
||
HSE_REQ_BASE=0;
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function allows your ISAPI extension to redirect a client
|
||
// browser to a different URL from the one they initially requested. When this
|
||
// support function is called, you must provide the new URL. IIS then sends the
|
||
// HTTP status code 302 (URL Redirect) to the client browser.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_SEND_URL_REDIRECT_RESP=( HSE_REQ_BASE + 1 ); // ISAPI 2.0/3.0
|
||
HSE_REQ_SEND_URL=( HSE_REQ_BASE + 2 ); // ISAPI 2.0/3.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function allows you to request that IIS send a complete HTTP
|
||
// response header to the client browser, including the HTTP status, server
|
||
// version, message time, and MIME version. Your extension can also, optionally,
|
||
// append other header information to the end of IIS-generated header, such as
|
||
// Content-Type or Content-Length.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_SEND_RESPONSE_HEADER=( HSE_REQ_BASE + 3 ); // ISAPI 2.0/3.0 // depreciated
|
||
HSE_REQ_SEND_RESPONSE_HEADER_EX=(HSE_REQ_END_RESERVED+16); // ISAPI 2.0/3.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// If your extension is performing some form of extended processing, and its
|
||
// HttpExtensionProc entry-point function has returned the status code
|
||
// HSE_STATUS_PENDING, then your extension should notify IIS when all
|
||
// processing is complete by using this support function. Calling this function
|
||
// will terminate the session connection.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_DONE_WITH_SESSION=( HSE_REQ_BASE + 4 ); // ISAPI 2.0/3.0
|
||
|
||
// These are Microsoft specific extensions
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function allows your ISAPI extension to map a logical URL path
|
||
// to a physical path.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_MAP_URL_TO_PATH=(HSE_REQ_END_RESERVED+1); // ISAPI 2.0/3.0
|
||
HSE_REQ_MAP_URL_TO_PATH_EX=(HSE_REQ_END_RESERVED+12); // ISAPI 4.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function allows your ISAPI extension to retrieve context and
|
||
// credential handles to the CtxtHandle and CredHandle structures, as defined
|
||
// in the header file sspi.h. Once these handles are retrieved, they can be
|
||
// used to query or manipulate the server certificate information by using the
|
||
// standard certificate APIs that are also defined in sspi.h.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_GET_SSPI_INFO=(HSE_REQ_END_RESERVED+2); // ISAPI 2.0/3.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// You can use this support function to write your own custom log strings to
|
||
// the log record. When this function is called, the string contained in the
|
||
// buffer you specify is appended to the log record for the current HTTP
|
||
// request.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_APPEND_LOG_PARAMETER=(HSE_REQ_END_RESERVED+3); // ISAPI 2.0/3.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// Using this support function, you can set a special callback function that
|
||
// will be used for handling asynchronous I/O operations.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_IO_COMPLETION=(HSE_REQ_END_RESERVED+5); // ISAPI 2.0/3.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function enables your ISAPI extension to call the
|
||
// high-performance Win32<33> API TransmitFile function to send a file to the
|
||
// client browser. This function accepts as a parameter a pointer to a
|
||
// structure, HSE_TF_INFO, so that you can specify the file handle of the file
|
||
// to be sent, HTTP headers for the response, and other important information.
|
||
//
|
||
// TransmitFile is carried out asynchronously, so your extension must specify a
|
||
// special callback function so IIS can notify your extension when the
|
||
// asynchronous write operation has completed. You can do this either by using
|
||
// the pfnHseIO member of the HSE_TF_INFO used in the function call, or by using
|
||
// the support function HSE_REQ_IO_COMPLETION.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_TRANSMIT_FILE=(HSE_REQ_END_RESERVED+6); // ISAPI 2.0/3.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function forces IIS to reprocess the discretionary access
|
||
// control list (DACL) for an ISAPI extension's DLL. Given sufficient security
|
||
// permissions, this support function can be used to reprocess another
|
||
// extension's DACL, as well.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_REFRESH_ISAPI_ACL=(HSE_REQ_END_RESERVED+7); // ISAPI 2.0/3.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function can be used to determine the Keep-Alive status of the
|
||
// current connection.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_IS_KEEP_CONN=(HSE_REQ_END_RESERVED+8);
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// Using this support function, your ISAPI extension can request that IIS
|
||
// attempt to read from the client asynchronously. In order for this function
|
||
// to work properly, however, you must have specified a special callback
|
||
// function, which IIS will call when the asynchronous read has completed. This
|
||
// callback function can be set using the ServerSupportFunction request
|
||
// HSE_REQ_IO_COMPLETION.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_ASYNC_READ_CLIENT=(HSE_REQ_END_RESERVED+10);
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function allows you to retrieve a handle to the impersonation
|
||
// token that the request is using. An impersonation token represents a user
|
||
// context.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_GET_IMPERSONATION_TOKEN=(HSE_REQ_END_RESERVED+11); // ISAPI 4.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function can be used to request that, when disconnecting the
|
||
// current connection, IIS will use an abortive shutdown sequence to close the
|
||
// TCP/IP connection socket.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_ABORTIVE_CLOSE=(HSE_REQ_END_RESERVED+14);
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This support function specifies the certificate context for the first
|
||
// certificate in the client's certificate chain.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_GET_CERT_INFO_EX=(HSE_REQ_END_RESERVED+15); // ISAPI 4.0
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// This server support function sends a request to IIS to close the current
|
||
// client socket connection, even if there is an asynchronous read pending.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
HSE_REQ_CLOSE_CONNECTION=(HSE_REQ_END_RESERVED+17); // ISAPI 5.0/5.1
|
||
|
||
HSE_TERM_MUST_UNLOAD=2;
|
||
|
||
Type
|
||
PHSE_SEND_HEADER_EX_INFO=^HSE_SEND_HEADER_EX_INFO;
|
||
HSE_SEND_HEADER_EX_INFO=Record
|
||
pszStatus:LPCSTR; // HTTP status code; for example "200 OK".
|
||
pszHeader:LPCSTR; // HTTP header.
|
||
cchStatus:Longword; // Number of characters in status code.
|
||
cchHeader:Longword; // Number of characters in header.
|
||
fKeepConn:BOOLEAN; // Keep client connection alive?
|
||
End;
|
||
Const
|
||
MAX_PATH = (256);
|
||
|
||
Type
|
||
PCERT_CONTEXT_EX=^TCERT_CONTEXT_EX;
|
||
TCERT_CONTEXT_EX = packed record
|
||
CertContext:TCERT_CONTEXT;
|
||
cbAllocated:Longword;
|
||
dwCertificateFlags:Longword;
|
||
End;
|
||
PHSE_URL_MAPEX_INFO = ^THSE_URL_MAPEX_INFO;
|
||
THSE_URL_MAPEX_INFO = record
|
||
lpszPath: array [0..MAX_PATH-1] of Char; // Physical path mapped to by the URL.
|
||
dwFlags:Longword; // Flags associated with this URL path.
|
||
cchMatchingPath:Longword; // Number of matching characters in
|
||
cchMatchingURL:Longword; // Number of matching characters in URL.
|
||
dwReserved1:Longword;
|
||
dwReserved2:Longword;
|
||
End;
|
||
PDXThreadRecord=^TDXThreadRecord;
|
||
TDXThreadRecord=record
|
||
fAllocMem:TList;
|
||
fToken:Cardinal;
|
||
fDopHeaders:String;
|
||
fDopDeniedHeaders:String;
|
||
fHeaderInfo:PHeaderInfo;
|
||
ThreadID:HCONN;
|
||
Thread:TDXClientThread;
|
||
fGetServerVariable:TDX_GetServerVariable;
|
||
fRedirectHeader:TDX_RedirectHeader;
|
||
fBuildHeader:TDX_BuildHeader;
|
||
fiTimeout:Integer;
|
||
ECB:TEXTENSION_CONTROL_BLOCK;
|
||
mapex:THSE_URL_MAPEX_INFO;
|
||
fRealPath:String; // 3.0
|
||
fISAPIThreadPoolDone:Boolean;
|
||
end;
|
||
PDXFilterRecord = ^TDXFilterRecord;
|
||
TDXFilterRecord = record
|
||
fName:String;
|
||
fVersion:PHTTP_FILTER_VERSION;
|
||
fNotification:Boolean;
|
||
fDisableNotification:Longword;
|
||
fNextReadSize:Longword;
|
||
End;
|
||
PDXMemoryBlock= ^TDXMemoryBlock;
|
||
TDXMemoryBlock = record
|
||
fPointer:Pointer;
|
||
fSize:Longword;
|
||
End;
|
||
|
||
Var
|
||
fDXThreadArray:TList;
|
||
fActiveFilter:PDXFilterRecord;
|
||
fFilter:TList;
|
||
{$IFDEF USE_DLL_MGR}
|
||
fDLLManager:TDXDLLManager;
|
||
{$ENDIF}
|
||
fPreprocHeader:PHeaderInfo;
|
||
fGetServerVariableFilterProc:TFilterGetServerVariableProc;
|
||
|
||
constructor TDXISAPI.Create(AOwner:TComponent);
|
||
begin
|
||
inherited Create(AOwner);
|
||
{$IFDEF USE_DLL_MGR}
|
||
fDLLManager:=TDXDLLManager.Create(Nil);
|
||
{$ENDIF}
|
||
fDXThreadArray:=TList.Create;
|
||
fFilter:=TList.Create;
|
||
fTimeout:=30000;
|
||
end;
|
||
|
||
destructor TDXISAPI.Destroy;
|
||
Var
|
||
DXThreadRecord:PDXThreadRecord;
|
||
DXMemoryBlock:PDXMemoryBlock;
|
||
|
||
begin
|
||
MyCriticalSection.StartingWrite;
|
||
If Assigned(fDXThreadArray) then Begin
|
||
MyCriticalSection.StartingWrite;
|
||
While fDXThreadArray.Count>0 do Begin
|
||
DXThreadRecord:=fDXThreadArray[0];
|
||
//Free memory for FilterAllocMem
|
||
while DXThreadRecord^.fAllocMem.Count>0 do Begin
|
||
DXMemoryBlock:=DXThreadRecord^.fAllocMem[0];
|
||
FreeMem(DXMemoryBlock^.fPointer, DXMemoryBlock^.fSize);
|
||
DXThreadRecord^.fAllocMem.Delete(0);
|
||
End;
|
||
Dispose(DXThreadRecord);
|
||
fDXThreadArray.Delete(0);
|
||
End;
|
||
MyCriticalSection.FinishedWrite;
|
||
fDXThreadArray.Free;
|
||
fDXThreadArray := Nil;
|
||
End;
|
||
MyCriticalSection.FinishedWrite;
|
||
|
||
{$IFDEF USE_DLL_MGR}
|
||
If Assigned(fDLLManager) then Begin
|
||
fDLLManager.Free;
|
||
fDLLManager := Nil;
|
||
End;
|
||
{$ENDIF}
|
||
|
||
If Assigned(fFilter) then Begin
|
||
fFilter.Free;
|
||
fFilter := Nil;
|
||
End;
|
||
|
||
inherited destroy;
|
||
end;
|
||
|
||
Function FindThread(FindHCONN:HCONN):PDXThreadRecord;
|
||
Var
|
||
Loop:Integer;
|
||
DXThreadRecord:PDXThreadRecord;
|
||
|
||
Begin
|
||
Result:=Nil;
|
||
// MyCriticalSection.StartingRead;
|
||
For Loop:=fDXThreadArray.Count-1 downto 0 do Begin
|
||
DXThreadRecord:=PDXThreadRecord(fDXThreadArray[Loop]);
|
||
If DXThreadRecord^.ThreadID=FindHCONN then Begin
|
||
Result:=DXThreadRecord;
|
||
Break; // o.z
|
||
End;
|
||
End;
|
||
// MyCriticalSection.FinishedRead;
|
||
End;
|
||
|
||
Function FindThreadToFilter(var pfc: THTTP_FILTER_CONTEXT):PDXThreadRecord;
|
||
var
|
||
conn:Pointer;
|
||
Begin
|
||
GetMem(conn, sizeof(Longword));
|
||
THTTP_FILTER_CONTEXT(pfc).ServerSupportFunction(pfc, SF_REQ_GET_CONNID, conn, 0, 0);
|
||
Result:=FindThread(HCONN(conn^));
|
||
FreeMem(conn, sizeof(Longword));
|
||
End;
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// Filter function implementation
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
Function FilterAddResponseHeaders(var pfc{: THTTP_FILTER_CONTEXT};
|
||
lpszHeaders: PChar; dwReserved: Longword):BOOLEAN; stdcall;
|
||
var
|
||
DXThreadRecord:PDXThreadRecord;
|
||
Begin
|
||
DXThreadRecord:=FindThreadToFilter(THTTP_FILTER_CONTEXT(pfc));
|
||
DXThreadRecord^.fDopHeaders:=DXThreadRecord^.fDopHeaders+lpszHeaders;
|
||
Result:=True;
|
||
End;
|
||
|
||
Function FilterWriteClient(var pfc{: THTTP_FILTER_CONTEXT};
|
||
Buffer: Pointer; var Bytes: Longword; dwReserved: Longword): BOOLEAN; stdcall;
|
||
var DXThreadRecord:PDXThreadRecord;
|
||
conn:Pointer;
|
||
Begin
|
||
GetMem(conn, sizeof(Longword));
|
||
THTTP_FILTER_CONTEXT(pfc).ServerSupportFunction(pfc, SF_REQ_GET_CONNID, conn, 0, 0);
|
||
DXThreadRecord:=FindThread(HCONN(conn^));
|
||
FreeMem(conn, sizeof(Longword));
|
||
{$IFDEF VER100} // D3
|
||
DXThreadRecord^.Thread.Socket.BlockWrite(Buffer,Bytes);
|
||
{$ELSE}
|
||
DXThreadRecord^.Thread.Socket.Write(Buffer,Bytes);
|
||
{$ENDIF}
|
||
Result:=True;
|
||
End;
|
||
|
||
Function FilterAllocMem(var pfc{: THTTP_FILTER_CONTEXT}; cbSize: Longword;
|
||
dwReserved: Longword):Pointer; stdcall;
|
||
var p:Pointer;
|
||
MemoryBlock:TDXMemoryBlock;
|
||
DXThreadRecord:PDXThreadRecord;
|
||
Begin
|
||
p:=Nil;
|
||
Try
|
||
GetMem(p, cbSize);
|
||
Except
|
||
FreeMem(p);
|
||
Result:=Nil;
|
||
Exit;
|
||
End;
|
||
MemoryBlock.fPointer:=p;
|
||
MemoryBlock.fSize:=cbSize;
|
||
DXThreadRecord:=FindThreadToFilter(THTTP_FILTER_CONTEXT(pfc));
|
||
DXThreadRecord^.fAllocMem.Add(@MemoryBlock);
|
||
Result:=p;
|
||
End;
|
||
|
||
Function FilterServerSupportFunction(var pfc{: THTTP_FILTER_CONTEXT};
|
||
sfReq: Longword; pData: Pointer; ul1, ul2: Longword):BOOLEAN; stdcall;
|
||
var
|
||
Results, hex:String;
|
||
normal:PString;
|
||
size:Longword;
|
||
DXThreadRecord:PDXThreadRecord;
|
||
i, dec, code : Integer;
|
||
Begin
|
||
Result:=True;
|
||
|
||
case sfReq of
|
||
SF_REQ_SEND_RESPONSE_HEADER:Begin
|
||
If pData = Nil then Results:='HTTP/1.1 200 OK'+#13#10
|
||
Else Results:=String(pData^);
|
||
Results:=Results+String(Pointer(ul1)^);
|
||
size:=Length(Results)+1;
|
||
THTTP_FILTER_CONTEXT(pfc).WriteClient(pfc, PChar(Results), size, 0);
|
||
End; //SF_REQ_SEND_RESPONSE_HEADER
|
||
|
||
SF_REQ_ADD_HEADERS_ON_DENIAL:Begin
|
||
DXThreadRecord := FindThreadToFilter(THTTP_FILTER_CONTEXT(pfc));
|
||
DXThreadRecord.fDopDeniedHeaders :=
|
||
DXThreadRecord.fDopDeniedHeaders+ String(pData);
|
||
End;//SF_REQ_ADD_HEADERS_ON_DENIAL
|
||
|
||
SF_REQ_SET_NEXT_READ_SIZE:Begin
|
||
fActiveFilter.fNextReadSize := ul1;
|
||
End; //SF_REQ_SET_NEXT_READ_SIZE
|
||
|
||
SF_REQ_SET_PROXY_INFO:Begin
|
||
//You can use this support function to indicate whether
|
||
//the current request is an HTTP proxy request.
|
||
if ul1 = 1 then Begin
|
||
//request is a proxy request.
|
||
End
|
||
Else
|
||
if ul1 = 0 then Begin
|
||
//request is not a proxy request
|
||
End;
|
||
End; //SF_REQ_SET_PROXY_INFO
|
||
|
||
SF_REQ_GET_CONNID:Begin
|
||
HCONN(pData^):=GetCurrentThreadId;
|
||
End;
|
||
|
||
SF_REQ_DISABLE_NOTIFICATIONS:Begin
|
||
fActiveFilter.fDisableNotification:=ul1;
|
||
End;
|
||
|
||
SF_REQ_GET_PROPERTY:Begin
|
||
//You can use this support function to retrieve special IIS
|
||
//properties defined in SF_PROPERTY_IIS.
|
||
case ul1 of
|
||
SF_PROPERTY_INSTANCE_NUM_ID:Begin
|
||
pData := Nil;
|
||
End;
|
||
End; //case
|
||
End;
|
||
|
||
SF_REQ_NORMALIZE_URL:Begin
|
||
normal := PString(pData);
|
||
i:=1;
|
||
while i<> Length(normal^) do
|
||
Begin
|
||
if normal^[i] = '%' then Begin
|
||
hex := Copy(normal^, i, 3);
|
||
hex[1] := '$';
|
||
Val(hex, dec, Code);
|
||
if code <> 0 then Delete(normal^, i, 3)
|
||
Else Begin
|
||
Delete(normal^, i, 2);
|
||
normal^[i]:=Char(dec);
|
||
End;
|
||
End;
|
||
i := i + 1;
|
||
End;//while
|
||
End; //SF_REQ_NORMALIZE_URL
|
||
else
|
||
Result:=False;
|
||
End;
|
||
End;
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// MSDN:
|
||
// The AddHeader callback function adds an HTTP header to the incoming request
|
||
// or outgoing response. This callback function is available only during
|
||
// notifications for the SF_NOTIFY_PREPROC_HEADERS and
|
||
// SF_NOTIFY_SEND_RESPONSE events.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
Function FilterAddHeader(var pfc: THTTP_FILTER_CONTEXT; lpszName,
|
||
lpszValue: PChar): BOOLEAN; stdcall;
|
||
var DXThreadRecord:PDXThreadRecord;
|
||
HeaderTools:TDXHTTPHeaderTools;
|
||
Begin
|
||
DXThreadRecord:=FindThreadToFilter(pfc);
|
||
HeaderTools := TDXHTTPHeaderTools.Create(Nil);
|
||
if Not Assigned(DXThreadRecord) then HeaderTools.Init(fPreprocHeader)
|
||
Else HeaderTools.Init(DXThreadRecord.fHeaderInfo);
|
||
Result := HeaderTools.AddHeader(String(lpszName), String(lpszValue));
|
||
HeaderTools.Free;
|
||
End;
|
||
|
||
Function FilterGetHeader(var pfc: THTTP_FILTER_CONTEXT; lpszName: PChar;
|
||
var lpvBuffer; var lpdwSize: Longword):BOOLEAN; stdcall;
|
||
var DXThreadRecord:PDXThreadRecord;
|
||
HeaderTools:TDXHTTPHeaderTools;
|
||
res:String;
|
||
resLength:Longword;
|
||
Begin
|
||
Result := False;
|
||
DXThreadRecord:=FindThreadToFilter(pfc);
|
||
HeaderTools := TDXHTTPHeaderTools.Create(Nil);
|
||
if Not Assigned(DXThreadRecord) then HeaderTools.Init(fPreprocHeader)
|
||
Else HeaderTools.Init(DXThreadRecord.fHeaderInfo);
|
||
res := HeaderTools.HeaderGetString(String(lpszName));
|
||
if res <> '' then Begin
|
||
resLength:=Length(res);
|
||
Result := True;
|
||
PChar(lpvBuffer) := PChar(res);
|
||
lpdwSize := resLength;
|
||
End;
|
||
HeaderTools.Free;
|
||
End;
|
||
|
||
Function FilterSetHeader(var pfc: THTTP_FILTER_CONTEXT; lpszName,
|
||
lpszValue: PChar):BOOLEAN; stdcall;
|
||
var DXThreadRecord:PDXThreadRecord;
|
||
HeaderTools:TDXHTTPHeaderTools;
|
||
Begin
|
||
DXThreadRecord:=FindThreadToFilter(pfc);
|
||
HeaderTools := TDXHTTPHeaderTools.Create(Nil);
|
||
if Not Assigned(DXThreadRecord) then HeaderTools.Init(fPreprocHeader)
|
||
Else HeaderTools.Init(DXThreadRecord.fHeaderInfo);
|
||
Result := HeaderTools.SetHeader(String(lpszName), String(lpszValue));
|
||
HeaderTools.Free;
|
||
End;
|
||
|
||
Procedure NotificationFilters(Notify:Longword; Buf1:Pointer; sizeBuf1:Longword;
|
||
Buf2:Pointer; sizeBuf2:Longword);
|
||
var p:Pointer;
|
||
filterContext:THTTP_FILTER_CONTEXT;
|
||
i:Integer;
|
||
filterRecord:PDXFilterRecord;
|
||
DLLHandle:THandle;
|
||
filterProc:THttpFilterProc;
|
||
outRes:PChar;
|
||
str:String;
|
||
outResSize:Longword;
|
||
DXThreadRecord:PDXThreadRecord;
|
||
|
||
Begin
|
||
If fFilter.Count<1 then Exit;
|
||
with filterContext do Begin
|
||
cbSize:=sizeof(THTTP_FILTER_CONTEXT);
|
||
Revision:=4;
|
||
ServerContext:=Nil;
|
||
ulReserved:=0;
|
||
fIsSecurePort:=False;
|
||
pFilterContext:=Nil;
|
||
GetServerVariable:=fGetServerVariableFilterProc;
|
||
AddResponseHeaders:=FilterAddresponseHeaders;
|
||
WriteClient:=FilterWriteClient;
|
||
AllocMem:=FilterAllocMem;
|
||
ServerSupportFunction:=FilterServerSupportFunction;
|
||
End;
|
||
DXThreadRecord:=FindThreadToFilter(filterContext);
|
||
|
||
Case Notify of
|
||
//Port Security Settings
|
||
SF_NOTIFY_SECURE_PORT : Begin
|
||
filterContext.fIsSecurePort:=True;
|
||
p:=Nil;
|
||
End;
|
||
|
||
SF_NOTIFY_NONSECURE_PORT : Begin
|
||
filterContext.fIsSecurePort:=False;
|
||
p:=Nil;
|
||
End;
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// This event was used when the ISAPI sends data to the client.
|
||
// Or when the server is reading data from the client.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
SF_NOTIFY_SEND_RAW_DATA: Begin
|
||
//this probably needs to be redesigned
|
||
GetMem(p, sizeof(THTTP_FILTER_RAW_DATA));
|
||
with PHTTP_FILTER_RAW_DATA(p)^ do Begin
|
||
pvInData:=Buf1;
|
||
cbInData:=sizeBuf1;
|
||
cbInBuffer:=sizeof(Buf1);
|
||
dwReserved:=0;
|
||
End;
|
||
End;
|
||
SF_NOTIFY_READ_RAW_DATA:Begin
|
||
//HTTP_FILTER_RAW_DATA
|
||
GetMem(p, sizeof(THTTP_FILTER_RAW_DATA));
|
||
with PHTTP_FILTER_RAW_DATA(p)^ do Begin
|
||
pvInData:=Buf1;
|
||
cbInData:=sizeBuf1;
|
||
cbInBuffer:=sizeof(Buf1);
|
||
dwReserved:=0;
|
||
End;
|
||
End;
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// Create hooks for Get/Set/Add Header Routines
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
SF_NOTIFY_PREPROC_HEADERS:Begin
|
||
//HTTP_FILTER_PREPROC_HEADERS
|
||
GetMem(p, sizeof(THTTP_FILTER_PREPROC_HEADERS));
|
||
with PHTTP_FILTER_PREPROC_HEADERS(p)^ do Begin
|
||
GetHeader:=FilterGetHeader;
|
||
SetHeader:=FilterSetHeader;
|
||
AddHeader:=FilterAddHeader;
|
||
HttpStatus:=200; //HTTP_STATUS_CONTINUE
|
||
dwReserved:=0;
|
||
End;
|
||
fPreprocHeader := PHeaderInfo(Buf1);
|
||
End;
|
||
|
||
SF_NOTIFY_AUTHENTICATION:Begin
|
||
//HTTP_FILTER_AUTHENT
|
||
GetMem(p, sizeof(THTTP_FILTER_AUTHENT));
|
||
with PHTTP_FILTER_AUTHENT(p)^ do Begin
|
||
pszUser:=PChar(Buf1);
|
||
cbUserBuff:=sizeBuf1;
|
||
pszPassword:=PChar(Buf2);
|
||
cbPasswordBuff:=sizeBuf2;
|
||
End;
|
||
End;
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// Notification is given to the filters after you have looked up the physical
|
||
// path. If the filters do not like it, then they can only close the connection
|
||
// and use SF_NOTIFY_PREPROC_HEADERS to write a 302 url.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
SF_NOTIFY_URL_MAP:Begin
|
||
// HTTP_FILTER_URL_MAP
|
||
GetMem(p, sizeof(THTTP_FILTER_URL_MAP));
|
||
with PHTTP_FILTER_URL_MAP(p)^ do Begin
|
||
pszURL:=PChar(Buf1);
|
||
pszPhysicalPath:=PChar(Buf2);
|
||
cbPathBuff:=sizeBuf2;
|
||
End;
|
||
End;
|
||
|
||
SF_NOTIFY_ACCESS_DENIED:Begin
|
||
// HTTP_FILTER_ACCESS_DENIED
|
||
GetMem(p, sizeof(THTTP_FILTER_ACCESS_DENIED));
|
||
with PHTTP_FILTER_ACCESS_DENIED(p)^ do Begin
|
||
pszURL:=PChar(Buf1); // Requesting URL
|
||
dwReason:=sizeBuf1; // Bitfield of SF_DENIED flags
|
||
pszPhysicalPath:=PChar(Buf2); // Physical path of resource
|
||
End;
|
||
End;
|
||
|
||
SF_NOTIFY_LOG:Begin
|
||
//HTTP_FILTER_LOG
|
||
GetMem(p, sizeof(THTTP_FILTER_LOG));
|
||
with PHTTP_FILTER_LOG(p)^ do Begin
|
||
pszClientHostName:='not support';
|
||
pszClientUserName:='not support';
|
||
pszServerName:='not support';
|
||
pszOperation:='not support';
|
||
pszTarget:='not support';
|
||
pszParameters:='not support';
|
||
dwHttpStatus:=200;
|
||
dwWin32Status:=0;
|
||
dwBytesSent:=0;
|
||
dwBytesRecvd:=0;
|
||
msTimeForProcessing:=0;
|
||
End;
|
||
End;
|
||
|
||
SF_NOTIFY_END_OF_REQUEST:Begin
|
||
p:=Nil;
|
||
End;
|
||
|
||
SF_NOTIFY_END_OF_NET_SESSION:Begin
|
||
p:=Nil;
|
||
End;
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// Create hooks for Get/Set/Add Header Routines - guess means to actually
|
||
// transmit the header to the client.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
SF_NOTIFY_SEND_RESPONSE:Begin
|
||
//HTTP_FILTER_SEND_RESPONSE
|
||
GetMem(p, sizeof(THTTP_FILTER_SEND_RESPONSE));
|
||
with PHTTP_FILTER_SEND_RESPONSE(p)^ do Begin
|
||
GetHeader:=FilterGetHeader;
|
||
SetHeader:=FilterSetHeader;
|
||
AddHeader:=FilterAddHeader;
|
||
HttpStatus:=200;
|
||
dwReserved:=0;
|
||
End;
|
||
// DXThreadRecord.fHeaderInfo := PHeaderInfo(Buf1);
|
||
End;
|
||
Else
|
||
Exit;
|
||
End;
|
||
|
||
for i:=fFilter.Count-1 downto 0 do Begin
|
||
filterRecord:=fFilter.Items[i];
|
||
if Not filterRecord.fNotification then continue;
|
||
if (filterRecord.fVersion.dwFlags AND
|
||
(Not filterRecord.fDisableNotification) AND Notify)=0 then continue;
|
||
fActiveFilter:=filterRecord;
|
||
{$IFDEF USE_DLL_MGR}
|
||
DLLHandle:=fDLLManager.GetDLLHandle(filterRecord.fName);
|
||
{$ELSE}
|
||
{$IFDEF LINUX}
|
||
DLLHandle:=LoadLibrary(PChar(filterRecord.fName));
|
||
{$ELSE}
|
||
DLLHandle:=LoadLibraryEx(PChar(filterRecord.fName),0,0);
|
||
{$ENDIF}
|
||
{$ENDIF}
|
||
If DLLHandle=0 then continue;
|
||
@filterProc:=GetProcAddress(DLLHandle,PChar('HttpFilterProc'));
|
||
If Not Assigned(filterProc) then continue;
|
||
case filterProc(filterContext, Notify, p) of
|
||
SF_STATUS_REQ_FINISHED_KEEP_CONN,
|
||
SF_STATUS_REQ_FINISHED:Begin
|
||
if Assigned(DXThreadRecord) then
|
||
DXThreadRecord.Thread.Socket.CloseNow;
|
||
End;
|
||
SF_STATUS_REQ_NEXT_NOTIFICATION:Begin
|
||
continue; // pass to next filter
|
||
End;
|
||
SF_STATUS_REQ_HANDLED_NOTIFICATION:Begin
|
||
Break; // handled and done
|
||
End;
|
||
SF_STATUS_REQ_ERROR:Begin
|
||
NotificationFilters(SF_NOTIFY_ACCESS_DENIED, PChar(filterRecord.fName),
|
||
SF_DENIED_FILTER, PChar(''), 0);
|
||
|
||
{$IFNDEF LINUX}
|
||
FormatMessage(
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER OR
|
||
FORMAT_MESSAGE_FROM_SYSTEM OR
|
||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
Nil,
|
||
GetLastError(),
|
||
0, // Default language
|
||
@outRes,
|
||
0,
|
||
Nil
|
||
);
|
||
{$ENDIF}
|
||
if outRes <> '' then Begin
|
||
str := 'HTTP/1.1 500 '+#13#10;
|
||
str := str + DXThreadRecord.fDopDeniedHeaders;
|
||
str := str + String(outRes) +#13#10;
|
||
outResSize:=Length(str);
|
||
filterContext.WriteClient(filterContext, PChar(str), outResSize, 0);
|
||
End
|
||
Else Begin
|
||
str:='HTTP/1.1 500'+#13#10 + DXThreadRecord.fDopDeniedHeaders;
|
||
outResSize:=Length(str);
|
||
filterContext.WriteClient(filterContext, PChar(str), outResSize, 0);
|
||
End;
|
||
if Assigned(DXThreadRecord) then
|
||
DXThreadRecord.Thread.Socket.CloseNow;
|
||
End; //SF_STATUS_REQ_ERROR
|
||
|
||
// to-do: this has to be able to let the web server object do the read,
|
||
// that way no data disappear from the stream. Normally this status type
|
||
// is only returned when the filter is opaque (like SSL).
|
||
SF_STATUS_REQ_READ_NEXT:Begin
|
||
DXThreadRecord.ECB.ReadClient(DXThreadRecord.ThreadID, Pointer(outRes), filterRecord.fNextReadSize);
|
||
End; //SF_STATUS_REQ_READ_NEXT
|
||
End; //case
|
||
|
||
End; //for
|
||
// once done - we have to return the changes to the P content!
|
||
if Assigned(p) then FreeMem(p);
|
||
fActiveFilter:=Nil;
|
||
End;
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// Extension ISAPI implementation
|
||
// ==============================
|
||
// ISAPI CALLBACK FUNCTIONS
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
function ServerVariable(ThreadID:HCONN;Variable:PChar;Buffer:Pointer;Size:LPDWord):BOOLEAN; stdcall;
|
||
var
|
||
DXThreadRecord:PDXThreadRecord;
|
||
Results:String;
|
||
Str:String;
|
||
|
||
begin
|
||
Result:=False;
|
||
LongWord(Size^):=0;
|
||
DXThreadRecord:=FindThread(ThreadID);
|
||
If Not Assigned(DXThreadRecord) then Exit;
|
||
Results:='';
|
||
str := Variable;
|
||
If Str='INSTANCE_ID' then Results:=IntToStr(ThreadID)
|
||
Else if Assigned(DXThreadRecord^.fGetServerVariable) then
|
||
DXThreadRecord^.fGetServerVariable(DXThreadRecord^.Thread,Str,Results);
|
||
StrPCopy(PChar(Buffer),Results);
|
||
If Results<>'' then LongWord(Size^):=Length(Results)+1;
|
||
Result:=True;
|
||
end;
|
||
|
||
Function ExtensionWriteClient(ThreadID:HCONN;Buf:Pointer;Var Bytes:Longword;dwReserved:Longword):BOOLEAN; stdcall;
|
||
var
|
||
DXThreadRecord:PDXThreadRecord;
|
||
|
||
begin
|
||
If Bytes=0 then Begin // PHP occasionally calls this with zero bytes?!
|
||
Result:=True;
|
||
Exit;
|
||
End;
|
||
Result:=False;
|
||
DXThreadRecord:=FindThread(ThreadID);
|
||
If Not Assigned(DXThreadRecord) then Exit;
|
||
NotificationFilters(SF_NOTIFY_SEND_RAW_DATA, Buf, Bytes, Nil, 0);
|
||
{$IFDEF VER100} // D3
|
||
DXThreadRecord^.Thread.Socket.BlockWrite(Buf,Bytes);
|
||
{$ELSE}
|
||
DXThreadRecord^.Thread.Socket.Write(Buf,Bytes);
|
||
{$ENDIF}
|
||
Result:=DXThreadRecord^.Thread.Socket.LastCommandStatus=0;
|
||
end;
|
||
|
||
function ExtensionReadClient(ThreadID:HCONN;Buf:Pointer;var Size:Longword):BOOLEAN; stdcall;
|
||
var
|
||
DXThreadRecord:PDXThreadRecord;
|
||
begin
|
||
Result:=False;
|
||
DXThreadRecord:=FindThread(ThreadID);
|
||
If Not Assigned(DXThreadRecord) then Exit;
|
||
NotificationFilters(SF_NOTIFY_READ_RAW_DATA, Buf, Size, Nil, 0);
|
||
{$IFDEF VER100}
|
||
Size:=DXThreadRecord^.Thread.Socket.BlockRead(Buf,Size);
|
||
{$ELSE}
|
||
Size:=DXThreadRecord^.Thread.Socket.Read(Buf,Size);
|
||
{$ENDIF}
|
||
Result:=True;
|
||
end;
|
||
|
||
{$HINTS OFF}
|
||
function ServerSupportFunctionS(ThreadID:HCONN;
|
||
HSE_REQ:Longword;
|
||
Buf:Pointer;
|
||
Size:Pointer{PDWORD};
|
||
DataType:Pointer{PDWORD}):BOOLEAN; stdcall;
|
||
var
|
||
DXThreadRecord:PDXThreadRecord;
|
||
Results:String;
|
||
|
||
begin // HTTPODBC.DLL calls with HSE_REQ=61442 (wtf?)
|
||
Result:=False;
|
||
Results:='';
|
||
DXThreadRecord:=FindThread(ThreadID);
|
||
If Not Assigned(DXThreadRecord) then Exit;
|
||
Case HSE_REQ of
|
||
HSE_APPEND_LOG_PARAMETER:Begin
|
||
Move(PChar(Buf),DXThreadRecord^.ECB.lpszLogData,StrLen(PChar(Buf)));
|
||
Result:=False;
|
||
End;
|
||
HSE_REQ_ABORTIVE_CLOSE,
|
||
HSE_REQ_CLOSE_CONNECTION:Begin
|
||
DXThreadRecord^.Thread.Socket.CloseNow;
|
||
Result:=True;
|
||
End;
|
||
HSE_REQ_IS_KEEP_CONN:Begin
|
||
Boolean(Buf^):=False; // when I get keep alive for ISAPI working set this to true
|
||
Result:=True;
|
||
End;
|
||
HSE_REQ_MAP_URL_TO_PATH:
|
||
Begin
|
||
Results := DXThreadRecord^.fRealPath+StringReplace(String(PChar(Buf)), '/', '\', [rfReplaceAll]);
|
||
Results := StringReplace(Results,'\\','\',[rfReplaceAll]);
|
||
LongWord(Size^):=Length(Results); // 9/11/2002
|
||
Buf:=PChar(Results);
|
||
with DXThreadRecord^.mapex do Begin
|
||
StrPCopy(lpszPath, Results);
|
||
dwFlags:=1+2+4; //READ+WRITE+EXECUTE
|
||
cchMatchingPath:=StrLen(lpszPath);
|
||
cchMatchingURL:=StrLen(lpszPath);
|
||
dwReserved1:=0;
|
||
dwReserved2:=0;
|
||
End;
|
||
Move(DXThreadRecord^.Mapex,DataType^,Sizeof(DXThreadRecord^.Mapex));
|
||
NotificationFilters(SF_NOTIFY_URL_MAP, Buf, Longword(Size), @Results, Length(Results));
|
||
Result:=True;
|
||
End;
|
||
HSE_REQ_MAP_URL_TO_PATH_EX:
|
||
Begin
|
||
Results := DXThreadRecord^.fRealPath+StringReplace(String(PChar(Buf)), '/', '\', [rfReplaceAll]);
|
||
Results := StringReplace(Results,'\\','\',[rfReplaceAll]);
|
||
with DXThreadRecord^.mapex do Begin
|
||
StrPCopy(lpszPath,Results);
|
||
dwFlags:=1+2+4; //READ+WRITE+EXECUTE
|
||
cchMatchingPath:=StrLen(lpszPath);
|
||
cchMatchingURL:=StrLen(lpszPath);
|
||
dwReserved1:=0;
|
||
dwReserved2:=0;
|
||
End;
|
||
Move(DXThreadRecord^.Mapex,DataType^,Sizeof(DXThreadRecord^.Mapex));
|
||
NotificationFilters(SF_NOTIFY_URL_MAP, Buf, Longword(Size), @Results, Length(Results));
|
||
Result:=True;
|
||
End;
|
||
HSE_REQ_SEND_URL_REDIRECT_RESP,
|
||
HSE_REQ_SEND_URL:Begin
|
||
If Assigned(DXThreadRecord^.fRedirectHeader) then
|
||
DXThreadRecord^.fRedirectHeader(
|
||
DXThreadRecord^.Thread,
|
||
StrPas(PChar(Buf)),Results)
|
||
Else Results:='HTTP/1.1 302 Moved Temporarily'+#13#10+'Location: '+StrPas(PChar(Buf))+#13#10;
|
||
DXThreadRecord^.Thread.Socket.Writeln(Results);
|
||
Result:=True;
|
||
End;
|
||
HSE_REQ_SEND_RESPONSE_HEADER:Begin
|
||
Result := True;
|
||
Results:='';
|
||
If Assigned(Buf) then begin
|
||
If PChar(Buf)<>'' then Begin
|
||
Results:='HTTP/1.1 '+PChar(Buf)+#13#10;
|
||
End;
|
||
End;
|
||
If Results='' then Begin
|
||
If Assigned(DXThreadRecord^.fBuildHeader) then
|
||
DXThreadRecord^.fBuildHeader(DXThreadRecord^.ECB.dwHttpStatusCode,Results)
|
||
Else Begin
|
||
Results:='HTTP/1.1 200 OK'+#13#10;
|
||
End;
|
||
End;
|
||
If Assigned(DataType) then begin
|
||
Results:=Results+PChar(DataType);
|
||
End;
|
||
If Copy(Results,Length(Results)-1,2)<>#13#10 then
|
||
Results:=Results+#13#10;
|
||
{// 5-11-2002
|
||
If Copy(Results,Length(Results)-3,4)<>#13#10#13#10 then
|
||
DXThreadRecord^.Thread.Socket.Writeln(Results)}
|
||
|
||
// 5-11-2002
|
||
If (Copy(Results,Length(Results)-3,4)<>#13#10#13#10) and
|
||
(Copy(Results,Length(Results)-1,2)<>#10#10) and //10-3-2002
|
||
(Copy(Results,Length(Results)-1,2)<>#13#13) then Begin //10-3-2002
|
||
// 10-3-2002
|
||
If PChar(Buf)<>'' then DXThreadRecord^.Thread.Socket.Writeln(Results)
|
||
Else DXThreadRecord^.Thread.Socket.Write(Results);
|
||
End
|
||
Else
|
||
DXThreadRecord^.Thread.Socket.Write(Results)
|
||
End;
|
||
HSE_REQ_SEND_RESPONSE_HEADER_EX:Begin
|
||
Results:='';
|
||
If Assigned(DXThreadRecord^.fBuildHeader) then
|
||
DXThreadRecord^.fBuildHeader(DXThreadRecord^.ECB.dwHttpStatusCode,Results)
|
||
Else Begin
|
||
If PHSE_SEND_HEADER_EX_INFO(Buf)^.cchStatus>0 then
|
||
Results:='HTTP/1.1 '+PChar(PHSE_SEND_HEADER_EX_INFO(Buf)^.pszStatus)+#13#10
|
||
Else
|
||
Results:='HTTP/1.1 200 OK'+#13#10;
|
||
End;
|
||
If PHSE_SEND_HEADER_EX_INFO(Buf)^.cchHeader=0 then Results:=Results+#13#10
|
||
Else Results:=Results+PHSE_SEND_HEADER_EX_INFO(Buf)^.pszHeader;
|
||
// redesign
|
||
NotificationFilters(SF_NOTIFY_SEND_RESPONSE, @Results, 0, Nil, 0);
|
||
DXThreadRecord^.Thread.Socket.Write(Results);
|
||
Result:=True;
|
||
End;
|
||
HSE_REQ_TRANSMIT_FILE:Begin
|
||
Result:=False;
|
||
// ?
|
||
//if access denied to call
|
||
//NotificationFilters(SF_NOTIFY_ACCESS_DENIED, Pointer1, SF_DENIED_RESOURCE, Pointer2, 0);
|
||
//This: Pointer1 - Requesting URL,
|
||
// Pointer2 - Physical path of resource
|
||
End;
|
||
HSE_REQ_DONE_WITH_SESSION:Begin
|
||
DXThreadRecord^.fISAPIThreadPoolDone:=True;
|
||
Result:=True;
|
||
End;
|
||
HSE_REQ_GET_SSPI_INFO:Begin
|
||
Result:=False;
|
||
End;
|
||
HSE_REQ_IO_COMPLETION:Begin
|
||
Result:=False;
|
||
End;
|
||
HSE_REQ_REFRESH_ISAPI_ACL:Begin
|
||
Result:=False;
|
||
End;
|
||
HSE_REQ_ASYNC_READ_CLIENT:Begin
|
||
Result:=True;
|
||
End;
|
||
{ do not know there values!
|
||
HSE_REQ_EXECUTE_CHILD:Begin // ISAPI 5.1
|
||
Result:=False;
|
||
End;
|
||
HSE_REQ_GET_EXECUTE_FLAGS:Begin // ISAPI 5.1
|
||
Reslut:=True;
|
||
Move(HSE_EXEC_CUSTOM_ERROR,DataType,Sizeof(HSE_EXEC_CUSTOM_ERROR));
|
||
End;
|
||
}
|
||
HSE_REQ_GET_IMPERSONATION_TOKEN:Begin
|
||
Result:=False;
|
||
{$IFNDEF LINUX}
|
||
If Assigned(Buf) then Begin
|
||
Result:=OpenThreadToken(HCONN(DXThreadRecord^.Thread), TOKEN_ALL_ACCESS, False, THandle(DXThreadRecord^.fToken));
|
||
if Result then Buf:=@DXThreadRecord^.fToken;
|
||
End;
|
||
{$ENDIF}
|
||
End;
|
||
HSE_REQ_GET_CERT_INFO_EX:Begin
|
||
Result:=False;
|
||
// fCertificate:=TCERT_CONTEXT_EX(Buf);
|
||
End;
|
||
|
||
End;
|
||
end;
|
||
{$HINTS ON}
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// LOG INFORMATION
|
||
// Use to write log information of transaction request and response.
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
function WriteTransactionToLog(LogStr:String; Size:Longword):BOOLEAN;
|
||
Begin
|
||
NotificationFilters(SF_NOTIFY_LOG, PChar(LogStr), Size, Nil, 0);
|
||
Result:=True;
|
||
End;
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// Find and Load DLL instance
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
Function TDXISAPI.RegisterDLL(ISAPI:String):Boolean;
|
||
Begin
|
||
{$IFDEF USE_DLL_MGR}
|
||
Result:=fDLLManager.LoadThisDLL(ISAPI);
|
||
{$ELSE}
|
||
Result:=True;
|
||
{$ENDIF}
|
||
End;
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// Find and Un-Load DLL instance
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
Function TDXISAPI.UnRegisterDLL(ISAPI:String):Boolean;
|
||
Begin
|
||
{$IFDEF USE_DLL_MGR}
|
||
Result:=fDLLManager.UnLoadThisDLL(ISAPI);
|
||
{$ELSE}
|
||
Result:=True;
|
||
{$ENDIF}
|
||
End;
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// LAUNCH THE DLL!
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
Function TDXISAPI.Execute(Session:TDXClientThread;
|
||
ISAPI,
|
||
Method,
|
||
QueryString,
|
||
PathInfo,
|
||
PathTranslated,
|
||
POSTContent_Type,
|
||
POSTData:String;
|
||
POSTDataSize:Integer;
|
||
Var ResultLog:String):Boolean;
|
||
Var
|
||
DXThreadRecord:PDXThreadRecord;
|
||
Version:TGetExtensionVersion;
|
||
Proc:THttpExtensionProc;
|
||
AllDone:TTerminateExtension;
|
||
Loop:Integer;
|
||
DLLHandle:THandle;
|
||
ProcResults:Longword;
|
||
Err:PChar;
|
||
EVI:THSE_VERSION_INFO;
|
||
StartTime:Cardinal; // 3.0.b
|
||
|
||
Begin
|
||
Result:=False;
|
||
{$IFDEF USE_DLL_MGR}
|
||
DLLHandle:=fDLLManager.GetDLLHandle(ISAPI);
|
||
{$ELSE}
|
||
{$IFDEF LINUX}
|
||
DLLHandle:=LoadLibrary(PChar(ISAPI));
|
||
{$ELSE}
|
||
DLLHandle:=LoadLibraryEx(PChar(ISAPI),0,0);
|
||
{$ENDIF}
|
||
{$ENDIF}
|
||
If DLLHandle=0 then Begin
|
||
GetMem(Err,256);
|
||
{$IFNDEF LINUX}
|
||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,nil,GetLastError,0,Err,256,Nil);
|
||
{$ENDIF}
|
||
ResultLog:=ISAPI+' was not registered! ('+Err+')';
|
||
FreeMem(Err,256);
|
||
{$IFNDEF USE_DLL_MGR}
|
||
FreeLibrary(DLLHandle);
|
||
{$ENDIF}
|
||
Exit;
|
||
End;
|
||
@Version:=GetProcAddress(DLLHandle,PChar('GetExtensionVersion'));
|
||
If Not Assigned(Version) then Begin
|
||
ResultLog:=ISAPI+' does not export "GetExtensionVersion"';
|
||
{$IFNDEF USE_DLL_MGR}
|
||
FreeLibrary(DLLHandle);
|
||
{$ENDIF}
|
||
Exit;
|
||
End;
|
||
@Proc:=GetProcAddress(DLLHandle,PChar('HttpExtensionProc'));
|
||
If Not Assigned(Proc) then Begin
|
||
ResultLog:=ISAPI+' does not export "HTTPExtensionProc"';
|
||
{$IFNDEF USE_DLL_MGR}
|
||
FreeLibrary(DLLHandle);
|
||
{$ENDIF}
|
||
Exit;
|
||
End;
|
||
|
||
New(DXThreadRecord);
|
||
With DXThreadRecord^ do Begin
|
||
ThreadID:=GetCurrentThreadID;
|
||
Thread:=Session;
|
||
fToken:=0;
|
||
fDopHeaders:='';
|
||
fDopDeniedHeaders:='';
|
||
fGetServerVariable:=self.fGetServerVariable;
|
||
fRedirectHeader:=self.fRedirectHeader;
|
||
fBuildHeader:=self.fBuildHeader;
|
||
fRealPath:=ExtractFilePath(PathTranslated);
|
||
fiTimeout:=fTimeout;
|
||
fISAPIThreadPoolDone:=False;
|
||
End;
|
||
If Assigned(Version) then Begin
|
||
FillChar(EVI,Sizeof(EVI),#0);
|
||
If Not Version(EVI) then Begin
|
||
Dispose(DXThreadRecord);
|
||
ResultLog:=ISAPI+' Version Hook Refused';
|
||
{$IFNDEF USE_DLL_MGR}
|
||
FreeLibrary(DLLHandle);
|
||
{$ENDIF}
|
||
Exit;
|
||
End
|
||
Else ResultLog:=EVI.lpszExtensionDesc;
|
||
End;
|
||
|
||
With DXThreadRecord^.ECB do Begin
|
||
cbSize:=sizeof(TEXTENSION_CONTROL_BLOCK);
|
||
dwVersion:=HSE_VERSION_MAJOR shl 16 + HSE_VERSION_MINOR;
|
||
ConnID:=DXThreadRecord^.ThreadID;
|
||
dwHttpStatusCode:=200;
|
||
FillChar(lpszLogData,HSE_LOG_BUFFER_LEN,#0);
|
||
lpszMethod:=PChar(Method);
|
||
lpszQueryString:=PChar(QueryString);
|
||
lpszPathInfo:=PChar(PathInfo);
|
||
lpszPathTranslated:=PChar(PathTranslated);
|
||
cbAvailable:=Length(PostData);
|
||
lpbData:=PChar(PostData);
|
||
cbTotalBytes:=POSTDataSize;
|
||
lpszContentType:=PChar(PostContent_Type);
|
||
GetServerVariable:=ServerVariable;
|
||
ServerSupportFunction:=ServerSupportFunctionS;
|
||
WriteClient:=ExtensionWriteClient;
|
||
ReadClient:=ExtensionReadClient;
|
||
End;
|
||
|
||
MyCriticalSection.StartingWrite;
|
||
fDXThreadArray.Add(DXThreadRecord);
|
||
MyCriticalSection.FinishedWrite;
|
||
try
|
||
ProcResults:=Proc(DXThreadRecord^.ECB);
|
||
Result:=True;
|
||
Case ProcResults of
|
||
HSE_STATUS_SUCCESS,
|
||
HSE_STATUS_SUCCESS_AND_KEEP_CONN:Begin
|
||
ResultLog:=ResultLog+' success: '+StrPas(DXThreadRecord^.ECB.lpszLogData);
|
||
End;
|
||
HSE_STATUS_PENDING:Begin
|
||
// we must loop here and wait for ISAPIThreadPool to finish.
|
||
// 3.0.b
|
||
StartTime:=TimeCounter; // 9/11/2002 moved down here.
|
||
While (Not DXThreadRecord^.fISAPIThreadPoolDone) and (TimeCounter<StartTime+30000) do Begin
|
||
DoSleepEx(1);
|
||
End;
|
||
End;
|
||
HSE_STATUS_ERROR:Begin
|
||
ResultLog:=ResultLog+' failed: '+StrPas(DXThreadRecord^.ECB.lpszLogData);
|
||
Result:=False;
|
||
NotificationFilters(SF_NOTIFY_ACCESS_DENIED, PChar(ISAPI), SF_DENIED_APPLICATION, PChar(PathTranslated), 0);
|
||
End;
|
||
else Begin
|
||
ResultLog:=ResultLog+' returned unknown status '+
|
||
StrPas(DXThreadRecord^.ECB.lpszLogData);
|
||
Result:=False;
|
||
End; //else
|
||
End; //case
|
||
except
|
||
on E: Exception do Begin
|
||
ResultLog:=ISAPI+' failed: '+E.Message;
|
||
Result:=False;
|
||
End;
|
||
end;
|
||
NotificationFilters(SF_NOTIFY_END_OF_REQUEST, Nil, 0, Nil, 0); //END Request
|
||
@AllDone:=GetProcAddress(DLLHandle,PCHar('TerminateExtension'));
|
||
If Assigned(AllDone) then AllDone(HSE_TERM_MUST_UNLOAD);
|
||
{$IFNDEF USE_DLL_MGR}
|
||
FreeLibrary(DLLHandle);
|
||
{$ENDIF}
|
||
WriteTransactionToLog('',0);
|
||
Loop:=0;
|
||
MyCriticalSection.StartingRead;
|
||
While (Loop<fDXThreadArray.Count) do Begin
|
||
DXThreadRecord:=fDXThreadArray[Loop];
|
||
If dword(DXThreadRecord^.ThreadID)=getCurrentThreadID then Begin
|
||
// closing token if he is exist
|
||
MyCriticalSection.FinishedRead;
|
||
MyCriticalSection.StartingWrite;
|
||
{$IFNDEF LINUX}
|
||
If DXThreadRecord^.fToken<>0 then
|
||
CloseHandle(DXThreadRecord^.fToken);
|
||
{$ENDIF}
|
||
Dispose(DXThreadRecord);
|
||
fDXThreadArray.Delete(Loop);
|
||
MyCriticalSection.FinishedWrite;
|
||
Exit;
|
||
End
|
||
Else Inc(Loop);
|
||
End;
|
||
MyCriticalSection.FinishedRead;
|
||
End;
|
||
|
||
function SortFilterCompare(Item1, Item2: Pointer): Integer;
|
||
var fv1, fv2 : PHTTP_FILTER_VERSION;
|
||
Begin
|
||
fv1:=PDXFilterRecord(Item1).fVersion;
|
||
fv2:=PDXFilterRecord(Item2).fVersion;
|
||
Result:= (fv1.dwFlags AND SF_NOTIFY_ORDER_MASK) -
|
||
(fv2.dwFlags AND SF_NOTIFY_ORDER_MASK);
|
||
End;
|
||
|
||
Procedure TDXISAPI.RegisterFilters(var ResultLog:String);
|
||
var DXFilterRecord:PDXFilterRecord;
|
||
filterVersion:THTTP_FILTER_VERSION;
|
||
i:Integer;
|
||
DLLHandle:THandle;
|
||
ISAPI:String;
|
||
Version:TGetFilterVersion;
|
||
Begin
|
||
for i:=0 to fFilter.Count-1 do Begin
|
||
DXFilterRecord:=fFilter.Items[i];
|
||
ISAPI:=DXFilterRecord.fName;
|
||
RegisterDLL(ISAPI);
|
||
{$IFDEF USE_DLL_MGR}
|
||
DLLHandle:=fDLLManager.GetDLLHandle(ISAPI);
|
||
{$ELSE}
|
||
{$IFDEF LINUX}
|
||
DLLHandle:=LoadLibrary(PChar(ISAPI));
|
||
{$ELSE}
|
||
DLLHandle:=LoadLibraryEx(PChar(ISAPI),0,0);
|
||
{$ENDIF}
|
||
{$ENDIF}
|
||
If DLLHandle=0 then Begin
|
||
ResultLog:=ISAPI+' was not registered!';
|
||
Continue;
|
||
End;
|
||
|
||
@Version:=GetProcAddress(DLLHandle,PChar('GetFilterVersion'));
|
||
If Not Assigned(Version) then Begin
|
||
ResultLog:=ISAPI+' does not export "GetFilterVersion"';
|
||
RemoveFilter(ISAPI);
|
||
Exit;
|
||
End;
|
||
|
||
DXFilterRecord.fNotification:=Version(filterVersion);
|
||
DXFilterRecord.fVersion^:=filterVersion;
|
||
End;
|
||
|
||
fFilter.Sort(SortFilterCompare);
|
||
End;
|
||
|
||
Procedure TDXISAPI.UnRegisterFilters(var ResultLog:String);
|
||
var DXFilterRecord:PDXFilterRecord;
|
||
i:Integer;
|
||
DLLHandle:THandle;
|
||
Term:TTerminateFilter;
|
||
Begin
|
||
for i:=0 to fFilter.Count-1 do Begin
|
||
DXFilterRecord:=fFilter.Items[i];
|
||
{$IFDEF USE_DLL_MGR}
|
||
DLLHandle:=fDLLManager.GetDLLHandle(DXFilterRecord.fName);
|
||
{$ELSE}
|
||
{$IFDEF LINUX}
|
||
DLLHandle:=LoadLibrary(PChar(DXFilterRecord.fName));
|
||
{$ELSE}
|
||
DLLHandle:=LoadLibraryEx(PChar(DXFilterRecord.fName),0,0);
|
||
{$ENDIF}
|
||
{$ENDIF}
|
||
If DLLHandle=0 then Begin
|
||
ResultLog:=DXFilterRecord.fName+' was not registered!';
|
||
Continue;
|
||
End;
|
||
|
||
@Term:=GetProcAddress(DLLHandle,PChar('TerminateFilter'));
|
||
If Not Assigned(Term) then
|
||
Continue;
|
||
|
||
Term(0);
|
||
{$IFDEF USE_DLL_MGR}
|
||
fDLLManager.UnLoadThisDLL(DXFilterRecord.fName);
|
||
{$ELSE}
|
||
FreeLibrary(DLLHandle);
|
||
{$ENDIF}
|
||
End;
|
||
End;
|
||
|
||
Function TDXISAPI.AddFilter(ISAPI:String):Boolean;
|
||
var DXFilterRecord:PDXFilterRecord;
|
||
filterVersion:PHTTP_FILTER_VERSION;
|
||
Begin
|
||
Result:=False;
|
||
New(DXFilterRecord);
|
||
New(filterVersion);
|
||
DXFilterRecord.fName:=ISAPI;
|
||
with filterVersion^ do
|
||
Begin
|
||
dwServerFilterVersion:=HTTP_FILTER_REVISION;
|
||
dwFilterVersion:=0;
|
||
lpszFilterDesc:='';
|
||
dwFlags:=0;
|
||
End;
|
||
DXFilterRecord.fVersion := filterVersion;
|
||
DXFilterRecord.fNotification := True;
|
||
DXFilterRecord.fDisableNotification := 0;
|
||
DXFilterRecord.fNextReadSize := 16*1024; //16Kb
|
||
if (fFilter.Add(DXFilterRecord) >= 0) then Result:=True
|
||
else Begin
|
||
Dispose(filterVersion);
|
||
Dispose(DXFilterRecord);
|
||
End;
|
||
End;
|
||
|
||
Function TDXISAPI.RemoveFilter(ISAPI:String):Boolean;
|
||
var DXFilterRecord:PDXFilterRecord;
|
||
HTTP_FILTER_VERSION:PHTTP_FILTER_VERSION;
|
||
i : Integer;
|
||
Begin
|
||
Result:=False;
|
||
MyCriticalSection.StartingWrite;
|
||
for i:=0 to fFilter.Count-1 do
|
||
Begin
|
||
DXFilterRecord:=fFilter.Items[i];
|
||
if DXFilterRecord.fName = ISAPI then
|
||
Begin
|
||
HTTP_FILTER_VERSION:=DXFilterRecord.fVersion;
|
||
Dispose(HTTP_FILTER_VERSION);
|
||
Dispose(DXFilterRecord);
|
||
fFilter.Delete(i);
|
||
Result:=True;
|
||
MyCriticalSection.FinishedWrite;
|
||
Exit;
|
||
End;
|
||
End;
|
||
MyCriticalSection.FinishedRead;
|
||
End;
|
||
|
||
Procedure TDXISAPI.ServerStartEvent;
|
||
var
|
||
res:String;
|
||
Begin
|
||
RegisterFilters(res);
|
||
End;
|
||
|
||
Procedure TDXISAPI.ServerStopEvent;
|
||
var
|
||
res:String;
|
||
Begin
|
||
self.UnRegisterFilters(res);
|
||
End;
|
||
|
||
Procedure TDXISAPI.ServerRawRead(ReadString:String;Len:Longword);
|
||
Begin
|
||
NotificationFilters(SF_NOTIFY_READ_RAW_DATA, @ReadString, Len, Nil, 0);
|
||
End;
|
||
|
||
Procedure TDXISAPI.ServerPreprocHeaderEvent(DXHeaderInfo:PHeaderInfo);
|
||
Begin
|
||
NotificationFilters(SF_NOTIFY_PREPROC_HEADERS, DXHeaderInfo, 0, Nil, 0);
|
||
End;
|
||
|
||
Procedure TDXISAPI.ConvertedURL2Physical(URL:String;Physical:String);
|
||
Begin
|
||
NotificationFilters(SF_NOTIFY_URL_MAP,@URL,Length(URL),@Physical,Length(Physical));
|
||
End;
|
||
|
||
Procedure TDXISAPI.ServerEndOfRequest;
|
||
Begin
|
||
NotificationFilters(SF_NOTIFY_END_OF_REQUEST, Nil, 0, Nil, 0);
|
||
End;
|
||
|
||
Procedure TDXISAPI.ServerEndSession;
|
||
Begin
|
||
NotificationFilters(SF_NOTIFY_END_OF_NET_SESSION, Nil, 0, Nil, 0);
|
||
End;
|
||
|
||
Procedure TDXISAPI.SetServerVariableProc(value:TFilterGetServerVariableProc);
|
||
Begin
|
||
fGetServerVariableFilterProc:=value;
|
||
End;
|
||
|
||
Function TDXISAPI.GetServerVariableProc:TFilterGetServerVariableProc;
|
||
Begin
|
||
Result := fGetServerVariableFilterProc;
|
||
End;
|
||
|
||
Function TDXISAPI.FilterCount:Integer;
|
||
Begin
|
||
Result:=fFilter.Count;
|
||
End;
|
||
|
||
{$IFDEF SUPPORT_COM}
|
||
initialization
|
||
CoInitializeEx(nil,COINIT_MULTITHREADED);
|
||
finalization
|
||
CoUninitialize;
|
||
{$ENDIF}
|
||
|
||
end.
|
||
|