|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2000.
//
// File: errormsg.cxx
//
// Contents: Error messages for output/running queries
//
// History: 96/Mar/3 DwightKr Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#define ERROR_MESSAGE_SIZE 512
//+---------------------------------------------------------------------------
//
// Function: GetErrorPageNoThrow - public
//
// Synposis: Generates an error page based on the error parameters passed.
//
// Arguments: [eErrorClass] - class of error (IDQ, HTX, restirction, etc)
// [status] - error code generated
// [ulErrorLine] - line on which the error occured
// [wcsErrorFileName] - name of file which generated the error
// [pVariableSet] - replaceable parameters which generated the error
// [pOutputFormat] - format of dates & numbers
// [locale] - locale of the browser
// [webServer] - the web server
// [vString] - virtual string to contain error code
//
// History: 96/Feb/29 DwightKr Created
//
//----------------------------------------------------------------------------
void GetErrorPageNoThrow( int eErrorClass, NTSTATUS status, ULONG ulErrorLine, WCHAR const * wcsErrorFileName, CVariableSet * pVariableSet, COutputFormat * pOutputFormat, LCID locale, CWebServer & webServer, CVirtualString & vString ) { //
// If the error was caused by a failure to WRITE to the web server,
// then don't bother trying to report an error, there is no one to
// receive it.
//
if ( eWebServerWriteError == eErrorClass ) { ciGibDebugOut(( DEB_IWARN, "Failed to write to the web server" ));
return; }
//
// If the error was the result of an access denied problem, then simply
// return a 401 error to the browser
//
WCHAR awcsErrorMessage[ERROR_MESSAGE_SIZE]; WCHAR * pwszErrorMessage = awcsErrorMessage; ULONG cchAvailMessage = ERROR_MESSAGE_SIZE;
//
// Generate the Win32 error code by removing the facility code (7) and
// the error bit.
//
ULONG Win32status = status; if ( (Win32status & (FACILITY_WIN32 << 16)) == (FACILITY_WIN32 << 16) ) { Win32status &= ~( 0x80000000 | (FACILITY_WIN32 << 16) ); }
if ( (STATUS_ACCESS_DENIED == status) || (STATUS_NETWORK_ACCESS_DENIED == status) || (ERROR_ACCESS_DENIED == Win32status) || (ERROR_INVALID_ACCESS == Win32status) || (ERROR_NETWORK_ACCESS_DENIED == Win32status) ) { ciGibDebugOut(( DEB_WARN, "mapping 0x%x to 401 access denied\n", status ));
ReturnServerError( HTTP_STATUS_DENIED, webServer ); return; }
//
// Map special error codes to their message equivalents.
//
if ( QUERY_E_DUPLICATE_OUTPUT_COLUMN == status ) { status = MSG_CI_IDQ_DUPLICATE_COLUMN; } else if ( QUERY_E_INVALID_OUTPUT_COLUMN == status ) { status = MSG_CI_IDQ_NO_SUCH_COLUMN_PROPERTY; }
if ( 0 != wcsErrorFileName ) { WCHAR *p = wcsrchr( wcsErrorFileName, L'\\' ); if ( 0 == p ) p = wcsrchr( wcsErrorFileName, L'/' ); if ( 0 == p ) p = wcsrchr( wcsErrorFileName, L':' );
if ( 0 != p ) wcsErrorFileName = p + 1; }
//
// 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(locale);
switch (eErrorClass) { case eIDQParseError: { //
// These are errors encountered while parsing the IDQ file
//
DWORD_PTR args [] = { (DWORD_PTR) ulErrorLine, (DWORD_PTR) wcsErrorFileName };
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, GetModuleHandle(L"idq.dll"), status, 0, pwszErrorMessage, cchAvailMessage, (va_list *) args ) ) { ciGibDebugOut(( DEB_ERROR, "Format message failed with error 0x%x\n", GetLastError() ));
swprintf( pwszErrorMessage, L"Processing of IDQ file %ls failed with error 0x%x\n", wcsErrorFileName, status ); } } break;
case eIDQPlistError: { //
// These are errors encountered while parsing the [names] section
//
if (wcsErrorFileName != 0) { DWORD_PTR args [] = { (DWORD_PTR) wcsErrorFileName, (DWORD_PTR) ulErrorLine, };
NTSTATUS MsgNum = MSG_IDQ_FILE_MESSAGE; if (ulErrorLine != 0) { MsgNum = MSG_IDQ_FILE_LINE_MESSAGE; }
ULONG cchMsg = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, GetModuleHandle(L"idq.dll"), MsgNum, 0, pwszErrorMessage, cchAvailMessage, (va_list *) args ); pwszErrorMessage += cchMsg; cchAvailMessage -= cchMsg; }
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(L"query.dll"), status, 0, pwszErrorMessage, cchAvailMessage, 0 ) ) { ciGibDebugOut(( DEB_ERROR, "Format message failed with error 0x%x\n", GetLastError() ));
swprintf( pwszErrorMessage, L"Processing of IDQ file [names] failed with error 0x%x\n", status ); } } break;
case eHTXParseError: { //
// These are errors encountered while parsing the IDQ file
//
DWORD_PTR args [] = { (DWORD_PTR) ulErrorLine, (DWORD_PTR) wcsErrorFileName };
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, GetModuleHandle(L"idq.dll"), status, 0, pwszErrorMessage, cchAvailMessage, (va_list *) args ) ) { ciGibDebugOut(( DEB_ERROR, "Format message failed with error 0x%x\n", GetLastError() ));
swprintf( pwszErrorMessage, L"Error 0x%x occured while parsing in HTX file %ls\n", status, wcsErrorFileName ); } } break;
case eRestrictionParseError: { //
// These are errors encountered while parsing the restriction
//
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(L"query.dll"), status, 0, pwszErrorMessage, cchAvailMessage, 0 ) ) { ciGibDebugOut(( DEB_ERROR, "Format message failed with error 0x%x\n", GetLastError() ));
swprintf( pwszErrorMessage, L"Restriction parsing failed with error 0x%x\n", status ); } } break;
default: { //
// All other errors; other major classes of errors are caught above.
//
DWORD_PTR args [] = { (DWORD_PTR) ulErrorLine, (DWORD_PTR) wcsErrorFileName };
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, GetModuleHandle(L"idq.dll"), status, 0, pwszErrorMessage, cchAvailMessage, (va_list *) args ) ) { if (wcsErrorFileName != 0) { NTSTATUS MsgNum = MSG_IDQ_FILE_MESSAGE; args[0] = (DWORD_PTR)wcsErrorFileName; if (ulErrorLine != 0) { args[1] = ulErrorLine; MsgNum = MSG_IDQ_FILE_LINE_MESSAGE; }
ULONG cchMsg = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, GetModuleHandle(L"idq.dll"), MsgNum, 0, pwszErrorMessage, cchAvailMessage, (va_list *) args ); pwszErrorMessage += cchMsg; cchAvailMessage -= cchMsg; }
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(L"query.dll"), status, 0, pwszErrorMessage, cchAvailMessage, 0 ) ) { //
// Try looking up the error in the Win32 list of error codes
//
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(L"kernel32.dll"), Win32status, 0, pwszErrorMessage, cchAvailMessage, 0 ) ) { ciGibDebugOut(( DEB_ERROR, "Format message failed with error 0x%x\n", GetLastError() ));
swprintf( pwszErrorMessage, L"Error 0x%x caught while processing query\n", status ); } } } } break; } SetThreadLocale(SaveLCID);
BOOL fCaughtException = FALSE;
//
// Try to bind to language object by looking up registry and get
// the error message HTX file associated with this class of error.
//
TRY { CWebLangLocator langreg( locale );
WCHAR * wcsErrorFile = 0;
if ( langreg.LocaleFound() ) { //
// If the locale was found in the registry, get the error message
// file associated with this language.
//
switch (eErrorClass) { case eIDQParseError: case eIDQPlistError: wcsErrorFile = langreg.GetIDQErrorFile(); break;
case eHTXParseError: wcsErrorFile = langreg.GetHTXErrorFile(); break;
case eRestrictionParseError: wcsErrorFile = langreg.GetRestrictionErrorFile(); break;
default: wcsErrorFile = langreg.GetDefaultErrorFile(); break; } }
if ( ( 0 != pVariableSet ) && ( 0 != pOutputFormat ) && ( 0 != wcsErrorFile ) && ( wcslen(wcsErrorFile) > 0 ) ) { //
// Set CiErrorMessage and CiErrorNumber.
//
// The variables won't own the memory for the strings;
// the pointers will be reset later.
//
PROPVARIANT propVariant; propVariant.vt = VT_LPWSTR; propVariant.pwszVal = awcsErrorMessage;
pVariableSet->SetVariable( ISAPI_CI_ERROR_MESSAGE, &propVariant, 0 );
WCHAR achErrorNumber[11]; swprintf( achErrorNumber, L"0x%8x", status );
propVariant.pwszVal = achErrorNumber; pVariableSet->SetVariable( ISAPI_CI_ERROR_NUMBER, &propVariant, 0 );
WCHAR wcsPhysicalPath[_MAX_PATH]; ULONG cwcVirtualPath = wcslen(wcsErrorFile) + 1;
XPtrST<WCHAR> wcsVirtualPath( new WCHAR[cwcVirtualPath] );
//
// We could have a virtual root or a physical root
// All virtual roots begin with a "/".
//
if (wcsErrorFile[0] == L'/') { //
// Ask the web server to convert the virtual path to our error
// message file to a physical path.
//
webServer.GetPhysicalPath( wcsErrorFile, wcsPhysicalPath, _MAX_PATH ); RtlCopyMemory( wcsVirtualPath.GetPointer(), wcsErrorFile, cwcVirtualPath*sizeof(WCHAR) ); } else { // simply copy the path to physical path. It has to be a physical
// path. If not, it will result in an error later.
wcscpy(wcsPhysicalPath, wcsErrorFile); }
CSecurityIdentity securityStub;
CHTXFile htxFile( wcsVirtualPath, pOutputFormat->CodePage(), securityStub, pOutputFormat->GetServerInstance() );
ciGibDebugOut((DEB_ITRACE, "File is: %ws\n", wcsPhysicalPath)); htxFile.ParseFile( wcsPhysicalPath, *pVariableSet, webServer ); htxFile.GetHeader( vString, *pVariableSet, *pOutputFormat ); } else { vString.StrCat( L"<HTML>" ); HTMLEscapeW( awcsErrorMessage, vString, pOutputFormat->CodePage() ); } } CATCH ( CException, e ) { fCaughtException = TRUE; } END_CATCH
TRY { // Extending the vstring can fail
if ( fCaughtException ) { vString.StrCat( L"<HTML>" ); HTMLEscapeW( awcsErrorMessage, vString, pOutputFormat->CodePage() ); }
// These can fail if the variable wasn't set above
if ( pVariableSet ) { PROPVARIANT propVariant; propVariant.vt = VT_EMPTY;
pVariableSet->SetVariable( ISAPI_CI_ERROR_MESSAGE, &propVariant, 0 ); pVariableSet->SetVariable( ISAPI_CI_ERROR_NUMBER, &propVariant, 0 ); } } CATCH ( CException, e ) { // give up
} END_CATCH } //GetErrorPageNoThrow
//+---------------------------------------------------------------------------
//
// Function: GetErrorPageNoThrow - public
//
// Synposis: Generates an error page based on the error parameters passed.
// The error description is already available.
//
// Arguments: [scError] - error SCODE generated
// [pwszErrorMessage] - description provided by ole-db error mechanism
// [pVariableSet] - replaceable parameters which generated the error
// [pOutputFormat] - format of dates & numbers
// [locale] - locale of the browser
// [webServer] - the web server
// [vString] - virtual string to contain error code
//
// History: 08-May-97 KrishnaN Created
//
//----------------------------------------------------------------------------
void GetErrorPageNoThrow( int eErrorClass, SCODE scError, WCHAR const * pwszErrorMessage, CVariableSet * pVariableSet, COutputFormat * pOutputFormat, LCID locale, CWebServer & webServer, CVirtualString & vString ) { BOOL fCaughtException = FALSE;
//
// Try to bind to language object by looking up registry and get
// the error message HTX file associated with this class of error.
//
TRY { //
// If the error was the result of an access denied problem, then simply
// return a 401 error to the browser
//
//
// Generate the Win32 error code by removing the facility code (7) and
// the error bit.
//
ULONG Win32status = scError; if ( (Win32status & (FACILITY_WIN32 << 16)) == (FACILITY_WIN32 << 16) ) { Win32status &= ~( 0x80000000 | (FACILITY_WIN32 << 16) ); }
if ( (STATUS_ACCESS_DENIED == scError) || (STATUS_NETWORK_ACCESS_DENIED == scError) || (ERROR_ACCESS_DENIED == Win32status) || (ERROR_INVALID_ACCESS == Win32status) || (ERROR_NETWORK_ACCESS_DENIED == Win32status) ) { ciGibDebugOut(( DEB_WARN, "mapping 0x%x to 401 access denied\n", scError ));
ReturnServerError( HTTP_STATUS_DENIED, webServer ); return; }
CWebLangLocator langreg( locale );
WCHAR * wcsErrorFile = 0;
if ( langreg.LocaleFound() ) { //
// If the locale was found in the registry, get the error message
// file associated with this language.
//
switch (eErrorClass) { case eIDQParseError: case eIDQPlistError: wcsErrorFile = langreg.GetIDQErrorFile(); break;
case eHTXParseError: wcsErrorFile = langreg.GetHTXErrorFile(); break;
case eRestrictionParseError: wcsErrorFile = langreg.GetRestrictionErrorFile(); break;
default: wcsErrorFile = langreg.GetDefaultErrorFile(); break; } }
if ( ( 0 != pVariableSet ) && ( 0 != pOutputFormat ) && ( 0 != wcsErrorFile ) && ( wcslen(wcsErrorFile) > 0 ) ) { //
// Set CiErrorMessage and CiErrorNumber.
//
// The variables won't own the memory for the strings;
// the pointers will be reset later.
//
PROPVARIANT propVariant; propVariant.vt = VT_LPWSTR; propVariant.pwszVal = (LPWSTR)pwszErrorMessage;
pVariableSet->SetVariable( ISAPI_CI_ERROR_MESSAGE, &propVariant, 0 );
WCHAR achErrorNumber[11]; swprintf( achErrorNumber, L"0x%8x", scError );
propVariant.pwszVal = achErrorNumber; pVariableSet->SetVariable( ISAPI_CI_ERROR_NUMBER, &propVariant, 0 );
WCHAR wcsPhysicalPath[_MAX_PATH]; ULONG cwcVirtualPath = wcslen(wcsErrorFile) + 1;
XPtrST<WCHAR> wcsVirtualPath( new WCHAR[cwcVirtualPath] );
//
// We could have a virtual root or a physical root
// All virtual roots begin with a "/".
//
if (wcsErrorFile[0] == L'/') { //
// Ask the web server to convert the virtual path to our error
// message file to a physical path.
//
webServer.GetPhysicalPath( wcsErrorFile, wcsPhysicalPath, _MAX_PATH ); RtlCopyMemory( wcsVirtualPath.GetPointer(), wcsErrorFile, cwcVirtualPath*sizeof(WCHAR) ); } else { // simply copy the path to physical path. It has to be a physical
// path. If not, it will result in an error later.
wcscpy(wcsPhysicalPath, wcsErrorFile); }
CSecurityIdentity securityStub;
CHTXFile htxFile( wcsVirtualPath, pOutputFormat->CodePage(), securityStub, pOutputFormat->GetServerInstance() );
ciGibDebugOut((DEB_ITRACE, "File is: %ws\n", wcsPhysicalPath)); htxFile.ParseFile( wcsPhysicalPath, *pVariableSet, webServer ); htxFile.GetHeader( vString, *pVariableSet, *pOutputFormat ); } else { vString.StrCat( L"<HTML>" ); vString.StrCat( pwszErrorMessage ); } } CATCH ( CException, e ) { fCaughtException = TRUE; } END_CATCH
TRY { // Extending the vstring can fail
if ( fCaughtException ) { vString.StrCat( L"<HTML>" ); vString.StrCat( pwszErrorMessage ); }
// These can fail if the variable wasn't set above
if ( pVariableSet ) { PROPVARIANT propVariant; propVariant.vt = VT_EMPTY;
pVariableSet->SetVariable( ISAPI_CI_ERROR_MESSAGE, &propVariant, 0 ); pVariableSet->SetVariable( ISAPI_CI_ERROR_NUMBER, &propVariant, 0 ); } } CATCH ( CException, e ) { // give up
} END_CATCH } //GetErrorPageNoThrow
enum { eAccessDeniedMsg = 0, eServerBusyMsg, eServerErrorMsg, };
#define MAX_SERVER_ERROR_MSGSIZE 100
WCHAR g_awszServerErrorMsgs [3] [MAX_SERVER_ERROR_MSGSIZE] = { L"Access denied.\r\n", L"Server too busy.\r\n", L"Unexpected server error.\r\n", };
//+---------------------------------------------------------------------------
//
// Function: ReturnServerError - public
//
// Synposis: Generates an error page for an HTTP error code.
//
// Arguments: [httpError] - the HTTP status code
// [webServer] - the web server
//
// Notes: This is used when the server is too busy; it should be a
// very low-overhead path.
//
// History: 12 Aug 1997 AlanW Created
//
//----------------------------------------------------------------------------
void ReturnServerError( ULONG httpError, CWebServer & webServer ) { char const * pszHeader = ""; int iMessage = 0;
switch (httpError) { case HTTP_STATUS_DENIED: pszHeader = "401 Access denied"; iMessage = eAccessDeniedMsg; break;
case HTTP_STATUS_SERVICE_UNAVAIL: pszHeader = "503 Server busy"; iMessage = eServerBusyMsg; break;
default: ciGibDebugOut(( DEB_ERROR, "unexpected server error status %d\n", httpError )); httpError = HTTP_STATUS_SERVER_ERROR; iMessage = eServerErrorMsg; break; }
webServer.WriteHeader( 0, pszHeader );
WCHAR * pwszMessage = g_awszServerErrorMsgs[iMessage]; webServer.WriteClient( pwszMessage ); webServer.SetHttpStatus( httpError ); }
//+---------------------------------------------------------------------------
//
// Function: LoadServerErrors - public
//
// Synposis: Load messages for server errors.
//
// Arguments: -NONE-
//
// Notes:
//
// History: 29 Sep 1997 AlanW Created
//
//----------------------------------------------------------------------------
void LoadServerErrors( ) { unsigned iMessage = eAccessDeniedMsg; SCODE scMessage = MSG_CI_ACCESS_DENIED; const unsigned cMessages = sizeof g_awszServerErrorMsgs / sizeof g_awszServerErrorMsgs[0];
while (iMessage < cMessages) { FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(L"idq.dll"), scMessage, GetSystemDefaultLangID(), &g_awszServerErrorMsgs [iMessage][0], MAX_SERVER_ERROR_MSGSIZE, 0 ); scMessage++; iMessage++; } }
|