//+--------------------------------------------------------------------------- // // 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 #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 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"" ); HTMLEscapeW( awcsErrorMessage, vString, pOutputFormat->CodePage() ); } } CATCH ( CException, e ) { fCaughtException = TRUE; } END_CATCH TRY { // Extending the vstring can fail if ( fCaughtException ) { vString.StrCat( L"" ); 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 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"" ); vString.StrCat( pwszErrorMessage ); } } CATCH ( CException, e ) { fCaughtException = TRUE; } END_CATCH TRY { // Extending the vstring can fail if ( fCaughtException ) { vString.StrCat( L"" ); 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++; } }