Componentes.Terceros.RemObj.../internal/5.0.23.613/1/RemObjects SDK for Delphi/Source/RODX/uRODXISAPI.pas
david 2824855ea7 - Modificación del paquete RemObjects_Core_D10 para que sea un paquete de runtime/designtime (antes era designtime sólo)
- 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
2007-09-10 14:06:19 +00:00

1633 lines
59 KiB
ObjectPascal
Raw Blame History

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.