📄 filters.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*--
Module Name: filters.cpp
Abstract: ISAPI Filter handling classes
--*/
#include "httpd.h"
CISAPIFilterCon* g_pFilterCon;
const DWORD g_fIsapiFilterModule = TRUE;
const LPCWSTR cwszFilterSep = L","; // what seperates filter ids in the registry
// Used to increment the filter, goes up 1 normally, down 1 for RAW DATA prio inversion
#define NEXTFILTER(dwNotifyType, i) { (dwNotifyType == SF_NOTIFY_SEND_RAW_DATA) ? i-- : i++;}
void FreeLogParams(PHTTP_FILTER_LOG pLog);
// Creates new filter info used globally
BOOL InitFilters() {
g_pFilterCon = new CISAPIFilterCon();
return (g_pFilterCon && g_pFilterCon->m_nFilters!=0);
}
// Destroys the global filter information
void CleanupFilters() {
if (g_pFilterCon)
delete g_pFilterCon;
g_pFilterCon = 0;
}
CFilterInfo* CreateCFilterInfo(void) {
if (0 == g_pFilterCon->m_nFilters)
return NULL;
return new CFilterInfo;
}
// CFilterInfo is an internal member of CHttpRequest. Allocate buffers for it
CFilterInfo::CFilterInfo() {
ZEROMEM(this);
m_pdwEnable = MyRgAllocNZ(DWORD,g_pFilterCon->m_nFilters);
if (!m_pdwEnable) {
DEBUGMSG(ZONE_ERROR, (L"HTTPD: CFilterInfo::Init died on Alloc!\r\n"));
return;
}
m_ppvContext = MyRgAllocZ(PVOID,g_pFilterCon->m_nFilters);
if (!m_ppvContext) {
MyFree(m_pdwEnable);
DEBUGMSG(ZONE_ERROR, (L"HTTPD: CFilterInfo::Init died on Alloc!\r\n"));
return;
}
// A filter can disable itself for events in a session, m_pdwEnable stores this.
memset(m_pdwEnable,0xFFFF,g_pFilterCon->m_nFilters*sizeof(DWORD)); // all true at first
m_dwStartTick = GetTickCount();
m_fFAccept = TRUE;
return;
}
// Notes: If http request is to be persisted, this is called.
// Do NOT Free the Allocated Mem or the context structure here, these are persisted
// across requests, delete at end of session.
BOOL CFilterInfo::ReInit() {
MyFree(m_pszDenyHeader);
if (m_pFLog) {
MyFree(m_pFLog);
}
// Reset the enable structure to all 1's, starting over.
memset(m_pdwEnable,0xFFFF,g_pFilterCon->m_nFilters*sizeof(DWORD)); // all true at first
// The context struct and AllocMem data lasts through the session, not just a request.
m_dwStartTick = GetTickCount();
m_fFAccept = TRUE;
m_dwNextReadSize = 0;
m_dwBytesSent = 0;
m_dwBytesReceived = 0;
return TRUE;
}
CFilterInfo::~CFilterInfo() {
MyFree(m_pszDenyHeader);
if (m_pFLog) {
MyFree(m_pFLog);
}
MyFree(m_pdwEnable);
MyFree(m_ppvContext);
FreeAllocMem(); // frees m_pAllocBlock
}
// Initilization routine for global filters. This looks in the registry for the
// filters, loads any dlls into memory, and puts them into a list that is
// ordered from Highest prio filters to lowest.
BOOL CISAPIFilterCon::Init() {
DEBUG_CODE_INIT;
BOOL ret = FALSE;
BOOL fChange = FALSE;
CISAPI *pCISAPI = NULL;
const WCHAR *wcszReg;
WCHAR *wszFilterNames;
DWORD dwFilterLen = 0;
PWSTR wszToken = NULL;
DWORD i;
int j;
CReg topreg(HKEY_LOCAL_MACHINE,RK_HTTPD);
wcszReg = topreg.ValueSZ(RV_FILTER);
wszFilterNames = MySzDupW(wcszReg);
DEBUGMSG(ZONE_ISAPI, (L"HTTPD: Filter DLLs Reg Value <<%s>>\r\n",wszFilterNames));
if (NULL == wszFilterNames || 0 == (dwFilterLen = wcslen(wszFilterNames))) {
DEBUGMSG(ZONE_ISAPI,(L"HTTPD: No filters listed in registry\r\n"));
myleave(0); // no values => no registered filters
}
// count # of commas to figure how many dlls there are
m_nFilters = 1; // there's at least 1 if we're this far
for (i = 0; i < dwFilterLen && wszFilterNames[i] != L'\0'; i++) {
if (wszFilterNames[i] == L',')
m_nFilters++;
}
DEBUGMSG(ZONE_ISAPI, (L"HTTPD: # of filters = %d\r\n",m_nFilters));
if (! (m_pFilters = MyRgAllocZ(FILTERINFO,m_nFilters)))
myleave(203);
// now tokenize the string and load filter libs as we do it
j = 0;
wszToken = wcstok(wszFilterNames,cwszFilterSep);
while (wszToken != NULL) {
svsutil_SkipWWhiteSpace(wszToken);
// Handles the case where there's a comma but nothing after it.
if (*wszToken == L'\0') {
m_nFilters--;
break;
}
pCISAPI = m_pFilters[j].pCISAPI = new CISAPI(SCRIPT_TYPE_FILTER);
DEBUGMSG(ZONE_ISAPI, (L"HTTPD: Initiating filter library %s\r\n",wszToken));
if (!pCISAPI) {
m_nFilters = j;
if (m_nFilters == 0)
MyFree(m_pFilters);
myleave(204);
}
if (TRUE == pCISAPI->Load(wszToken)) {
m_pFilters[j].wszDLLName = MySzDupW(wszToken);
m_pFilters[j].dwFlags = pCISAPI->GetFilterFlags();
if (m_pFilters[j].dwFlags & SF_NOTIFY_READ_RAW_DATA)
g_pVars->m_fReadFilters = TRUE;
j++;
}
else {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Filter <<%s>> failed to load!\r\n",wszToken));
// only messed up this filter, others may work so keep on moving
m_nFilters--;
delete pCISAPI;
}
wszToken = wcstok(NULL,cwszFilterSep);
}
DEBUGCHK(j == m_nFilters);
// Case where every filter fails to load
if (0 == m_nFilters) {
// Cleanup();
MyFree(m_pFilters);
myleave(205);
}
// Reorder list based on priorities of filters.
do {
fChange = FALSE;
for(j=0; j<m_nFilters-1; j++) {
if ( (m_pFilters[j].dwFlags & SF_NOTIFY_ORDER_MASK) < (m_pFilters[j+1].dwFlags & SF_NOTIFY_ORDER_MASK)) {
// swap the 2 filter infos
FILTERINFO ftemp = m_pFilters[j+1];
m_pFilters[j+1] = m_pFilters[j];
m_pFilters[j] = ftemp;
fChange = TRUE;
}
}
} while(fChange);
ret = TRUE;
done:
DEBUGMSG_ERR(ZONE_ERROR, (L"HTTPD: CIsapiFilterCon::Init FAILED: GLE=%d err=%d\r\n",
GetLastError(), err));
MyFree(wszFilterNames);
return ret;
}
void CISAPIFilterCon::Cleanup() {
if (0 == m_pFilters)
return;
for (int i = 0; i < m_nFilters; i++) {
m_pFilters[i].pCISAPI->Unload(m_pFilters[i].wszDLLName);
MyFree(m_pFilters[i].wszDLLName);
delete m_pFilters[i].pCISAPI;
}
MyFree(m_pFilters);
}
// Determines whether or not a filter will be called based on current set of flags
BOOL CHttpRequest::IsCurrentFilterCalled(DWORD dwNotifyType, int iCurrentFilter) {
// Filter has not requested to be notified for current call or has disabled itself through SF_REQ_DISABLE_NOTIFICATIONS.
if (0 == ((dwNotifyType & g_pFilterCon->m_pFilters[iCurrentFilter].dwFlags) & m_pFInfo->m_pdwEnable[iCurrentFilter]))
return FALSE;
// Filter only wants secure notifications but we're receiving on an insecure port, or vice versa.
if ((m_fIsSecurePort && ! (g_pFilterCon->m_pFilters[iCurrentFilter].dwFlags & SF_NOTIFY_SECURE_PORT)) ||
(!m_fIsSecurePort && ! (g_pFilterCon->m_pFilters[iCurrentFilter].dwFlags & SF_NOTIFY_NONSECURE_PORT)))
return FALSE;
return TRUE;
}
// BOOL CHttpRequest::CallFilter
// Function: Httpd calls this function on specified events, it's goes through
// the list and calls the registered filters for that event.
// PARAMETERS:
// DWORD dwNotifyType - what SF_NOTIFIY type occured
// The last 3 parameters are optional; only 3 filter calls use them.
// They are used when extra data needs to be passed to the filter that isn't
// part of the CHttpRequest structure.
// PSTR *ppszBuf1 ---> SF_NOTIFY_SEND_RAW_DATA --> The buffer about to be sent
// ---> SF_NOTIFY_URL_MAP --> The virtual path (only
// on ServerSupportFunction with HSE_REQ_MAP_URL_TO_PATH,
// otherwise use CHttpRequest values.)
// ---> SF_NOTIFY_AUTHENTECATION --> The remote user name
// ---> SF_NOTIFY_READ_RAW_DATA --> Buffer about to be read
// PSTR *ppszBuf2 ---> SF_NOTIFY_SEND_RAW_DATA --> Unused
// ---> SF_NOTIFY_URL_MAP --> The physical mapping
// ---> SF_NOTIFY_AUTHENTECATION --> The user's password
// ---> SF_NOTIFY_READ_RAW_DATA --> Buffer about to be read
//
// int *pcbBuf ---> SF_NOTIFY_SEND_RAW_DATA --> Length of buffer to be sent
// ---> SF_NOTIFY_URL_MAP --> Length of physical path buf
// ---> SF_NOTIFY_AUTHENTECATION --> Unused
// ---> SF_NOTIFY_READ_RAW_DATA --> Buffer about to be read
// int *pcbBuf2 ---> SF_NOTIFY_READ_RAW_DATA --> size of the buffer reading into
// return values
// TRUE tells calling fcn to continue normal execution
// FALSE tells calling fcn to terminate this request.
// Notes:
// if FALSE is returned, m_pFilterInfo->m_fAccept is also set to false. This
// helps the filter handle unwinding from nested filter calls.
// For example, the http server calls a filter with URL_MAP flags. The filter
// then calls a WriteClient, which will call the filter again with event
// SF_NOTIFY_SEND_RAW_DATA. If on the SEND_RAW_DATA call the filter returns a
// code to stop the session, we need to store it for the original MAP_URL call,
// so that it knows to stop the session too.
BOOL CHttpRequest::CallFilter(DWORD dwNotifyType, PSTR *ppszBuf1,
int *pcbBuf, PSTR *ppszBuf2, int *pcbBuf2)
{
DEBUG_CODE_INIT;
HTTP_FILTER_CONTEXT fc;
LPVOID pStFilter; // 3rd param passed on HttpFilterProc
LPVOID pStFilterOrg; // stores a copy of pStFilter, so we remember alloc'd mem to cleanup, if any
BOOL fFillStructs = TRUE;
BOOL fReqReadNext;
BOOL ret = FALSE;
DWORD dwFilterCode;
int i;
if (0 == g_pFilterCon->m_nFilters)
return TRUE;
// m_pFInfo->m_fFAccept = FALSE implies no more filter calls, except on the "cleanup" calls
DEBUGMSG(ZONE_ISAPI,(L"HTTPD: Filter notify type = 0x%08x\r\n",dwNotifyType));
if ( (! m_pFInfo->m_fFAccept) &&
! (dwNotifyType & (SF_NOTIFY_END_OF_REQUEST | SF_NOTIFY_LOG | SF_NOTIFY_END_OF_NET_SESSION | SF_NOTIFY_SEND_RESPONSE | SF_NOTIFY_SEND_RAW_DATA)))
{
return FALSE;
}
m_pFInfo->m_dwSFEvent = dwNotifyType;
do {
pStFilter = pStFilterOrg = NULL;
fReqReadNext = FALSE;
// Filters implement priority inversion for SEND_RAW_DATA events.
i = (dwNotifyType == SF_NOTIFY_SEND_RAW_DATA) ? g_pFilterCon->m_nFilters - 1 : 0;
while ( (dwNotifyType == SF_NOTIFY_SEND_RAW_DATA) ? i >= 0 : i < g_pFilterCon->m_nFilters ) {
// we still reference g_pFilterCon just in case a filter failed in another request
if (! IsCurrentFilterCalled(dwNotifyType,i)) {
// ith filter didn't request this notification, move along
NEXTFILTER(dwNotifyType, i);
continue;
}
m_pFInfo->m_iFIndex = i;
if (fFillStructs && (!FillFC(&fc,dwNotifyType,&pStFilter,&pStFilterOrg,
ppszBuf1, pcbBuf, ppszBuf2, pcbBuf2)))
myretleave(FALSE,210); // memory error on FillFC
fFillStructs = FALSE; // after structs or filled don't refill them
fc.pFilterContext = m_pFInfo->m_ppvContext[i];
__try {
dwFilterCode = g_pFilterCon->m_pFilters[i].pCISAPI->CallFilter(&fc,dwNotifyType,pStFilter);
}
__except(ReportFault(GetExceptionInformation(),0), EXCEPTION_EXECUTE_HANDLER) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -