windows-nt/Source/XPSP1/NT/inetsrv/query/apps/webhits/webhits.cxx
2020-09-26 16:20:57 +08:00

1042 lines
34 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2000.
//
// File: webhits.cxx
//
// History: 05-20-96 t-matts Created
// 03-03-97 dlee Converted to isapi
//
// Contents: This is the main() for the hit-highliting feature. The
// CGI environment variables are read, yielding the filename
// and the textual form of the restriction. The textual form
// is then converted to internal form. The document is then
// scanned for hits, and the positions contained in those
// hits are sorted. Finally, HTML tags are inserted in the order
// in which the distinct positions appear in the document, to
// allow the user to navigate.
//
//--------------------------------------------------------------------------
#include<pch.cxx>
#pragma hdrstop
#include <cidebug.hxx>
#include <codepage.hxx>
#include <ciregkey.hxx>
#include <regacc.hxx>
#include <cpid.hxx>
#include <dblink.hxx>
#include <imprsnat.hxx>
#include <regevent.hxx>
#include <dynstack.hxx>
#include <cimbmgr.hxx>
#include "webhits.hxx"
#include "webdbg.hxx"
#include "whmsg.h"
#include "linkhits.hxx"
#define _DECL_DLLMAIN 1
DECLARE_INFOLEVEL (web);
DECLARE_INFOLEVEL (ci);
const int ERROR_MESSAGE_SIZE=512;
BOOL g_fShutdown = TRUE;
LONG g_cThreads = 0;
CWebhitsInfo * g_pWebhitsInfo = 0;
void OutputErrorMessage( CWebServer & webServer,
CLanguageInfo & LanguageInfo,
DWORD dwMsgId,
WCHAR const * pwcIdqPPath,
WCHAR const * pwcIdqVPath,
WCHAR const * pwcHtwPPath,
WCHAR const * pwcHtwVPath,
WCHAR const * pwcWebhitsPPath,
WCHAR const * pwcWebhitsVPath,
WCHAR const * pwszDefaultMsg = 0,
WCHAR const * pwszFileName = 0,
ULONG ulFileLine = 0 );
//+---------------------------------------------------------------------------
//
// Function: GetVPathInfo
//
// Synopsis: Convers a vpath to a ppath
//
// Arguments: [webServer] -- Used for the translation
// [pwcVPath] -- VPath to translate
// [dwAccessMask] -- Access required for file, or 0 for none
// [dwFlags] -- Returns vpath flags (HSE_URL_FLAGS_*)
//
// Returns: pointer to PPath allocated on the heap.
//
// History: 3-04-97 dlee Created
//
//----------------------------------------------------------------------------
WCHAR * GetVPathInfo(
CWebServer & webServer,
WCHAR const * pwcVPath,
DWORD dwAccessMask,
DWORD & dwFlags )
{
WCHAR *pwc = 0;
TRY
{
WCHAR awcPPath[MAX_PATH];
dwFlags = webServer.GetPhysicalPath( pwcVPath,
awcPPath,
sizeof awcPPath / sizeof WCHAR,
dwAccessMask );
if ( ( 0 == wcsstr( awcPPath, L"../" ) ) &&
( 0 == wcsstr( awcPPath, L"..\\" ) ) )
{
ULONG cwc = wcslen( awcPPath ) + 1;
pwc = new WCHAR[ cwc ];
RtlCopyMemory( pwc, awcPPath, cwc * sizeof WCHAR );
}
}
CATCH( CException, e )
{
// returning 0 is sufficient
}
END_CATCH
return pwc;
} //GetVPathInfo
//+---------------------------------------------------------------------------
//
// Function: GetWebhitsVPathInfo
//
// Synopsis: Converts vpaths to ppaths for the query, template, and
// webhits files.
//
// Arguments: [vars] -- Source of vpaths, sink of ppaths
// [webServer] -- Used for the translations
//
// History: 9-06-96 srikants Created
//
//----------------------------------------------------------------------------
void GetWebhitsVPathInfo(
CGetEnvVars & vars,
CWebServer & webServer )
{
// Translate the path of the query (idq) file if one is given.
DWORD dwFlags;
if ( vars.GetQueryFileVPath() )
{
WCHAR * pwc = GetVPathInfo( webServer,
vars.GetQueryFileVPath(),
0,
dwFlags );
if ( 0 == pwc )
THROW( CWTXException( MSG_WEBHITS_IDQ_NOT_FOUND,
vars.GetQueryFileVPath(),
0 ) );
vars.AcceptQueryFilePPath( pwc, dwFlags );
webDebugOut(( DEB_ITRACE, "Query file '%ws'\n", pwc ));
}
// Translate the path of the template (htw) file if one is given.
if ( vars.GetTemplateFileVPath() )
{
WCHAR * pwc = GetVPathInfo( webServer,
vars.GetTemplateFileVPath(),
0,
dwFlags );
if ( 0 == pwc )
THROW( CWTXException( MSG_WEBHITS_NO_SUCH_TEMPLATE,
vars.GetTemplateFileVPath(),
0 ) );
vars.AcceptTemplateFilePPath( pwc, dwFlags );
webDebugOut(( DEB_ITRACE, "Template file '%ws'\n", pwc ));
}
// Translate the path of the WebHits file being displayed. Read access
// is required for this file.
if ( vars.GetWebHitsFileVPath() )
{
WCHAR * pwc = GetVPathInfo( webServer,
vars.GetWebHitsFileVPath(),
HSE_URL_FLAGS_READ,
dwFlags );
if ( 0 == pwc )
THROW( CException(MSG_WEBHITS_PATH_INVALID) );
vars.AcceptWebHitsFilePPath( pwc, dwFlags );
webDebugOut(( DEB_ITRACE, "WebHits file '%ws'\n", pwc ));
}
else
{
THROW( CException(MSG_WEBHITS_PATH_INVALID) );
}
} //GetWebhitsVPathInfo
//+---------------------------------------------------------------------------
//
// Function: ProcessWebRequest
//
// Synopsis: Main driver method for webhits.
//
// Arguments: [webServer] -- web server to use
//
// History: 9-04-96 srikants Created
//
//----------------------------------------------------------------------------
DWORD ProcessWebRequest( CWebServer & webServer )
{
DWORD hse = HSE_STATUS_SUCCESS;
//
// Initialize the locale and codepage.
//
LCID lcid = GetLCID( webServer );
ULONG urlCodePage = GetBrowserCodepage( webServer, lcid );
CLanguageInfo langInfo;
//
// Set the client and output locale info to be the same as
// the client info. If a different value is set
// via CiLocale, it will be changed when the querystring is parsed.
//
langInfo.SetUrlLangInfo( urlCodePage, lcid );
langInfo.SetRestrictionLangInfo( urlCodePage, lcid );
CURLUnescaper unescaper( langInfo.GetUrlCodePage() );
CCollectVar varRetriever( unescaper, webServer );
XArray<WCHAR> xwszQueryFile;
WCHAR awcWebhitsPPath[ MAX_PATH ];
WCHAR awcWebhitsVPath[ MAX_PATH ];
WCHAR awcIdqPPath[ MAX_PATH ];
WCHAR awcIdqVPath[ MAX_PATH ];
WCHAR awcHtwPPath[ MAX_PATH ];
WCHAR awcHtwVPath[ MAX_PATH ];
WCHAR const * pwcWebhitsPPath = 0;
WCHAR const * pwcWebhitsVPath = 0;
WCHAR const * pwcIdqPPath = 0;
WCHAR const * pwcIdqVPath = 0;
WCHAR const * pwcHtwPPath = 0;
WCHAR const * pwcHtwVPath = 0;
TRY
{
//
// Refresh the registry values if necessary
//
g_pWebhitsInfo->Refresh();
//
// Are there too many threads doing webhits?
//
if ( g_cThreads > (LONG) g_pWebhitsInfo->GetMaxRunningWebhits() )
{
webDebugOut(( DEB_WARN,
"%d instances of webhits running\n",
g_cThreads ));
THROW( CException( MSG_WEBHITS_TOO_MANY_COPIES ) );
}
//
// Retrieve the necessary environment variables.
//
CGetEnvVars variables( webServer,
langInfo,
varRetriever,
unescaper );
if (variables.GetQueryFileVPath())
{
xwszQueryFile.Init( wcslen(variables.GetQueryFileVPath())+1 );
wcscpy( xwszQueryFile.GetPointer(), variables.GetQueryFileVPath() );
}
GetWebhitsVPathInfo( variables, webServer );
//
// construct Property List with static properties
//
XInterface<CEmptyPropertyList> xlist;
//
// If an idq file was specified, then parse the [NAMES] section of
// that file to obtain custom properties
//
if ( variables.GetQueryFilePPath() )
{
Win4Assert( wcslen( variables.GetQueryFilePPath() ) < MAX_PATH );
wcscpy( awcIdqPPath, variables.GetQueryFilePPath() );
pwcIdqPPath = awcIdqPPath;
Win4Assert( wcslen( variables.GetQueryFileVPath() ) < MAX_PATH );
wcscpy( awcIdqVPath, variables.GetQueryFileVPath() );
pwcIdqVPath = awcIdqVPath;
xlist.Set( new CLocalGlobalPropertyList( GetGlobalStaticPropertyList(),
TRUE,
variables.GetQueryFilePPath(),
langInfo.GetUrlCodePage()) );
ULONG iLine;
WCHAR * pwszFile;
SCODE sc = ((CLocalGlobalPropertyList *)xlist.GetPointer())->CheckError( iLine, &pwszFile );
if (FAILED(sc))
THROW(CException(sc));
}
else
xlist.Set(GetGlobalStaticPropertyList());
//
// If a template file is specified, it should be parsed.
//
XPtr<CWebhitsTemplate> xTemplate;
if ( variables.GetTemplateFileVPath() )
{
Win4Assert( wcslen( variables.GetTemplateFilePPath() ) < MAX_PATH );
wcscpy( awcHtwPPath, variables.GetTemplateFilePPath() );
pwcHtwPPath = awcHtwPPath;
Win4Assert( wcslen( variables.GetTemplateFileVPath() ) < MAX_PATH );
wcscpy( awcHtwVPath, variables.GetTemplateFileVPath() );
pwcHtwVPath = awcHtwVPath;
CWebhitsTemplate * pTemplate =
new CWebhitsTemplate( variables,
langInfo.GetOutputCodePage() );
xTemplate.Set( pTemplate );
}
//
// convert textual query into CDbRestriction
//
CInternalQuery query( variables, xlist.GetReference(), langInfo.GetQueryLCID() );
Win4Assert( wcslen( variables.GetWebHitsFilePPath() ) < MAX_PATH );
wcscpy( awcWebhitsPPath, variables.GetWebHitsFilePPath() );
pwcWebhitsPPath = awcWebhitsPPath;
Win4Assert( wcslen( variables.GetWebHitsFileVPath() ) < MAX_PATH );
wcscpy( awcWebhitsVPath, variables.GetWebHitsFileVPath() );
pwcWebhitsVPath = awcWebhitsVPath;
//
// Verify a consistent SSL-setting for .htw and webhits files.
// This fixes the problem where the webhits file requires SSL,
// but the template file doesn't, since a port can't change its
// SSL setting on the fly. A work-around would be to do a redirect
// to a bogus .htw file in the same virtual directory as the
// webhits file to force SSL, but that seemed overkill.
//
if ( variables.GetTemplateFileVPath() )
{
//
// This is a complete list of SSL-related flags.
//
const DWORD dwSSL = HSE_URL_FLAGS_SSL |
HSE_URL_FLAGS_NEGO_CERT |
HSE_URL_FLAGS_REQUIRE_CERT |
HSE_URL_FLAGS_MAP_CERT |
HSE_URL_FLAGS_SSL128;
DWORD dwTemplate = ( variables.GetTemplateFileFlags() & dwSSL );
DWORD dwWebHits = ( variables.GetWebHitsFileFlags() & dwSSL );
if ( ( dwTemplate != dwWebHits ) &&
( 0 != dwWebHits ) )
{
webDebugOut(( DEB_WARN,
"SSL mismatch template: 0x%x, webhits: 0x%x\n",
dwTemplate, dwWebHits ));
THROW( CException( MSG_WEBHITS_INCONSISTENT_SSL ) );
}
}
//
// Impersonate if the file being webhit is remote
//
CImpersonateRemoteAccess imp( 0 );
if ( CImpersonateRemoteAccess::IsNetPath( pwcWebhitsPPath ) )
{
CImpersonationTokenCache * pCache = g_pWebhitsInfo->GetTokenCache( webServer );
imp.SetTokenCache( pCache );
// Flip the slashes -- the token cache expects backslashes...
unsigned cwc = wcslen( pwcWebhitsVPath );
Win4Assert( cwc < MAX_PATH );
WCHAR awcTempVPath[ MAX_PATH ];
for ( unsigned c = 0; c < cwc; c++ )
{
if ( L'/' == pwcWebhitsVPath[c] )
awcTempVPath[c] = L'\\';
else
awcTempVPath[c] = pwcWebhitsVPath[c];
}
awcTempVPath[ cwc ] = 0;
//
// If impersonation fails, try rescanning the metabase.
// There may have been an update to vroot info.
// Note that revocation may take a long time as a result.
// It's really unlikely we'll have to reinit very often
// unless the server is misconfigured.
//
if ( !imp.ImpersonateIfNoThrow( pwcWebhitsPPath, awcTempVPath ) )
{
pCache->ReInitializeIISScopes();
imp.ImpersonateIf( pwcWebhitsPPath, awcTempVPath );
}
}
//
// construct framework for highlighting, and highlight hits
//
query.CreateISearch( pwcWebhitsPPath );
//
// two cases - either summary or full hit-highlighting
//
CReleasableLock lock( g_pWebhitsInfo->GetNonThreadedFilterMutex(),
FALSE );
if (variables.GetHiliteType() == CGetEnvVars::SUMMARY)
{
XPtr<CDocument> xDoc( new CDocument(
(WCHAR*) pwcWebhitsPPath,
CLinkQueryHits::BOGUS_RANK,
query.GetISearchRef(),
g_pWebhitsInfo->GetMaxWebhitsCpuTime(),
lock,
xlist.GetReference(),
g_pWebhitsInfo->GetDisplayScript() ) );
PHttpOutput httpOutput( webServer, langInfo );
httpOutput.Init( &variables, xTemplate.GetPointer() );
HitIter iterator;
iterator.Init( xDoc.GetPointer() );
httpOutput.OutputHTMLHeader();
if ( variables.IsFixedFont() )
httpOutput.OutputPreformattedTag();
CExtractHits hitExtractor( xDoc.GetReference(),
iterator,
httpOutput );
httpOutput.OutputHTMLFooter();
}
else
{
PHttpFullOutput httpOutput( webServer, langInfo );
httpOutput.Init(&variables, xTemplate.GetPointer());
XPtr<CLinkQueryHits> xLQH( new CLinkQueryHits(
query,
variables,
httpOutput,
g_pWebhitsInfo->GetMaxWebhitsCpuTime(),
lock,
xlist.GetReference(),
g_pWebhitsInfo->GetDisplayScript() ) );
httpOutput.OutputHTMLHeader();
xLQH->InsertLinks();
httpOutput.OutputHTMLFooter();
}
}
CATCH( CPListException, ple )
{
WCHAR wcTempBuffer[ERROR_MESSAGE_SIZE];
wsprintf( wcTempBuffer,
L"Property list parsing query file %ls failed with error 0x%X\n",
xwszQueryFile.GetPointer(),
ple.GetPListError() );
OutputErrorMessage( webServer,
langInfo,
ple.GetPListError(),
pwcIdqPPath,
pwcIdqVPath,
pwcHtwPPath,
pwcHtwVPath,
pwcWebhitsPPath,
pwcWebhitsVPath,
wcTempBuffer,
xwszQueryFile.GetPointer(),
ple.GetLine() );
}
AND_CATCH( CWTXException, we )
{
WCHAR wcTempBuffer[ERROR_MESSAGE_SIZE];
wsprintf( wcTempBuffer,
L"Parsing template file %ls failed with error 0x%X\n",
we.GetFileName(),
we.GetErrorCode() );
OutputErrorMessage( webServer,
langInfo,
we.GetErrorCode(),
pwcIdqPPath,
pwcIdqVPath,
pwcHtwPPath,
pwcHtwVPath,
pwcWebhitsPPath,
pwcWebhitsVPath,
wcTempBuffer,
we.GetFileName(),
we.GetLineNumber() );
}
AND_CATCH( CParserException, pe )
{
WCHAR wcTempBuffer[ERROR_MESSAGE_SIZE];
wsprintf( wcTempBuffer,
L"Parsing of QUERY_STRING failed with error 0x%X\n",
pe.GetErrorCode() );
OutputErrorMessage( webServer,
langInfo,
pe.GetParseError(),
pwcIdqPPath,
pwcIdqVPath,
pwcHtwPPath,
pwcHtwVPath,
pwcWebhitsPPath,
pwcWebhitsVPath,
wcTempBuffer );
}
AND_CATCH( CException,e )
{
OutputErrorMessage( webServer,
langInfo,
e.GetErrorCode(),
pwcIdqPPath,
pwcIdqVPath,
pwcHtwPPath,
pwcHtwVPath,
pwcWebhitsPPath,
pwcWebhitsVPath );
}
END_CATCH
return hse;
} //ProcessWebRequest
//+---------------------------------------------------------------------------
//
// Function: OutputErrorMessage
//
// Synopsis: Outputs an error message based on the msg id given. It first
// looks up for the error in webhits.dll, query.dll, then in
// kernel32.dll.
// If no message is found, it then uses the default message.
//
// Arguments: [dwMsgId] - Message id
// [pwszDefaultMsg] - Pointer to the default message. Will be
// used if there is no pre-formatted message.
// [pwszFileName] - File name to be printed prior to the error
// message. Will not be printed if null.
// [ulFileLine] - File line number. Not printed if zero.
//
// History: 9-04-96 srikants Created
//
//----------------------------------------------------------------------------
void OutputErrorMessage( CWebServer & webServer,
CLanguageInfo & langInfo,
DWORD dwMsgId,
WCHAR const * pwcIdqPPath,
WCHAR const * pwcIdqVPath,
WCHAR const * pwcHtwPPath,
WCHAR const * pwcHtwVPath,
WCHAR const * pwcWebhitsPPath,
WCHAR const * pwcWebhitsVPath,
WCHAR const * pwszDefaultMsg,
WCHAR const * pwszFileName,
ULONG ulFileLine )
{
CImpersonateSystem system;
//
// If the error was the result of an access denied problem, then simply
// return a 401 error to the browser if the path allows authentication
//
// Generate the Win32 error code by removing the facility code (7) and
// the error bit.
//
if ( (STATUS_ACCESS_DENIED == dwMsgId) ||
(STATUS_NETWORK_ACCESS_DENIED == dwMsgId) ||
(HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) == dwMsgId) ||
(HRESULT_FROM_WIN32( ERROR_INVALID_ACCESS ) == dwMsgId) ||
(HRESULT_FROM_WIN32( ERROR_NETWORK_ACCESS_DENIED ) == dwMsgId) )
{
WCHAR const * pwcVPath = 0;
WCHAR const * pwcPPath = 0;
if ( 0 != pwcWebhitsVPath )
{
pwcPPath = pwcWebhitsPPath;
pwcVPath = pwcWebhitsVPath;
}
else if ( 0 != pwcHtwVPath )
{
pwcPPath = pwcHtwPPath;
pwcVPath = pwcHtwVPath;
}
else
{
pwcPPath = pwcIdqPPath;
pwcVPath = pwcIdqVPath;
}
Win4Assert( 0 != pwcPPath );
Win4Assert( 0 != pwcVPath );
webDebugOut(( DEB_ITRACE, "error P and V paths: '%ws', '%ws'\n",
pwcPPath, pwcVPath ));
CMetaDataMgr mdMgr( FALSE, W3VRoot, webServer.GetServerInstance() );
ULONG Authorization = mdMgr.GetVPathAuthorization( pwcVPath );
webDebugOut(( DEB_ITRACE, "authorization: 0x%x\n", Authorization ));
// If the virtual directory doesn't support just anonymous,
// this is not a remote physical path, try to authenticate.
if ( 0 != Authorization &&
MD_AUTH_ANONYMOUS != Authorization &&
!CImpersonateRemoteAccess::IsNetPath( pwcPPath ) )
{
webDebugOut(( DEB_WARN,
"mapping 0x%x to 401 access denied\n",
dwMsgId ));
webServer.WriteHeader( 0, "401 Access denied" );
const char * pcAccessDenied = "Access is denied.";
webServer.WriteClient( (BYTE *) pcAccessDenied,
strlen( pcAccessDenied ) );
return;
}
}
WCHAR awcTempBuffer[ERROR_MESSAGE_SIZE];
WCHAR * pwszErrorMessage = awcTempBuffer;
ULONG cchAvailMessage = ERROR_MESSAGE_SIZE;
//
// Don't pass a specific lang id to FormatMessage since it will
// fail if there's no message in that language. Instead set
// the thread locale, which will get FormatMessage to use a search
// algorithm to find a message of the appropriate language or
// use a reasonable fallback msg if there's none.
//
LCID SaveLCID = GetThreadLocale();
SetThreadLocale( langInfo.GetQueryLCID() );
if (pwszFileName != 0)
{
//
// These are errors encountered while parsing the [names] section
//
DWORD_PTR args [] = {
(DWORD_PTR) pwszFileName,
(DWORD_PTR) ulFileLine,
};
NTSTATUS MsgNum = MSG_WEBHITS_FILE_MESSAGE;
if ( 0 != ulFileLine )
MsgNum = MSG_WEBHITS_FILE_LINE_MESSAGE;
ULONG cchMsg = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
GetModuleHandle(L"webhits.dll"),
MsgNum,
0,
pwszErrorMessage,
cchAvailMessage,
(va_list *) args );
pwszErrorMessage += cchMsg;
cchAvailMessage -= cchMsg;
}
if ( !FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
GetModuleHandle(L"webhits.dll"),
dwMsgId,
0,
pwszErrorMessage,
cchAvailMessage,
0 ) &&
!FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
GetModuleHandle(L"Query.dll"),
dwMsgId,
0,
pwszErrorMessage,
cchAvailMessage,
0 ) &&
!FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
GetModuleHandle(L"kernel32.dll"),
dwMsgId,
0,
pwszErrorMessage,
cchAvailMessage,
0 ) &&
!FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
GetModuleHandle(L"kernel32.dll"),
HRESULT_CODE(dwMsgId),
0,
pwszErrorMessage,
cchAvailMessage,
0 ) )
{
DWORD dwError = GetLastError();
webDebugOut(( DEB_ERROR, "Format Message failed with error 0x%X\n",
dwError ));
if ( !pwszDefaultMsg )
{
wsprintf( pwszErrorMessage,
L"Error 0x%X occurred while running webhits \n",
dwMsgId );
}
else
{
Win4Assert( wcslen( pwszDefaultMsg ) < cchAvailMessage );
wsprintf( pwszErrorMessage, L"%ws\n", pwszDefaultMsg );
}
}
SetThreadLocale(SaveLCID);
PHttpOutput httpOutput( webServer, langInfo );
httpOutput.OutputErrorHeader();
httpOutput.OutputErrorMessage( awcTempBuffer, wcslen(awcTempBuffer) );
httpOutput.OutputHTMLFooter();
} //OutputErrorMessage
//+---------------------------------------------------------------------------
//
// Function: GetExtensionVersion - public
//
// Synposis: Returns extension info to the server. This is called before
// HttpExtensionProc is called, and it is called in System
// context, so any initialization that requires this context
// must be handled here.
//
// Arguments: [pVer] - where the info goes
//
// History: 96-Apr-15 dlee Added header
//
//----------------------------------------------------------------------------
BOOL WINAPI GetExtensionVersion(
HSE_VERSION_INFO * pVer )
{
BOOL fOK = TRUE;
TRANSLATE_EXCEPTIONS;
TRY
{
Win4Assert( g_fShutdown );
Win4Assert( 0 == g_pWebhitsInfo );
pVer->dwExtensionVersion = MAKELONG( 0, 3 );
strcpy( pVer->lpszExtensionDesc, "Indexing Service webhits extension" );
g_pWebhitsInfo = new CWebhitsInfo();
g_fShutdown = FALSE;
}
CATCH( CException, e )
{
fOK = FALSE;
webDebugOut(( DEB_WARN,
"GetExtensionVersion failed 0x%x\n",
e.GetErrorCode() ));
}
END_CATCH
UNTRANSLATE_EXCEPTIONS;
return fOK;
} //GetExtensionVersion
//+---------------------------------------------------------------------------
//
// Function: TerminateExtension, public
//
// Synposis: Called by IIS during shutdown
//
// History: 3-Mar-97 dlee Created
//
//----------------------------------------------------------------------------
BOOL WINAPI TerminateExtension(
DWORD dwFlags )
{
TRANSLATE_EXCEPTIONS;
BOOL fOK = FALSE;
if ( dwFlags & HSE_TERM_MUST_UNLOAD )
{
TRY
{
Win4Assert( !g_fShutdown );
g_fShutdown = TRUE;
webDebugOut(( DEB_WARN,
"Mandatory extension unload. Shutting down webhits.\n" ));
// wait for all the isapi request threads to finish
while ( 0 != g_cThreads )
Sleep( 50 );
delete g_pWebhitsInfo;
g_pWebhitsInfo = 0;
CIShutdown();
}
CATCH( CException, e )
{
// ignore
}
END_CATCH
fOK = TRUE;
}
webDebugOut(( DEB_WARN,
"webhits extension unload: 0x%x. Flags = 0x%x\n",
fOK, dwFlags ));
UNTRANSLATE_EXCEPTIONS;
return fOK;
} //TerminateExtension
//+---------------------------------------------------------------------------
//
// Function: HttpExtensionProc, public
//
// Synposis: Handles a request from the web server
//
// Arguments: [pEcb] -- block from the server
//
// History: 3-Mar-97 dlee Created
//
//----------------------------------------------------------------------------
DWORD WINAPI HttpExtensionProc(
EXTENSION_CONTROL_BLOCK * pEcb )
{
if ( g_fShutdown )
{
pEcb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
return HSE_STATUS_ERROR;
}
InterlockedIncrement( & g_cThreads );
CWebServer webServer( pEcb );
DWORD hseStatus = HSE_STATUS_ERROR;
webServer.SetHttpStatus( HTTP_STATUS_OK );
TRANSLATE_EXCEPTIONS;
TRY
{
XCom xcom;
hseStatus = ProcessWebRequest( webServer );
}
CATCH( CException, e )
{
hseStatus = HSE_STATUS_ERROR;
webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
}
END_CATCH
UNTRANSLATE_EXCEPTIONS;
Win4Assert( HSE_STATUS_PENDING != hseStatus );
InterlockedDecrement( & g_cThreads );
return hseStatus;
} //HttpExtensionProc
//+---------------------------------------------------------------------------
//
// Method: CWebhitsInfo::CWebhitsInfo, public
//
// Synposis: Constructs a webhits info object
//
// History: 18-Aug-97 dlee Created
//
//----------------------------------------------------------------------------
CWebhitsInfo::CWebhitsInfo() :
_regChangeEvent( wcsRegAdminTree )
{
ReadRegValues();
} //CWebhitsInfo
//+---------------------------------------------------------------------------
//
// Method: CWebhitsInfo::Refresh, public
//
// Synposis: Checks to see if the registry has changed and refreshes it
//
// History: 18-Aug-97 dlee Created
//
//----------------------------------------------------------------------------
void CWebhitsInfo::Refresh()
{
CLock lock( _mutex );
ULONG res = WaitForSingleObject( _regChangeEvent.GetEventHandle(), 0 );
if ( WAIT_OBJECT_0 == res )
{
ReadRegValues();
_regChangeEvent.Reset();
}
} //Refresh
//+---------------------------------------------------------------------------
//
// Method: CWebhitsInfo::ReadRegValues
//
// Synposis: Reads webhits registry info
//
// History: 18-Aug-97 dlee Created
//
//----------------------------------------------------------------------------
void CWebhitsInfo::ReadRegValues()
{
CRegAccess reg( RTL_REGISTRY_CONTROL, wcsRegAdmin );
const ULONG CI_RUNNING_WEBHITS_DEFAULT = 20;
const ULONG CI_RUNNING_WEBHITS_MIN = 1;
const ULONG CI_RUNNING_WEBHITS_MAX = 200;
ULONG ul = reg.Read( wcsMaxRunningWebhits, CI_RUNNING_WEBHITS_DEFAULT );
_cMaxRunningWebhits = Range( ul, CI_RUNNING_WEBHITS_MIN, CI_RUNNING_WEBHITS_MAX );
const ULONG CI_WEBHITS_DISPLAY_SCRIPT_DEFAULT = DISPLAY_SCRIPT_KNOWN_FILTER;
const ULONG CI_WEBHITS_DISPLAY_SCRIPT_MIN = 0;
const ULONG CI_WEBHITS_DISPLAY_SCRIPT_MAX = 2;
ul = reg.Read( wcsWebhitsDisplayScript, CI_WEBHITS_DISPLAY_SCRIPT_DEFAULT );
_ulDisplayScript = Range( ul, CI_WEBHITS_DISPLAY_SCRIPT_MIN, CI_WEBHITS_DISPLAY_SCRIPT_MAX );
const ULONG CI_WEBHITS_TIMEOUT_DEFAULT = 30;
const ULONG CI_WEBHITS_TIMEOUT_MIN = 5;
const ULONG CI_WEBHITS_TIMEOUT_MAX = 7200;
ul = reg.Read( wcsMaxWebhitsCpuTime, CI_WEBHITS_TIMEOUT_DEFAULT );
_cmsMaxWebhitsCpuTime = Range( ul, CI_WEBHITS_TIMEOUT_MIN, CI_WEBHITS_TIMEOUT_MAX );
} //ReadRegValues
//+---------------------------------------------------------------------------
//
// Method: GetTokenCache, public
//
// Synposis: Retrieves the appropriate token cache for the web server
//
// Arguments: [webServer] -- The web server instance
//
// History: 18-Aug-97 dlee Created
//
//----------------------------------------------------------------------------
CImpersonationTokenCache * CWebhitsInfo::GetTokenCache(
CWebServer & webServer )
{
//
// Get the server instance of this ISAPI request
//
ULONG ulInstance = webServer.GetServerInstance();
//
// Look for a token cache for this server instance
//
CLock lock( _mutex );
for ( unsigned x = 0; x < _aTokenCache.Count(); x++ )
{
Win4Assert( 0 != _aTokenCache[ x ] );
if ( _aTokenCache[ x ]->GetW3Instance() == ulInstance )
return _aTokenCache[ x ];
}
//
// Not found, so create a new token cache
//
CImpersonateSystem system;
XPtr<CImpersonationTokenCache> xCache( new CImpersonationTokenCache( L"" ) );
xCache->Initialize( L"webhits", // arbitrary name of token cache
TRUE, // w3svc
FALSE, // not nntp
FALSE, // not imap
ulInstance, // virtual server instance number
0, // no nntp vserver instance
0 ); // no imap vserver instance
_aTokenCache[ _aTokenCache.Count() ] = xCache.GetPointer();
return xCache.Acquire();
} //GetTokenCache