📄 isapiflt.cpp
字号:
/* --- callback functions --- */
GetServerVariable = fnGetServerVariable;
AddResponseHeaders = fnAddResponseHeaders;
WriteClient = fnWriteClient;
AllocMem = fnAllocMem;
ServerSupportFunction = fnServerSupportFunction;
/* --- proprietary data --- */
const char *pContentLength = (const char *)PIDB_lookup(
pPIHTTP->pRequestDB, PIDBTYPE_RFC822, KEY_HTTP_CONTENTLENGTH, 0 );
cbTotalBytes = pContentLength ? atol( pContentLength ) : 0;
fIsSecurePort = (BOOL)PIDB_lookup( pPIHTTP->pConnectionDB,
PIDBTYPE_STRING, KEY_HTTPS_KEYSIZE, 0 );
};
~ISAPIContext()
{
CloseHandle( hToken );
}
};
/*____________________________________________________________________________*\
*
Class:
Description:
\*____________________________________________________________________________*/
class ISAPIFLT : public HandlerBase
{
private:
/* ---
Configuration data
--- */
PIDB *pTypes; /* DB for variable types */
PIFInfo *pFInfo; /* Store DLL file info */
PIDLL *pDLL; /* Store DLL handle */
const char *pPath; /* Store DLL path for error msgs */
Pi3Expression *pCondition; /* Store condition */
HTTP_FILTER_VERSION tVer; /* The server version of ISAPI filter */
PFN_HTTPFILTERPROC fnHttpFilterProc; /* Pointer to the client filter function */
const char *pfkIsapiContext; /* Lookup key for the context pointer */
const char *pFKPath; /* Lookup key for the path */
int iResult; /* Result code for Handler
/* ---
Configuration data
--- */
PIString sExtraHeadersPrefix; /* Extra Header for environment values, */
/* by default "HTTP_" */
int iExtraHeaders; /* whether or not to send extra headers */
DblList lIgnoreHeaders; /* extra headers to ignore */
int iSystemLogon;
FnPi3Write aFunctions[256]; /* callback functions */
int iOptions; /* The options of this handler */
inline int checkIgnoreList(const char *pKey)
{
/* --- exclude the variables in lIgnoreHeaders --- */
const char *pExclude;
for( DblListIterator l( lIgnoreHeaders ); !l.BadIndex(); l++ )
{
pExclude = (const char *)l.Current();
if (!PIUtil_stricmp(pKey, pExclude))
{
return 1;
}
};
return 0;
}
protected:
int Parameter( const char *pVariable, const char *pValue,
const char *pWhere )
{
assert( pVariable && pValue );
PIOStrStream os;
os.flags( os.flags() | ios::hex );
os << pWhere << "ISAPIFLT: ";
if ( !PIUtil_stricmp( KEY_CONF_CONDITION, pVariable ))
{
Pi3String *pError = Pi3String_new( 0 );
pCondition = Pi3Expression_new( pValue, 0, pError );
PIString sError( Pi3String_getPtr( pError ) );
Pi3String_delete( pError );
if ( !pCondition )
{
os << "Syntax error in condition: " << sError << ends;
CONFIG_ERR( Object(), os.str() );
Pi3Expression_delete( pCondition );
return 0;
};
}
else if ( !PIUtil_stricmp( KEY_CONF_EXTRAHDRPREFIX, pVariable ) )
{
sExtraHeadersPrefix = (const char *)DeQuote( pValue );
}
else if ( !PIUtil_stricmp( KEY_CONF_EXTRAHEADERSIGNORE, pVariable ) )
{
StringTokenizer tTokens( (const char *)DeQuote(pValue), " " );
for( int i=0; i<tTokens.NumTokens(); i++)
{
lIgnoreHeaders.Append( (DblList::type)
PI_NEW( PIString( tTokens.GetToken( i ) ) ) );
};
}
else if ( !PIUtil_stricmp( KEY_CONF_EXTRAHEADERS, pVariable ) )
{
if ( !PIUtil_stricmp( VALUE_NO, pValue ) )
{ iExtraHeaders = 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_SYSTEMLOGON, pVariable ) )
{
if ( !PIUtil_stricmp( VALUE_NO, pValue ) )
{ iSystemLogon = 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_VARIABLE, pVariable ) )
{
const char *pK;
const char *pV;
StringTokenizer tTokens( (const char *)DeQuote(pValue), "=" );
if (tTokens.NumTokens() < 2)
{
os << "Invalid Variable '" << pValue <<
"'" << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
}
pK = tTokens.GetToken( 0 );
pV = tTokens.GetToken( 1 );
Pi3String *pError = Pi3String_new( 0 );
Pi3Expression *pExpr = Pi3Expression_new( pV, aFunctions,
pError );
if ( !pExpr )
{
os << Pi3String_getPtr( pError ) << ends;
Pi3String_delete( pError );
CONFIG_ERR( Object(), os.str() );
return 0;
};
Pi3String_delete( pError );
PIDB_add( pTypes, PIDBTYPE_OPAQUE, pK, (void *)pExpr, 0 );
}
else if ( !PIUtil_stricmp( KEY_CONF_TERMINATORS, pVariable ))
{
/* ---
Split the options up by the bar ('|') character and then
strip trailing and leading whitespace from option before
attempting to match it.
--- */
StringTokenizer tTokens( pValue, "|" );
for(int i=0; i<tTokens.NumTokens(); i++)
{
const char *pToken = tTokens.GetToken( i );
/* --- skip leading whitespace --- */
for( ; *pToken && (isspace(*pToken)); pToken++ );
/* ---
include only to first whitespace trailing whitespace
--- */
int j=0;
for( ; pToken[j] && !(isspace(pToken[j])); j++ );
/* ---
j now contains the length of the first word in pToken
--- */
/* ---
cycle through the list of available flags
comparing them with this one
--- */
int i=0;
for( ; aFlagMap[i].pName; i++ )
{
if ( !PIUtil_strncmpi( aFlagMap[i].pName, pToken, j ) )
{ break; };
};
if ( !aFlagMap[i].pName )
{
/* --- flag not found --- */
PIString sTmp( pToken, j );
os << "Unknown option flag '" << sTmp << "'." << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
iOptions |= aFlagMap[i].iFlag;
}; /* --- loop over tokens separated by '|' --- */
}
else if ( !PIUtil_stricmp( KEY_CONF_FLTDLLPATH, pVariable ))
{
PIString sPath( pValue );
HTTPCore_relativeToAbsolutePath(PIObject_getDB( Object() ),
pValue, (int *)&sPath );
pFInfo = HTTPCore_getCachedFile( sPath );
if ( !pFInfo )
{
os << "ISAPI Filter DLL '" << pValue << \
"' does not exist or is not a regular file." << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
/* ---
This file must exist and be a regular file
--- */
if ( !PIFInfo_exists( pFInfo ) || !PIFInfo_isRegular( pFInfo ) )
{
os << "ISAPI Filter DLL '" << pValue << \
"' does not exist or is not a regular file." << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
/* ---
Try to load the ISAPI filter DLL
--- */
strcpy((char *)pPath, sPath );
pDLL = PIDLL_new( pPath );
if ( !PIDLL_isLoaded( pDLL ) )
{
const char *pDesc = PIDLL_getErrorDescription( pDLL );
os << "ISAPI Filter DLL '" << pValue << \
"' could not be loaded, error description is " << pDesc << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
/* ---
Load the GetFilterVersion function from the DLL
--- */
PFN_GETFILTERVERSION fnGetVersion = (PFN_GETFILTERVERSION)
PIDLL_getAddress( pDLL, "GetFilterVersion" );
if ( !fnGetVersion )
{
os << "Could not load function 'GetFilterVersion'" << \
" from ISAPI DLL '" << pPath << "'" << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
/* ---
Do GetFilterVersion
--- */
tVer.dwServerFilterVersion = HTTP_FILTER_REVISION;
if ( !( (fnGetVersion)( &tVer ) ) )
{
os << "Could not execute function 'GetFilterVersion'" << \
" from ISAPI DLL '" << pPath << "'. Win32 Error code is " << \
::GetLastError() << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
}
/* ---
Is the Version of the filter backward compatible to our server module?
--- */
else if ( tVer.dwServerFilterVersion < tVer.dwFilterVersion)
{
os << "Incompatible filter version in ISAPI DLL '" << pPath << \
"'. Server Filter version is " << tVer.dwServerFilterVersion << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
}
/* ---
This server module hasn't support for read/write filter notifications.
If the filter needs this, you couldn't use the filter with Pi3Web
--- */
else if ( !( tVer.dwFlags & ( SF_NOTIFY_READ_RAW_DATA | SF_NOTIFY_SEND_RAW_DATA )))
{
/* ---
Load the filter function
--- */
fnHttpFilterProc = ( PFN_HTTPFILTERPROC )PIDLL_getAddress( pDLL, "HttpFilterProc" );
if ( !fnHttpFilterProc )
{
os << "Could not load 'HttpFilterProc' from ISAPI DLL '" << pPath << "'" << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
}
else
{
os << "Pi3Web doesn't support raw data read/write notification " << \
"requested by ISAPI DLL '" << pPath << "'" << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
}
else
{
os << "Unknown directive '" << pVariable << "'" << ends;
CONFIG_ERR( Object(), os.str() );
return 0;
};
return 1;
};
/* ---
Callback function for Pi3Expression parameter %a
--- */
static int f_a( PIHTTP *pPIHTTP, void *pData, char *pszBuffer, int iLength )
{
(void)pPIHTTP;
ISAPIContext &tData = *( (ISAPIContext *)pData );
assert( pszBuffer );
PIDB *pQ = pPIHTTP->pRequestDB;
int i = 0;
/* --- loop over all RFC822 headers in request block --- */
PIDBIterator *pIter = PIDB_getIterator( pQ, PIDBTYPE_RFC822, 0, 0 );
if ( !pIter ) { return 0; }
const char *pKey;
const char *pValue;
for(; PIDBIterator_atValidElement( pIter ); PIDBIterator_next( pIter ) )
{
pValue = (const char *)PIDBIterator_current( pIter, &pKey );
assert( pKey && pValue );
if ( !pKey || !pValue ) { /* sanity */ continue; };
if (tData.pISAPIFLT->checkIgnoreList(pKey)) continue;
void *fnEnv = PIDB_lookup( tData.pISAPIFLT->pTypes, PIDBTYPE_OPAQUE, pKey, 0 );
if ( fnEnv ) { continue; };
int iVarLen = strlen( pKey );
int iVarPos = tData.pISAPIFLT->sExtraHeadersPrefix.Len();
int iValSize = strlen( pValue );
// keep space for ': \r\n\0'
if ( (i+iVarPos+iVarLen+iValSize+5) < iLength )
{
memcpy( &(pszBuffer[i]), tData.pISAPIFLT->sExtraHeadersPrefix, iVarPos );
i += iVarPos;
for( int j=0; j<iVarLen; j++, i++ )
{
if ( isalnum( pKey[j] ) )
{ pszBuffer[i]=toupper(pKey[j]); }
else
{ pszBuffer[i]='_'; };
};
pszBuffer[i++] = ':';
pszBuffer[i++] = ' ';
memcpy( &(pszBuffer[i]), pValue, iValSize ); i+=iValSize;
pszBuffer[i++] = '\r';
pszBuffer[i++] = '\n';
}
else
{
PIDBIterator_delete( pIter );
::SetLastError( ERROR_INSUFFICIENT_BUFFER );
return 1024;
};
};
PIDBIterator_delete( pIter );
pszBuffer[i] = 0;
return i;
};
/* ---
Callback function for Pi3Expression parameter %l
--- */
static int f_l( PIHTTP *pPIHTTP, void *pData, char *pszBuffer, int iLength )
{
(void)pPIHTTP;
ISAPIContext &tData = *( (ISAPIContext *)pData );
assert( pszBuffer );
*((DWORD *)pszBuffer) = tData.cbTotalBytes;
pszBuffer[sizeof(DWORD)] = 0;
return sizeof(DWORD);
}
public:
ISAPIFLT( PIObject *pObject, int iArgc, const char *ppArgv[] )
: HandlerBase( pObject ),
pTypes( PIDB_new( 0, "Types" ) ),
pFInfo( NULL ),
pDLL( NULL ),
fnHttpFilterProc( NULL ),
pPath( (const char *)PIUtil_malloc( 256 ) ),
pCondition( NULL ),
iOptions( 0 ),
pfkIsapiContext( PIDB_getFastKey( KEY_INT_ISAPICONTEXT, PIDBTYPE_STRING )),
pFKPath( PIDB_getFastKey( KEY_INT_PATH, PIDBTYPE_STRING )),
iResult( PIAPI_CONTINUE ),
iExtraHeaders( 1 ),
iSystemLogon( 1 )
{
/* --- clear out callback functions --- */
memset( aFunctions, 0, sizeof( FnPi3Write ) * 256 );
aFunctions['a'] = f_a;
aFunctions['l'] = f_l;
ReadParameters( iArgc, ppArgv );
};
virtual ~ISAPIFLT()
{
PIDB_delete( pTypes );
for( DblListIterator i( lIgnoreHeaders ); !i.BadIndex(); i++ )
{ PI_DELETE( (PIString *)i.Current() ); };
Pi3Expression_delete( pCondition );
if (pDLL) PIDLL_delete( pDLL );
if (pFInfo) HTTPCore_releaseCachedFile( pFInfo );
PIUtil_free( (void *)pPath );
};
/* ---
The real filter stuff
--- */
int RunISAPI( PIHTTP *pPIHTTP, int iPhase, ISAPIContext *pContext )
{
assert( pPIHTTP && fnHttpFilterProc && pContext);
int iFilterRet = 0;
/* ---
Look what we've to do
--- */
DWORD nType = 0;
LPVOID pvNotification = NULL;
/* ---
Nothing to do: if (non)secure port notification is other
than port characteristics of the connection
--- */
if (( pContext->fIsSecurePort && !( pContext->tVer.dwFlags & SF_NOTIFY_SECURE_PORT ))
|| !( pContext->fIsSecurePort || ( pContext->tVer.dwFlags & SF_NOTIFY_NONSECURE_PORT )))
{
return FALSE;
};
/* ---
Preprocessing headers phase mapped to SF_NOTIFY_PREPROC_HEADERS
--- */
if ( !nType && ( iPhase == PH_HEADERS ) && ( pContext->tVer.dwFlags & SF_NOTIFY_PREPROC_HEADERS ))
{
nType = SF_NOTIFY_PREPROC_HEADERS;
HTTP_FILTER_PREPROC_HEADERS Hdrs;
pvNotification = &Hdrs;
Hdrs.GetHeader = fnGetHeader;
Hdrs.SetHeader = fnSetHeader;
Hdrs.AddHeader = fnAddHeader;
/* ---
Not implemented in filter version 2.1
--- */
// Hdrs.HttpStatus = pPIHTTP->iStatus;
};
/* ---
Mapping phase mapped to SF_NOTIFY_URL_MAP
--- */
if ( !nType && ( iPhase == PH_MAPPING ) && ( pContext->tVer.dwFlags & SF_NOTIFY_URL_MAP ))
{
nType = SF_NOTIFY_URL_MAP;
HTTP_FILTER_URL_MAP urlMap;
pvNotification = &urlMap;
urlMap.pszURL = (const char *)PIDB_lookup( pPIHTTP->pRequestDB,
PIDBTYPE_STRING, KEY_HTTP_URI, 0 );
urlMap.pszPhysicalPath = (char *)PIDB_lookup( pPIHTTP->pResponseDB,
PIDBTYPE_STRING, pFKPath, PIDBFLAG_FASTKEY );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -