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

803 lines
25 KiB
C++

//+---------------------------------------------------------------------------
//
// 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++;
}
}