windows-nt/Source/XPSP1/NT/inetsrv/iis/iisrearc/iisplus/ssinc/ssinc.hxx
2020-09-26 16:20:57 +08:00

875 lines
18 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
ssinc.hxx
Abstract:
This module contains the server side include processing code. We
aim for support as specified by iis\spec\ssi.doc. The code is based
on existing SSI support done in iis\svcs\w3\gateways\ssinc\ssinc.cxx.
Author:
Ming Lu (MingLu) 5-Apr-2000
--*/
#ifndef SSINC_HXX_INCLUDED
#define SSINC_HXX_INCLUDED
/************************************************************
* Macros
************************************************************/
//
// General Constants
//
#define SSI_MAX_PATH 1024
#define SSI_MAX_ERROR_MESSAGE 512
#define SSI_MAX_TIME_SIZE 256
#define SSI_MAX_NUMBER_STRING 32
#define SSI_INIT_VARIABLE_OUTPUT_SIZE 64
#define SSI_MAX_NESTED_INCLUDES 255
#define SSI_MAX_FORMAT_LEN 1024
#define SSI_HEADER "Content-Type: text/html\r\n\r\n"
#define SSI_ACCESS_DENIED "401 Authentication Required"
#define SSI_OBJECT_NOT_FOUND "404 Object Not Found"
#define SSI_DLL_NAME L"ssinc.dll"
//
// Default values for #CONFIG options
//
#define SSI_DEF_ERRMSG ""
#define SSI_DEF_ERRMSG_LEN sizeof( SSI_DEF_ERRMSG )
#define SSI_MAX_ERRMSG 256
#define SSI_DEF_TIMEFMT "%A %B %d %Y"
#define SSI_DEF_TIMEFMT_LEN sizeof( SSI_DEF_TIMEFMT )
#define SSI_MAX_TIMEFMT 256
#define SSI_DEF_SIZEFMT FALSE
//
// Specific lvalues for #CONFIG SIZEFMT and #CONFIG CMDECHO
//
#define SSI_DEF_BYTES "bytes"
#define SSI_DEF_BYTES_LEN sizeof( SSI_DEF_BYTES )
#define SSI_DEF_ABBREV "abbrev"
#define SSI_DEF_ABBREV_LEN sizeof( SSI_DEF_ABBREV )
//
// Other cache/signature constants
//
#define SIGNATURE_SEI 0x20494553
#define SIGNATURE_SEL 0x204C4553
#define SIGNATURE_SEI_FREE 0x66494553
#define SIGNATURE_SEL_FREE 0x664C4553
#define W3_PARAMETERS_KEY \
L"System\\CurrentControlSet\\Services\\w3svc\\Parameters"
//
// These are available SSI commands
//
enum SSI_COMMANDS
{
SSI_CMD_INCLUDE = 0,
SSI_CMD_ECHO,
SSI_CMD_FSIZE, // File size of specified file
SSI_CMD_FLASTMOD, // Last modified date of specified file
SSI_CMD_CONFIG, // Configure options
SSI_CMD_EXEC, // Execute CGI or CMD script
SSI_CMD_BYTERANGE, // Custom commands, not defined by NCSA
SSI_CMD_UNKNOWN
};
//
// These tags are essentially subcommands for the various SSI_COMMAND
// values
//
enum SSI_TAGS
{
SSI_TAG_FILE, // Used with include, fsize & flastmod
SSI_TAG_VIRTUAL,
SSI_TAG_VAR, // Used with echo
SSI_TAG_CMD, // Used with Exec
SSI_TAG_CGI,
SSI_TAG_ISA,
SSI_TAG_ERRMSG, // Used with Config
SSI_TAG_TIMEFMT,
SSI_TAG_SIZEFMT,
SSI_TAG_UNKNOWN
};
//
// Variables available to #ECHO VAR = "xxx" but not available in ISAPI
//
enum SSI_VARS
{
SSI_VAR_DOCUMENT_NAME = 0,
SSI_VAR_DOCUMENT_URI,
SSI_VAR_QUERY_STRING_UNESCAPED,
SSI_VAR_DATE_LOCAL,
SSI_VAR_DATE_GMT,
SSI_VAR_LAST_MODIFIED,
SSI_VAR_UNKNOWN
};
//
// SSI Exec types
//
enum SSI_EXEC_TYPE
{
SSI_EXEC_CMD = 1,
SSI_EXEC_CGI = 2,
SSI_EXEC_ISA = 4,
SSI_EXEC_UNKNOWN
};
//
// States of asynchronous SSI_INCLUDE_FILE processing
//
enum SIF_STATE
{
SIF_STATE_UNINITIALIZED,
SIF_STATE_INITIALIZED,
SIF_STATE_READY,
SIF_STATE_EXEC_CHILD_PENDING,
SIF_STATE_INCLUDE_CHILD_PENDING,
SIF_STATE_PROCESSING,
SIF_STATE_COMPLETED,
SIF_STATE_UNKNOWN
};
class SSI_INCLUDE_FILE;
class SSI_ELEMENT_LIST;
class SSI_ELEMENT_ITEM;
/************************************************************
* Structure and Class declarations
************************************************************/
/*++
class SSI_REQUEST
Master structure for SSI request.
Provides a "library" of utilities for use by higher level functions
Hierarchy:
SSI_REQUEST
- SSI_INCLUDE_FILE
- SSI_ELEMENT_LIST
- SSI_ELEMENT_ITEM
--*/
class SSI_REQUEST
{
private:
EXTENSION_CONTROL_BLOCK * _pECB;
STRU _strFilename;
STRU _strURL;
STRA _strUserMessage;
BOOL _fBaseFile;
HANDLE _hUser;
BOOL _fValid;
// Current include file (multiple stm files may be nested)
SSI_INCLUDE_FILE * _pSIF;
// Buffers used for async writes must stay around
LPSTR _pchErrorBuff;
CHAR _achTimeBuffer[ SSI_MAX_TIME_SIZE + 1 ];
DWORD _cbTimeBufferLen;
BUFFER _IOBuffer;
STRA _IOString;
// buffer length variable (to be used for async I/O)
DWORD _cbIOLen;
// Handle to file cache
W3_FILE_INFO_CACHE * _pFileCache;
// Lookaside
static ALLOC_CACHE_HANDLER * sm_pachSSIRequests;
public:
SSI_REQUEST( EXTENSION_CONTROL_BLOCK * pECB );
~SSI_REQUEST();
VOID *
operator new(
size_t size
)
{
DBG_ASSERT( size == sizeof( SSI_REQUEST ) );
DBG_ASSERT( sm_pachSSIRequests != NULL );
return sm_pachSSIRequests->Alloc();
}
VOID
operator delete(
VOID * pSSIRequest
)
{
DBG_ASSERT( pSSIRequest != NULL );
DBG_ASSERT( sm_pachSSIRequests != NULL );
DBG_REQUIRE( sm_pachSSIRequests->Free( pSSIRequest ) );
}
static
HRESULT
Initialize(
VOID
)
/*++
Routine Description:
Global initialization routine for SSI_REQUEST
Arguments:
None
Return Value:
HRESULT
--*/
{
ALLOC_CACHE_CONFIGURATION acConfig;
HRESULT hr = NO_ERROR;
//
// Setup allocation lookaside
//
acConfig.nConcurrency = 1;
acConfig.nThreshold = 100;
acConfig.cbSize = sizeof( SSI_REQUEST );
DBG_ASSERT( sm_pachSSIRequests == NULL );
sm_pachSSIRequests = new ALLOC_CACHE_HANDLER( "SSI_REQUEST",
&acConfig );
if ( sm_pachSSIRequests == NULL )
{
return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
}
return NO_ERROR;
}
static
VOID
Terminate(
VOID
)
/*++
Routine Description:
Terminate SSI_REQUEST globals
Arguments:
None
Return Value:
None
--*/
{
if ( sm_pachSSIRequests != NULL )
{
delete sm_pachSSIRequests;
sm_pachSSIRequests = NULL;
}
}
BOOL
IsValid(
VOID
) const
{
return _fValid;
}
BOOL
SetCurrentIncludeFile(
SSI_INCLUDE_FILE * pSIF
)
{
_pSIF = pSIF;
return TRUE;
}
EXTENSION_CONTROL_BLOCK *
GetECB(
VOID
) const
{
return _pECB;
}
HANDLE
GetUserToken(
VOID
)
{
return _hUser;
}
HRESULT
WriteToClient(
IN PVOID pBuffer,
IN DWORD dwBufLen,
OUT PDWORD pdwActualLen
)
/*++
Write to data to client through ISAPI.
If sending a nulltermed string, dwBufLen should be strlen( pBuffer )
--*/
{
BOOL fRet = FALSE;
*pdwActualLen = dwBufLen;
if ( dwBufLen == 0 )
{
//
// If 0 bytes are sent asynchronously
// there will be no completion callback
//
return NO_ERROR;
}
fRet = _pECB->WriteClient( _pECB->ConnID,
pBuffer,
pdwActualLen,
HSE_IO_ASYNC );
if ( fRet )
{
return HRESULT_FROM_WIN32(ERROR_IO_PENDING);
}
else
{
return HRESULT_FROM_WIN32(GetLastError());
}
}
HRESULT
SendResponseHeader(
IN CHAR * pszMessage,
IN CHAR * pszHeaders
)
/*++
Send a response header to client through ISAPI
--*/
{
BOOL fRet = FALSE;
if( _pECB->ServerSupportFunction( _pECB->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER,
pszMessage,
NULL,
( DWORD * ) pszHeaders ) )
{
return NO_ERROR;
}
else
{
return HRESULT_FROM_WIN32(GetLastError());
}
}
HRESULT
GetVariable(
IN LPSTR pszVariableName,
OUT BUFFER * pbuffOutput
)
/*++
Get an ISAPI variable
--*/
{
DWORD dwBufLen = SSI_INIT_VARIABLE_OUTPUT_SIZE;
BOOL fRet;
BOOL fSecondTry = FALSE;
TryAgain:
if ( !pbuffOutput->Resize( dwBufLen ) )
{
return HRESULT_FROM_WIN32(GetLastError());
}
fRet = _pECB->GetServerVariable( _pECB->ConnID,
pszVariableName,
pbuffOutput->QueryPtr(),
&dwBufLen );
if ( fRet )
{
return NO_ERROR;
}
else if ( !fSecondTry &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
fSecondTry = TRUE;
goto TryAgain;
}
else
{
return HRESULT_FROM_WIN32(GetLastError());
}
}
HRESULT
SSISendError(
IN DWORD dwMessageID,
IN LPSTR apszParms[]
);
BOOL
SetUserErrorMessage(
IN STRA * pstrUserMessage
)
{
if( FAILED ( _strUserMessage.Copy(*pstrUserMessage) ) )
{
return FALSE;
}
return TRUE;
}
//BUGBUG OTHER WAYS TO FIND OUT THE METABASE INFO
BOOL
IsExecDisabled(
VOID
) const
{
//return _pReq->QueryMetaData()->SSIExecDisabled();
return FALSE;
}
HRESULT
SendCustomError(
HSE_CUSTOM_ERROR_INFO * pCustomErrorInfo
);
HRESULT
DoFLastMod(
IN STRU *,
IN STRA *,
IN SSI_ELEMENT_LIST *
);
HRESULT
DoFSize(
IN STRU *,
IN BOOL,
IN SSI_ELEMENT_LIST *
);
HRESULT
DoEchoISAPIVariable(
IN STRA *
);
HRESULT
DoEchoDocumentName(
IN STRU *
);
HRESULT
DoEchoDocumentURI(
IN STRU *
);
HRESULT
DoEchoQueryStringUnescaped(
VOID
);
HRESULT
DoEchoDateLocal(
IN STRA *
);
HRESULT
DoEchoDateGMT(
IN STRA *
);
HRESULT
DoEchoLastModified(
IN STRU *,
IN STRA *,
IN SSI_ELEMENT_LIST *
);
HRESULT
SendDate(
IN SYSTEMTIME *,
IN STRA *
);
HRESULT
LookupVirtualRoot(
IN WCHAR * pszVirtual,
OUT STRU * pstrPhysical,
IN DWORD dwAccess
);
HRESULT
DoWork(
DWORD dwError = NO_ERROR
);
HRESULT
PrepareSSI(
VOID
);
static
VOID WINAPI
HseIoCompletion(
IN EXTENSION_CONTROL_BLOCK * pECB,
IN PVOID pContext,
IN DWORD cbIO,
IN DWORD dwError
);
};
/*++
class SSI_INCLUDE_FILE
STM file may include other files. Each include file is represented by SSI_INCLUDE_FILE
--*/
class SSI_INCLUDE_FILE
{
private:
SSI_REQUEST * _pRequest;
// _strFileName - File to send
STRU _strFilename;
// _strURL - URL (from root) of this file
STRU _strURL;
// pParent - Parent SSI include file
SSI_INCLUDE_FILE * _pParent;
SIF_STATE _State;
SSI_ELEMENT_LIST * _pSEL;
LIST_ENTRY * _pCurrentEntry;
BOOL _fSELCached;
BOOL _fFileCached;
W3_FILE_INFO * _pOpenFile;
// Asynchronous child execute info
HSE_EXEC_URL_INFO _ExecUrlInfo;
// Size and time formating info
BOOL _fSizeFmtBytes;
STRA _strTimeFmt;
// Lookaside
static ALLOC_CACHE_HANDLER * sm_pachSSI_IncludeFiles;
public:
SSI_INCLUDE_FILE(
SSI_REQUEST * pRequest,
STRU & strFilename,
STRU & strURL,
SSI_INCLUDE_FILE * pParent
)
: _pRequest( pRequest ),
_pParent( pParent ),
_pSEL( NULL ),
_pCurrentEntry( NULL ),
_fSELCached( FALSE ),
_fFileCached( FALSE ),
_pOpenFile( NULL ),
_fSizeFmtBytes (SSI_DEF_SIZEFMT),
_State( SIF_STATE_UNINITIALIZED )
{
if ( FAILED( _strFilename.Copy( strFilename ) ) )
{
return;
}
if ( FAILED( _strURL.Copy( strURL ) ) )
{
return;
}
if ( FAILED( _strTimeFmt.Resize( sizeof( SSI_DEF_TIMEFMT ) + 1 ) ) )
{
return;
}
strcpy( ( CHAR * )_strTimeFmt.QueryStr(), SSI_DEF_TIMEFMT );
SetState( SIF_STATE_INITIALIZED );
}
~SSI_INCLUDE_FILE( VOID );
VOID *
operator new(
size_t size
)
{
DBG_ASSERT( size == sizeof( SSI_INCLUDE_FILE ) );
DBG_ASSERT( sm_pachSSI_IncludeFiles != NULL );
return sm_pachSSI_IncludeFiles->Alloc();
}
VOID
operator delete(
VOID * pSSI_IncludeFile
)
{
DBG_ASSERT( pSSI_IncludeFile != NULL );
DBG_ASSERT( sm_pachSSI_IncludeFiles != NULL );
DBG_REQUIRE( sm_pachSSI_IncludeFiles->Free( pSSI_IncludeFile ) );
}
static
HRESULT
Initialize(
VOID
)
/*++
Routine Description:
Global initialization routine for SSI_REQUEST
Arguments:
None
Return Value:
HRESULT
--*/
{
ALLOC_CACHE_CONFIGURATION acConfig;
HRESULT hr = NO_ERROR;
//
// Setup allocation lookaside
//
acConfig.nConcurrency = 1;
acConfig.nThreshold = 100;
acConfig.cbSize = sizeof( SSI_INCLUDE_FILE );
DBG_ASSERT( sm_pachSSI_IncludeFiles == NULL );
sm_pachSSI_IncludeFiles = new ALLOC_CACHE_HANDLER( "SSI_INCLUDE_FILE",
&acConfig );
if ( sm_pachSSI_IncludeFiles == NULL )
{
return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
}
return NO_ERROR;
}
static
VOID
Terminate(
VOID
)
/*++
Routine Description:
Terminate SSI_REQUEST globals
Arguments:
None
Return Value:
None
--*/
{
if ( sm_pachSSI_IncludeFiles != NULL )
{
delete sm_pachSSI_IncludeFiles;
sm_pachSSI_IncludeFiles = NULL;
}
}
SSI_INCLUDE_FILE *
GetParent( VOID )
{
return _pParent;
}
LIST_ENTRY *
GetCurrentEntry( VOID )
{
return _pCurrentEntry;
}
BOOL IsCompleted( VOID )
{
return ( _State == SIF_STATE_COMPLETED );
}
BOOL IsValid( VOID )
{
return ( _State != SIF_STATE_UNINITIALIZED );
}
BOOL IsBaseFile( VOID )
{
return ( _pParent == NULL );
}
BOOL IsRecursiveInclude( IN STRU & strFilename )
{
if ( !_wcsicmp( strFilename.QueryStr(),
_strFilename.QueryStr() ) )
{
return TRUE;
}
if ( !_pParent )
{
return FALSE;
}
else
{
return _pParent->IsRecursiveInclude( strFilename );
}
}
VOID
SetState(
SIF_STATE State
)
{
_State = State;
}
HRESULT
Prepare(
VOID
);
HRESULT
BuildSEL(
VOID
);
HRESULT
Process(
VOID
);
HRESULT
DoWork(
DWORD dwError = NO_ERROR
);
HRESULT
GetFullPath(
IN SSI_ELEMENT_ITEM * pSEI,
OUT STRU * pstrPath,
IN DWORD dwPermission,
IN STRU * pstrCurrentURL,
OUT STRU * pstrURL = NULL
);
static
BOOL
ParseSSITag(
IN OUT CHAR * * ppchFilePos,
IN CHAR * pchEOF,
OUT BOOL * pfValidTag,
OUT SSI_COMMANDS * pCommandType,
OUT SSI_TAGS * pTagType,
OUT CHAR * pszTagString
);
static
CHAR *
SSISkipTo(
IN CHAR * pchFilePos,
IN CHAR ch,
IN CHAR * pchEOF
);
static
CHAR *
SSISkipWhite(
IN CHAR * pchFilePos,
IN CHAR * pchEOF
);
static
BOOL
FindInternalVariable(
IN STRA * pstrVariable,
OUT PDWORD pdwID
);
};
#endif