974 lines
30 KiB
C++
974 lines
30 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 2000.
|
|
//
|
|
// File: main.cxx
|
|
//
|
|
// Contents: External entry points for idq.dll.
|
|
//
|
|
// History: 96/Jan/3 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <ntverp.h>
|
|
|
|
#define IDQ_VERSION 3
|
|
|
|
#define _DECL_DLLMAIN 1
|
|
|
|
CTheGlobalIDQVariables * pTheGlobalIDQVariables = 0;
|
|
DWORD g_cClients = 0;
|
|
CRITICAL_SECTION g_csInitExclusive;
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
//
|
|
// Notes: There may be multiple clients of this ISAPI app in one
|
|
// process (eg W3Svc and NNTPSvc), so refcount the users.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO * pVer )
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
|
|
EnterCriticalSection( &g_csInitExclusive );
|
|
|
|
TRANSLATE_EXCEPTIONS;
|
|
|
|
TRY
|
|
{
|
|
pVer->dwExtensionVersion = MAKELONG( 0, IDQ_VERSION );
|
|
strcpy( pVer->lpszExtensionDesc, "Indexing Service extension" );
|
|
|
|
if ( 0 == g_cClients )
|
|
{
|
|
Win4Assert( 0 == pTheGlobalIDQVariables );
|
|
pTheGlobalIDQVariables = new CTheGlobalIDQVariables();
|
|
LoadServerErrors();
|
|
}
|
|
|
|
g_cClients++;
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
fSuccess = FALSE;
|
|
|
|
ciGibDebugOut(( DEB_WARN, "GetExtensionVersion failed 0x%x\n",
|
|
e.GetErrorCode() ));
|
|
}
|
|
END_CATCH
|
|
|
|
UNTRANSLATE_EXCEPTIONS;
|
|
|
|
LeaveCriticalSection( &g_csInitExclusive );
|
|
|
|
return fSuccess;
|
|
} //GetExtensionVersion
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: TerminateExtension, public
|
|
//
|
|
// Synposis: Called by IIS during shutdown
|
|
|
|
// History: 29-Apr-96 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL WINAPI TerminateExtension( DWORD dwFlags )
|
|
{
|
|
EnterCriticalSection( &g_csInitExclusive );
|
|
|
|
TRANSLATE_EXCEPTIONS;
|
|
|
|
BOOL fOK = FALSE;
|
|
|
|
if ( dwFlags & HSE_TERM_MUST_UNLOAD )
|
|
{
|
|
TRY
|
|
{
|
|
Win4Assert( 0 != g_cClients );
|
|
g_cClients--;
|
|
if ( 0 == g_cClients )
|
|
{
|
|
ciGibDebugOut(( DEB_WARN, "Mandatory extension unload. Shutting down CI.\n" ));
|
|
|
|
TheWebQueryCache.Shutdown();
|
|
TheWebPendingRequestQueue.Shutdown();
|
|
|
|
//
|
|
// Wait for all ISAPI threads to exit before shutting down CI
|
|
//
|
|
while ( TheWebResourceArbiter.GetThreadCount() > 0 )
|
|
{
|
|
ciGibDebugOut(( DEB_WARN, "TerminateExtension: waiting for ISAPI threads to complete\n" ));
|
|
Sleep( 50 );
|
|
}
|
|
|
|
ciGibDebugOut(( DEB_WARN,
|
|
"TerminatExtension, request count %d\n",
|
|
TheWebQueryCache.ActiveRequestCount() ));
|
|
|
|
// note: don't call CIShutdown here. There's no need
|
|
// to, and it'll hose the impersonation token cache for
|
|
// webhits.
|
|
|
|
delete pTheGlobalIDQVariables;
|
|
pTheGlobalIDQVariables = 0;
|
|
}
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
// ignore
|
|
}
|
|
END_CATCH
|
|
|
|
fOK = TRUE;
|
|
}
|
|
|
|
ciGibDebugOut(( DEB_WARN, "Extension unload: 0x%x. Flags = 0x%x\n",
|
|
fOK, dwFlags ));
|
|
|
|
UNTRANSLATE_EXCEPTIONS;
|
|
|
|
LeaveCriticalSection( &g_csInitExclusive );
|
|
|
|
return fOK;
|
|
} //TerminateExtension
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateQueryFromRequest, private
|
|
//
|
|
// Synposis: Issues a query from a request.
|
|
//
|
|
// Arguments: [outputFormat] -- returns the formatting info.
|
|
// [localVars] -- returns the local variables.
|
|
// [wcsIDQFile] -- returns the idq file name.
|
|
// [webServer] -- web server for the request.
|
|
// [eErrorClass] -- returns the error class
|
|
// [status] -- returns the error code
|
|
// [fPending] -- returns TRUE if the request is pending
|
|
//
|
|
// History: 96-Apr-15 dlee created from existing code
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#if (CIDBG == 0)
|
|
inline
|
|
#endif
|
|
|
|
CWQueryItem * CreateQueryFromRequest( XPtr<COutputFormat> & outputFormat,
|
|
XPtr<CVariableSet> & localVars,
|
|
WCHAR * wcsIDQFile,
|
|
CWebServer & webServer,
|
|
int & eErrorClass,
|
|
NTSTATUS & status,
|
|
BOOL & fPending )
|
|
{
|
|
//
|
|
// NOTE: COutputFormat makes a **copy** of the web server. This
|
|
// copy should be used exclusively from this point on. The
|
|
// original web server will still be used by callers of this
|
|
// routine in cases where we fail to create the copy.
|
|
//
|
|
|
|
outputFormat.Set( new COutputFormat( webServer ) );
|
|
localVars.Set( new CVariableSet );
|
|
|
|
CSecurityIdentity securityIdentity;
|
|
XArray<WCHAR> xLocale;
|
|
|
|
//
|
|
// Update the original web server, in case we use it in a top-level
|
|
// error path.
|
|
//
|
|
|
|
webServer = outputFormat.GetReference();
|
|
LCID locale = GetBrowserLCID( outputFormat.GetReference() , xLocale );
|
|
outputFormat->LoadNumberFormatInfo( locale, GetBrowserCodepage(outputFormat.GetReference(), locale) );
|
|
localVars->AddExtensionControlBlock( outputFormat.GetReference() );
|
|
|
|
ULONG cwc = MAX_PATH;
|
|
BOOL fOK = outputFormat->GetCGI_PATH_TRANSLATED( wcsIDQFile, cwc );
|
|
|
|
if ( !fOK )
|
|
{
|
|
wcsIDQFile[0] = 0;
|
|
THROW( CIDQException( MSG_CI_IDQ_NOT_FOUND, 0 ) );
|
|
}
|
|
|
|
outputFormat->SetCodePage(outputFormat->CodePage());
|
|
|
|
Win4Assert( fOK );
|
|
|
|
if ( IsNetPath(wcsIDQFile) )
|
|
{
|
|
ciGibDebugOut(( DEB_ERROR, "Path for idq file (%ws) is a UNC name\n",
|
|
wcsIDQFile ));
|
|
|
|
THROW( CIDQException(MSG_CI_SCRIPTS_ON_REMOTE_UNC, 0) );
|
|
}
|
|
|
|
CWQueryItem *pItem = 0;
|
|
|
|
//
|
|
// Check to see whether this is an .IDQ or .IDA file.
|
|
//
|
|
|
|
static WCHAR const wszAdmin[] = L".IDA";
|
|
static unsigned const ccAdmin = sizeof(wszAdmin)/sizeof(wszAdmin[0]) - 1;
|
|
|
|
if ( cwc > ccAdmin && 0 == _wcsicmp( wszAdmin, wcsIDQFile + cwc - ccAdmin - 1 ) )
|
|
{
|
|
CVirtualString IDAResults;
|
|
|
|
DoAdmin( wcsIDQFile,
|
|
localVars.GetReference(),
|
|
outputFormat.GetReference(),
|
|
IDAResults );
|
|
|
|
if ( outputFormat->WriteClient( IDAResults ) )
|
|
outputFormat->SetHttpStatus( HTTP_STATUS_OK );
|
|
else
|
|
{
|
|
eErrorClass = eWebServerWriteError;
|
|
outputFormat->SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Atempt to find an existing query using this IDQ file, &
|
|
// sequence number, based on the bookmark received.
|
|
//
|
|
|
|
fPending = FALSE;
|
|
pItem = TheWebQueryCache.CreateOrFindQuery( wcsIDQFile,
|
|
localVars,
|
|
outputFormat,
|
|
securityIdentity,
|
|
fPending );
|
|
|
|
if ( fPending )
|
|
{
|
|
Win4Assert( 0 == pItem );
|
|
}
|
|
else
|
|
{
|
|
TRY
|
|
{
|
|
Win4Assert( !pItem->IsCanonicalOutput() );
|
|
|
|
CVirtualString queryResults( 16384 );
|
|
|
|
//
|
|
// Write the query results to a WCHAR string buffer
|
|
// Initial virtual string size is in WCHARs
|
|
//
|
|
pItem->OutputQueryResults( localVars.GetReference(),
|
|
outputFormat.GetReference(),
|
|
queryResults );
|
|
|
|
//
|
|
// Send the query results to the browser
|
|
//
|
|
if ( outputFormat->WriteClient( queryResults ) )
|
|
outputFormat->SetHttpStatus( HTTP_STATUS_OK );
|
|
else
|
|
{
|
|
eErrorClass = eWebServerWriteError;
|
|
outputFormat->SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
|
|
}
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
eErrorClass = eDefaultISAPIError;
|
|
status = e.GetErrorCode();
|
|
}
|
|
END_CATCH
|
|
}
|
|
}
|
|
|
|
return pItem;
|
|
} //CreateQueryFromRequest
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ReportErrorNoThrow, public
|
|
//
|
|
// Synposis: Attempts to report an error condition and log the query
|
|
//
|
|
// Arguments: [localVars] -- local variables.
|
|
// [eErrorClass] -- error class
|
|
// [status] -- status code of faulure
|
|
// [ulErrorLine] -- line # of the error
|
|
// [wcsErrorFile] -- file associated with error
|
|
// [outputFormat] -- formatting info.
|
|
// [webServer] -- web server for the request.
|
|
//
|
|
// History: 96-Nov-25 dlee created from existing code, added TRY
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void ReportErrorNoThrow(
|
|
XPtr<CVariableSet> & localVars,
|
|
int eErrorClass,
|
|
NTSTATUS status,
|
|
ULONG ulErrorLine,
|
|
WCHAR const * wcsErrorFile,
|
|
XPtr<COutputFormat> & outputFormat,
|
|
CWebServer & webServer )
|
|
{
|
|
TRY
|
|
{
|
|
WCHAR * wcsRestriction = 0;
|
|
|
|
//
|
|
// Lookup the restriction, if one has been fully constructed.
|
|
//
|
|
if ( 0 != localVars.GetPointer() )
|
|
{
|
|
CVariable * pVarRestriction = localVars->Find(ISAPI_CI_RESTRICTION);
|
|
|
|
if ( 0 != pVarRestriction )
|
|
{
|
|
ULONG cwcValue;
|
|
wcsRestriction = pVarRestriction->GetStringValueRAW( outputFormat.GetReference(), cwcValue );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Attempt to write out the error picture, if appropriate
|
|
//
|
|
|
|
CVirtualString vString;
|
|
|
|
GetErrorPageNoThrow( eErrorClass,
|
|
status,
|
|
ulErrorLine,
|
|
wcsErrorFile,
|
|
localVars.GetPointer(),
|
|
outputFormat.GetPointer(),
|
|
outputFormat.GetPointer() ? outputFormat->GetLCID() : 0,
|
|
webServer,
|
|
vString );
|
|
|
|
ciGibDebugOut(( DEB_IWARN, "WARNING: %ws\n", vString.Get() ));
|
|
webServer.WriteClient( vString );
|
|
|
|
Win4Assert( webServer.GetHttpStatus() >= HTTP_STATUS_FIRST );
|
|
|
|
//
|
|
// Log the restriction in the failed query. It may not have
|
|
// been logged yet since we may have thrown before it was
|
|
// logged in the query execution path.
|
|
//
|
|
// if ( 0 != wcsRestriction )
|
|
// webServer.WriteLogData( wcsRestriction );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
// ignore -- not enough memory to output an error message
|
|
}
|
|
END_CATCH
|
|
} //ReportErrorNoThrow
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ReportErrorNoThrow, public
|
|
//
|
|
// Synposis: Attempts to report an error condition and log the query
|
|
//
|
|
// Arguments: [localVars] -- local variables.
|
|
// [scError] -- error code
|
|
// [pwszErrorMessage] -- Description provided by Ole-DB error svc.
|
|
// [outputFormat] -- formatting info.
|
|
// [webServer] -- web server for the request.
|
|
//
|
|
// History: 97-May-08 KrishnaN created from existing ReportErrorNoThrow
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void ReportErrorNoThrow(
|
|
XPtr<CVariableSet> & localVars,
|
|
int eErrorClass,
|
|
SCODE scError,
|
|
WCHAR const * pwszErrorMessage,
|
|
XPtr<COutputFormat> & outputFormat,
|
|
CWebServer & webServer )
|
|
{
|
|
TRY
|
|
{
|
|
WCHAR * wcsRestriction = 0;
|
|
|
|
//
|
|
// Lookup the restriction, if one has been fully constructed.
|
|
//
|
|
if ( 0 != localVars.GetPointer() )
|
|
{
|
|
CVariable * pVarRestriction = localVars->Find(ISAPI_CI_RESTRICTION);
|
|
|
|
if ( 0 != pVarRestriction )
|
|
{
|
|
ULONG cwcValue;
|
|
wcsRestriction = pVarRestriction->GetStringValueRAW( outputFormat.GetReference(), cwcValue );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Attempt to write out the error picture, if appropriate
|
|
//
|
|
|
|
CVirtualString vString;
|
|
|
|
GetErrorPageNoThrow(eErrorClass,
|
|
scError,
|
|
pwszErrorMessage,
|
|
localVars.GetPointer(),
|
|
outputFormat.GetPointer(),
|
|
outputFormat.GetPointer() ? outputFormat->GetLCID() : 0,
|
|
webServer,
|
|
vString );
|
|
|
|
ciGibDebugOut(( DEB_IWARN, "WARNING: %ws\n", vString.Get() ));
|
|
webServer.WriteClient( vString );
|
|
|
|
Win4Assert( webServer.GetHttpStatus() >= HTTP_STATUS_FIRST );
|
|
|
|
//
|
|
// Log the restriction in the failed query. It may not have
|
|
// been logged yet since we may have thrown before it was
|
|
// logged in the query execution path.
|
|
//
|
|
// if ( 0 != wcsRestriction )
|
|
// webServer.WriteLogData( wcsRestriction );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
// ignore -- not enough memory to output an error message
|
|
}
|
|
END_CATCH
|
|
} //ReportErrorNoThrow
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ProcessWebRequest, public
|
|
//
|
|
// Synposis: Issues a query from a request.
|
|
//
|
|
// Arguments: [webServer] -- web server for the request.
|
|
//
|
|
// Returns: The HSE_STATUS code.
|
|
//
|
|
// History: 96-Apr-15 dlee created from existing code
|
|
// 98-Sep-16 KLam Checks for valid method
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD ProcessWebRequest(
|
|
CWebServer & webServer )
|
|
{
|
|
Win4Assert( HTTP_STATUS_ACCEPTED == webServer.GetHttpStatus() );
|
|
|
|
WCHAR wcsIDQFile[MAX_PATH];
|
|
wcsIDQFile[0] = 0;
|
|
CWQueryItem *pItem = 0;
|
|
|
|
XPtr<COutputFormat> outputFormat;
|
|
XPtr<CVariableSet> localVars;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS; // Error code from query
|
|
ULONG ulErrorLine; // Line # in IDQ file error occured
|
|
int eErrorClass; // Type of error, IDQ, HTX, parse, ...
|
|
WCHAR const * wcsErrorFile = 0; // Name of file containing error
|
|
|
|
BOOL fPending = FALSE;
|
|
|
|
//
|
|
// Set the following flag to TRUE if we encounter an error
|
|
// whose description is already available.
|
|
//
|
|
|
|
BOOL fReportErrorWithDescription = FALSE;
|
|
BSTR bstrErrorDescription = 0;
|
|
|
|
//
|
|
// Make sure we have a valid method
|
|
//
|
|
if ( strcmp ( webServer.GetMethod(), "HEAD" ) == 0 )
|
|
{
|
|
//
|
|
// Do not need to execute the query if the client only wants the head
|
|
//
|
|
if ( webServer.WriteHeader() )
|
|
webServer.SetHttpStatus ( HTTP_STATUS_OK );
|
|
else
|
|
{
|
|
eErrorClass = eWebServerWriteError;
|
|
webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
|
|
return HSE_STATUS_ERROR;
|
|
}
|
|
|
|
return HSE_STATUS_SUCCESS;
|
|
}
|
|
// Only support GET and POST for queries
|
|
else if ( strcmp( webServer.GetMethod(), "GET" ) != 0
|
|
&& strcmp ( webServer.GetMethod(), "POST" ) != 0 )
|
|
{
|
|
// HTTP 1.1 Spec determines value of header status string
|
|
if ( webServer.WriteHeader( NULL, "501 Not Implemented" ) )
|
|
webServer.SetHttpStatus ( HTTP_STATUS_NOT_SUPPORTED );
|
|
else
|
|
{
|
|
eErrorClass = eWebServerWriteError;
|
|
webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
|
|
}
|
|
|
|
return HSE_STATUS_ERROR;
|
|
}
|
|
else
|
|
{
|
|
TRY
|
|
{
|
|
pItem = CreateQueryFromRequest( outputFormat,
|
|
localVars,
|
|
wcsIDQFile,
|
|
webServer,
|
|
eErrorClass,
|
|
status,
|
|
fPending );
|
|
}
|
|
CATCH( CPListException, e )
|
|
{
|
|
status = e.GetPListError();
|
|
ulErrorLine = e.GetLine();
|
|
eErrorClass = eIDQPlistError;
|
|
wcsErrorFile = wcsIDQFile;
|
|
Win4Assert( STATUS_SUCCESS != status );
|
|
}
|
|
AND_CATCH( CIDQException, e )
|
|
{
|
|
status = e.GetErrorCode();
|
|
ulErrorLine = e.GetErrorIndex();
|
|
eErrorClass = eIDQParseError;
|
|
wcsErrorFile = wcsIDQFile;
|
|
Win4Assert( STATUS_SUCCESS != status );
|
|
}
|
|
AND_CATCH( CHTXException, e )
|
|
{
|
|
status = e.GetErrorCode();
|
|
ulErrorLine = e.GetErrorIndex();
|
|
eErrorClass = eHTXParseError;
|
|
wcsErrorFile = e.GetHTXFileName();
|
|
|
|
//
|
|
// copy the error file name; it's stored on the stack below
|
|
// this function.
|
|
//
|
|
ULONG cchFileName = min( wcslen(wcsErrorFile) + 1, MAX_PATH );
|
|
Win4Assert(cchFileName < MAX_PATH);
|
|
|
|
RtlCopyMemory( wcsIDQFile,
|
|
wcsErrorFile,
|
|
sizeof(WCHAR) * cchFileName );
|
|
|
|
wcsIDQFile[MAX_PATH-1] = 0;
|
|
wcsErrorFile = wcsIDQFile;
|
|
Win4Assert( STATUS_SUCCESS != status );
|
|
}
|
|
AND_CATCH( CParserException, e )
|
|
{
|
|
status = e.GetParseError();
|
|
ulErrorLine = 0;
|
|
eErrorClass = eRestrictionParseError;
|
|
wcsErrorFile = wcsIDQFile;
|
|
Win4Assert( STATUS_SUCCESS != status );
|
|
}
|
|
AND_CATCH( CPostedOleDBException, e )
|
|
{
|
|
//
|
|
// When the execution error was detected, the Ole DB error
|
|
// info was retrieved and stored in the exception object.
|
|
// We retrieve that here and compose the error message.
|
|
//
|
|
|
|
status = e.GetErrorCode();
|
|
eErrorClass = e.GetErrorClass();
|
|
Win4Assert( STATUS_SUCCESS != status );
|
|
|
|
XInterface <IErrorInfo> xErrorInfo(e.AcquireErrorInfo());
|
|
|
|
if (xErrorInfo.GetPointer())
|
|
xErrorInfo->GetDescription(&bstrErrorDescription);
|
|
if (bstrErrorDescription)
|
|
fReportErrorWithDescription = TRUE;
|
|
else
|
|
{
|
|
// NO description. Follow the normal path.
|
|
ulErrorLine = 0;
|
|
wcsErrorFile = wcsIDQFile;
|
|
}
|
|
}
|
|
AND_CATCH( CException, e )
|
|
{
|
|
status = e.GetErrorCode();
|
|
ulErrorLine = 0;
|
|
eErrorClass = eDefaultISAPIError;
|
|
wcsErrorFile = wcsIDQFile;
|
|
Win4Assert( STATUS_SUCCESS != status );
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
TRY
|
|
{
|
|
if ( STATUS_SUCCESS != status )
|
|
{
|
|
fPending = FALSE;
|
|
|
|
// the request failed, but we're returning an error message,
|
|
// so indicate that everything is ok.
|
|
|
|
webServer.SetHttpStatus( HTTP_STATUS_OK );
|
|
|
|
if (fReportErrorWithDescription)
|
|
{
|
|
Win4Assert(bstrErrorDescription);
|
|
ReportErrorNoThrow(localVars,
|
|
eErrorClass,
|
|
status,
|
|
(WCHAR const *)bstrErrorDescription,
|
|
outputFormat,
|
|
webServer );
|
|
SysFreeString(bstrErrorDescription);
|
|
}
|
|
else
|
|
{
|
|
Win4Assert(0 == bstrErrorDescription);
|
|
ReportErrorNoThrow( localVars,
|
|
eErrorClass,
|
|
status,
|
|
ulErrorLine,
|
|
wcsErrorFile,
|
|
outputFormat,
|
|
webServer );
|
|
}
|
|
|
|
if ( 0 != pItem )
|
|
pItem->Zombify();
|
|
}
|
|
|
|
TheWebQueryCache.Release( pItem );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciGibDebugOut(( DEB_ERROR, "ProcessWebRequest Error 0x%X\n", e.GetErrorCode() ));
|
|
Win4Assert( e.GetErrorCode() != STATUS_ACCESS_VIOLATION );
|
|
}
|
|
END_CATCH
|
|
|
|
#if CIDBG == 1
|
|
|
|
//
|
|
// If fPending is TRUE, the http status of the ecb can't be trusted,
|
|
// because the request may have asynchronously completed by now:
|
|
//
|
|
|
|
if ( !fPending )
|
|
{
|
|
DWORD dwHttpStatus = webServer.GetHttpStatus();
|
|
|
|
Win4Assert( HTTP_STATUS_ACCEPTED != dwHttpStatus );
|
|
Win4Assert( HTTP_STATUS_OK == dwHttpStatus ||
|
|
HTTP_STATUS_SERVER_ERROR == dwHttpStatus ||
|
|
HTTP_STATUS_DENIED == dwHttpStatus ||
|
|
HTTP_STATUS_SERVICE_UNAVAIL == dwHttpStatus );
|
|
}
|
|
|
|
#endif // CIDBG == 1
|
|
|
|
if ( fPending )
|
|
return HSE_STATUS_PENDING;
|
|
|
|
return HSE_STATUS_SUCCESS;
|
|
} //ProcessWebRequest
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HttpExtensionProc, public
|
|
//
|
|
// Synposis: Handles a request from the web server
|
|
//
|
|
// Arguments: [pEcb] -- block from the server
|
|
//
|
|
// History: 96-Apr-15 dlee created header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pEcb )
|
|
{
|
|
if ( 0 == pTheGlobalIDQVariables || fTheActiveXSearchShutdown )
|
|
{
|
|
ciGibDebugOut(( DEB_GIB_REQUEST,
|
|
"Indexing Service being shutdown\n" ));
|
|
pEcb->dwHttpStatusCode = HTTP_STATUS_SERVICE_UNAVAIL;
|
|
return HSE_STATUS_ERROR;
|
|
}
|
|
|
|
CIncomingThread incoming( TheWebResourceArbiter );
|
|
|
|
TheWebQueryCache.IncrementActiveRequests();
|
|
|
|
CWebServer webServer( pEcb );
|
|
DWORD hseStatus = HSE_STATUS_ERROR;
|
|
webServer.SetHttpStatus( HTTP_STATUS_ACCEPTED );
|
|
|
|
TRANSLATE_EXCEPTIONS;
|
|
|
|
TRY
|
|
{
|
|
if ( TheWebResourceArbiter.IsSystemBusy() )
|
|
{
|
|
if ( TheWebQueryCache.AddToPendingRequestQueue( pEcb ) )
|
|
{
|
|
ciGibDebugOut(( DEB_GIB_REQUEST, "Server busy, queueing request\n" ));
|
|
hseStatus = HSE_STATUS_PENDING;
|
|
|
|
TheWebQueryCache.Wakeup();
|
|
TheWebQueryCache.UpdatePendingRequestCount();
|
|
}
|
|
else
|
|
{
|
|
TheWebQueryCache.IncrementRejectedRequests();
|
|
ciGibDebugOut(( DEB_GIB_REQUEST,
|
|
"Server too busy, failing request!!!\n" ));
|
|
ReturnServerError( HTTP_STATUS_SERVICE_UNAVAIL, webServer );
|
|
hseStatus = HSE_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ciGibDebugOut(( DEB_GIB_REQUEST, "Server not busy, processing request\n" ));
|
|
hseStatus = ProcessWebRequest( webServer );
|
|
}
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
hseStatus = HSE_STATUS_ERROR;
|
|
}
|
|
END_CATCH
|
|
|
|
UNTRANSLATE_EXCEPTIONS;
|
|
|
|
if ( HSE_STATUS_PENDING != hseStatus )
|
|
{
|
|
TheWebQueryCache.DecrementActiveRequests();
|
|
|
|
ciGibDebugOut(( DEB_GIB_REQUEST,
|
|
"Falling out of isapi proc, active: %d\n",
|
|
TheWebQueryCache.ActiveRequestCount() ));
|
|
|
|
Win4Assert( webServer.GetHttpStatus() >= HTTP_STATUS_FIRST &&
|
|
webServer.GetHttpStatus() <= HTTP_STATUS_LAST );
|
|
|
|
if ( ( webServer.GetHttpStatus() < HTTP_STATUS_FIRST ) ||
|
|
( webServer.GetHttpStatus() > HTTP_STATUS_LAST ) )
|
|
{
|
|
ciGibDebugOut(( DEB_WARN,
|
|
"non-pending hse %d ECB %08x status invalid: %d\n",
|
|
hseStatus,
|
|
pEcb,
|
|
webServer.GetHttpStatus() ));
|
|
webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The pending request may have asynchronously completed by now,
|
|
// so nothing can be asserted about the http status except that it
|
|
// is a valid http status code, which retrieving the status does.
|
|
//
|
|
|
|
#if CIDBG == 1
|
|
webServer.GetHttpStatus();
|
|
#endif
|
|
}
|
|
|
|
ciGibDebugOut(( DEB_ITRACE, "httpExtensionProc: hse %d, http %d\n",
|
|
hseStatus, webServer.GetHttpStatus() ));
|
|
|
|
return hseStatus;
|
|
} //HttpExtensionProc
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CWebPendingQueue::CWebPendingQueue, public
|
|
//
|
|
// Synposis: Constructs the pending request queue
|
|
//
|
|
// History: 96-Apr-15 dlee created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CWebPendingQueue::CWebPendingQueue()
|
|
: TFifoCircularQueue<CWebPendingItem>
|
|
( TheIDQRegParams.GetISRequestQueueSize() ),
|
|
_ulSignature( LONGSIG( 'p', 'e', 'n', 'd' ) )
|
|
{
|
|
} //CWebPendingQueue
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CWebResourceArbiter::CWebResourceArbiter, public
|
|
//
|
|
// Synposis: Constructs the web resource arbiter
|
|
//
|
|
// History: 96-Apr-15 dlee created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CWebResourceArbiter::CWebResourceArbiter() :
|
|
_ulSignature( LONGSIG( 'a', 'r', 'b', 'i' ) ),
|
|
_cThreads( 0 )
|
|
{
|
|
ULONG factor = TheIDQRegParams.GetISRequestThresholdFactor();
|
|
|
|
Win4Assert( 0 != factor );
|
|
|
|
SYSTEM_INFO si;
|
|
GetSystemInfo( &si );
|
|
|
|
_maxThreads = si.dwNumberOfProcessors * factor;
|
|
|
|
Win4Assert( _maxThreads >= (LONG) factor );
|
|
|
|
_maxPendingQueries = TheIDQRegParams.GetMaxActiveQueryThreads() *
|
|
factor;
|
|
} //CWebResourceArbiter
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CWebResourceArbiter::IsSystemBusy, public
|
|
//
|
|
// Synposis: Determines if the system is too busy to process a request.
|
|
//
|
|
// Returns: TRUE if the request should be queued or rejected, FALSE
|
|
// if the system is free enough to handle it.
|
|
//
|
|
// History: 96-Apr-15 dlee created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CWebResourceArbiter::IsSystemBusy()
|
|
{
|
|
return ( _cThreads > _maxThreads ) ||
|
|
( TheWebQueryCache.PendingQueryCount() >= _maxPendingQueries );
|
|
} //IsSystemBusy
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DllMain
|
|
//
|
|
// Synopsis: Called from C-Runtime on process/thread attach/detach
|
|
//
|
|
// Arguments: [hInstance] -- Module handle
|
|
// [dwReason] -- Reason for being called
|
|
// [lpReserved] --
|
|
//
|
|
// History: 23-Apr-97 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#if CIDBG == 1
|
|
#define VER_CIDEBUG "chk"
|
|
#else // CIDBG == 1
|
|
#define VER_CIDEBUG "fre"
|
|
#endif // CIDBG == 1
|
|
|
|
#if IDQ_VERSION == 3
|
|
#define VER_PROJECT "query"
|
|
#else // IDQ_VERSION != 3
|
|
#define VER_PROJECT "indexsrv"
|
|
#endif // IDQ_VERSION == 3
|
|
|
|
#define MAKELITERALSTRING( s, lit ) s #lit
|
|
#define MAKELITERAL( s, lit ) MAKELITERALSTRING( s, lit )
|
|
|
|
#define VERSION_STRING MAKELITERAL("Indexing Service ", IDQ_VERSION) \
|
|
"(" VER_PROJECT ") " VER_CIDEBUG \
|
|
MAKELITERAL(" built by ", BUILD_USERNAME) \
|
|
MAKELITERAL(" with ", VER_PRODUCTBUILD) \
|
|
" on " __DATE__ " at " __TIME__
|
|
|
|
char g_ciBuild[ ] = VERSION_STRING;
|
|
|
|
|
|
BOOL WINAPI DllMain(
|
|
HANDLE hInstance,
|
|
DWORD dwReason,
|
|
void * lpReserved )
|
|
{
|
|
BOOL fRetval = TRUE;
|
|
TRANSLATE_EXCEPTIONS;
|
|
|
|
TRY
|
|
{
|
|
switch ( dwReason )
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
{
|
|
DisableThreadLibraryCalls( (HINSTANCE) hInstance );
|
|
InitializeCriticalSection( &g_csInitExclusive );
|
|
|
|
break;
|
|
}
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
DeleteCriticalSection( &g_csInitExclusive );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
// About the only thing this could be is STATUS_NO_MEMORY which
|
|
// can be thrown by InitializeCriticalSection.
|
|
|
|
ciGibDebugOut(( DEB_ERROR,
|
|
"IDQ: Exception %#x in DllMain\n",
|
|
e.GetErrorCode()));
|
|
|
|
#if CIDBG == 1 // for debugging NTRAID 340297
|
|
if (e.GetErrorCode() == STATUS_NO_MEMORY)
|
|
DbgPrint( "IDQ: STATUS_NO_MEMORY exception in DllMain\n");
|
|
else
|
|
DbgPrint( "IDQ: ??? Exception in DllMain\n");
|
|
#endif // CIDBG == 1
|
|
|
|
fRetval = FALSE;
|
|
}
|
|
END_CATCH
|
|
|
|
UNTRANSLATE_EXCEPTIONS;
|
|
|
|
return fRetval;
|
|
} //DllMain
|