Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1580 lines
37 KiB

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
main.cxx
Abstract:
This is the HTTP ODBC gateway
Author:
John Ludeman (johnl) 20-Feb-1995
Revision History:
Tamas Nemeth (t-tamasn) 12-Jun-1998
--*/
//
// System include files.
//
#include "precomp.hxx"
#include "iadmw.h"
#include <ole2.h>
#include <lmcons.h>
DECLARE_DEBUG_PRINTS_OBJECT();
DECLARE_DEBUG_VARIABLE();
#ifndef ARRAYSIZE
#define ARRAYSIZE(_a) (sizeof((_a))/sizeof(*(_a)))
#endif
extern "C" {
BOOL
WINAPI
DllMain(
HINSTANCE hDll,
DWORD dwReason,
LPVOID lpvReserved
);
}
//
// Globals
//
IMSAdminBase * g_pMetabase = NULL;
//
// Is this system DBCS?
//
BOOL g_fIsSystemDBCS;
//
// Prototypes
//
HRESULT
ODBCInitialize(
VOID
);
VOID
ODBCTerminate(
VOID
);
HRESULT
DoQuery(
EXTENSION_CONTROL_BLOCK * pecb,
const CHAR * pszQueryFile,
const CHAR * pszParamList,
STRA * pstrError,
int nCharset,
BOOL * pfAccessDenied
);
DWORD
OdbcExtensionOutput(
EXTENSION_CONTROL_BLOCK * pecb,
const CHAR * pchOutput,
DWORD cbOutput
);
BOOL
OdbcExtensionHeader(
EXTENSION_CONTROL_BLOCK * pecb,
const CHAR * pchStatus,
const CHAR * pchHeaders
);
BOOL LookupHttpSymbols( // eliminated, check its functionality
const CHAR * pszSymbolName,
STRA * pstrSymbolValue
);
HRESULT
GetIDCCharset(
CONST CHAR * pszPath,
int * pnCharset,
STRA * pstrError
);
HRESULT
ConvertUrlEncodedStringToSJIS(
int nCharset,
STRA * pstrParams
);
BOOL
IsSystemDBCS(
VOID
);
CHAR *
FlipSlashes(
CHAR * pszPath
);
HRESULT
GetPoolIDCTimeout(
unsigned char * szMdPath,
DWORD * pdwPoolIDCTimeout
);
HRESULT
SendCustomError(
EXTENSION_CONTROL_BLOCK *pecb,
const CHAR *pszStatus
);
VOID WINAPI
CustomErrorCompletion(
EXTENSION_CONTROL_BLOCK *pECB,
PVOID pContext,
DWORD cbIO,
DWORD dwError
);
HRESULT
SendErrorResponse(
EXTENSION_CONTROL_BLOCK *pecb,
const CHAR *pszStatus,
DWORD dwResID,
const CHAR *pszParam
);
HRESULT
SendErrorResponseFromHr(
EXTENSION_CONTROL_BLOCK *pecb,
const CHAR *pszStatus,
DWORD dwResID,
HRESULT hrError
);
static const CHAR c_sz500InternalServerError[] = "500 Internal Server Error";
DWORD
HttpExtensionProc(
EXTENSION_CONTROL_BLOCK * pecb
)
{
STACK_STRA( strPath, MAX_PATH);
STACK_STRA( strParams, MAX_PATH);
STRA strError;
CHAR * pch;
DWORD cch;
int nCharset;
HRESULT hr;
//
// Make sure ODBC is loaded
//
if ( !LoadODBC() )
{
hr = SendErrorResponse( pecb,
"500 Unable to load ODBC",
ODBCMSG_CANT_LOAD_ODBC,
NULL);
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_ERROR;
}
//
// We currently only support the GET and POST methods
//
if ( !strcmp( pecb->lpszMethod, "POST" ))
{
if ( _stricmp( pecb->lpszContentType,
"application/x-www-form-urlencoded" ) )
{
// Try to send custom error
hr = SendCustomError( pecb, "400 Bad Request" );
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_PENDING;
}
//
// The query params are in the extra data, add a few bytes in
// case we need to double "'"
//
hr = strParams.Resize( pecb->cbAvailable + sizeof(TCHAR) + 3);
if ( SUCCEEDED( hr ) )
{
hr = strParams.Copy( ( const char * ) pecb->lpbData,
pecb->cbAvailable );
}
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error resizing param buffer, hr = 0x%x.\n",
hr ));
hr = SendErrorResponseFromHr( pecb,
"500 Error performing Query",
ODBCMSG_ERROR_PERFORMING_QUERY,
hr);
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_ERROR;
}
}
else if ( !strcmp( pecb->lpszMethod, "GET" ) )
{
hr = strParams.Copy( pecb->lpszQueryString );
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error copying params, hr = 0x%x.\n",
hr ));
hr = SendErrorResponseFromHr( pecb,
"500 Error performing Query",
ODBCMSG_ERROR_PERFORMING_QUERY,
hr);
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_ERROR;
}
}
else
{
// Try to send custom error
hr = SendCustomError( pecb, "400 Method Not Allowed" );
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_PENDING;
}
//
// "Charset" field is enabled for CP932 (Japanese) only in
// this version.
//
if ( 932 != GetACP() )
{
nCharset = CODE_ONLY_SBCS;
}
else
{
//
// Get the charset from .idc file
//
hr = GetIDCCharset( pecb->lpszPathTranslated,
&nCharset,
&strError );
if ( FAILED( hr ) )
{
// If the file was not found
if ( ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) ) ||
( hr == HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) ) ||
( hr == HRESULT_FROM_WIN32( ERROR_INVALID_NAME ) ) )
{
// Try to send custom error
hr = SendCustomError( pecb, "404 Not Found" );
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_PENDING;
}
hr = SendErrorResponse( pecb,
"500 Error performing Query",
ODBCMSG_ERROR_PERFORMING_QUERY,
strError.QueryStr() );
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_ERROR;
}
if ( strParams.QueryCB() )
{
if ( CODE_ONLY_SBCS != nCharset )
{
//
// Convert the charset of Parameters to SJIS
//
hr = ConvertUrlEncodedStringToSJIS( nCharset,
&strParams );
if ( FAILED( hr ) )
{
hr = SendErrorResponseFromHr( pecb,
"500 Error performing Query",
ODBCMSG_ERROR_PERFORMING_QUERY,
hr);
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_ERROR;
}
}
}
}
//
// Walk the parameter string to do two things:
//
// 1) Remove escaped '\n's so we don't break parameter parsing
// later on
// 2) Replace all '&' parameter delimiters with real '\n' so
// escaped '&'s won't get confused later on
//
pch = strParams.QueryStr();
cch = strParams.QueryCCH();
while ( *pch )
{
switch ( *pch )
{
case '%':
if ( pch[1] == '0' && toupper(pch[2]) == 'A' )
{
pch[1] = '2';
pch[2] = '0';
}
pch += 3;
break;
case '&':
*pch = '\n';
pch++;
break;
default:
pch++;
}
}
//
// The path info contains the location of the query file
//
hr = strPath.Copy( pecb->lpszPathTranslated );
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error copying query file path, hr = 0x%x.\n",
hr ));
hr = SendErrorResponseFromHr( pecb,
"500 Error performing Query",
ODBCMSG_ERROR_PERFORMING_QUERY,
hr);
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_ERROR;
}
FlipSlashes( strPath.QueryStr() );
//
// Attempt the query
//
BOOL fAccessDenied = FALSE;
hr = DoQuery( pecb,
strPath.QueryStr(),
strParams.QueryStr(),
&strError,
nCharset,
&fAccessDenied );
if ( FAILED( hr ) )
{
// If the file was not found
if ( ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) ) ||
( hr == HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) ) ||
( hr == HRESULT_FROM_WIN32( ERROR_INVALID_NAME ) ) )
{
// Try to send custom error
hr = SendCustomError( pecb, "404 Not Found" );
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_PENDING;
}
if ( fAccessDenied )
{
// Try to send custom error
hr = SendCustomError( pecb, "401 Unauthorized" );
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_PENDING;
}
else
{
hr = SendErrorResponse( pecb,
"500 Error performing Query",
ODBCMSG_ERROR_PERFORMING_QUERY,
strError.QueryStr() );
if ( FAILED( hr ) )
{
goto FatalError;
}
return HSE_STATUS_ERROR;
}
}
return HSE_STATUS_SUCCESS;
FatalError:
pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER,
(VOID*)c_sz500InternalServerError,
NULL,
NULL );
return HSE_STATUS_ERROR;
}
HRESULT
DoQuery(
EXTENSION_CONTROL_BLOCK * pecb,
const CHAR * pszQueryFile,
const CHAR * pszParamList,
STRA * pstrError,
int nCharset,
BOOL * pfAccessDenied
)
/*++
Routine Description:
Performs the actual query or retrieves the same query from the
query cache
Arguments:
pecb - Extension context
pTsvcInfo - Server info class
pszQueryFile - .wdg file to use for query
pszParamList - Client supplied param list
pstrError - Error text to return errors in
pfAccessDenied - Set to TRUE if the user was denied access
Return Value:
HRESULT
--*/
{
HRESULT hr;
ODBC_REQ * podbcreq;
STACK_STRA( strHeaders, MAX_PATH );
CHAR achInstanceMetaPath[ MAX_PATH ];
DWORD dwInstanceMetaPath =
sizeof( achInstanceMetaPath );
CHAR achURL[ MAX_PATH ];
DWORD dwURL = sizeof( achURL );
STACK_STRA( strMetaPath, MAX_PATH );
DWORD dwPoolIDCTimeout;
//
// Get the metapath for the current request
//
if( !pecb->GetServerVariable( pecb->ConnID,
"INSTANCE_META_PATH",
achInstanceMetaPath,
&dwInstanceMetaPath ) ||
!pecb->GetServerVariable( pecb->ConnID,
"URL",
achURL,
&dwURL ) )
{
return E_FAIL;
}
hr = strMetaPath.Copy( achInstanceMetaPath, dwInstanceMetaPath - 1 );
if( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error copying InstanceMetaPath, hr = 0x%x.\n",
hr ));
return hr;
}
hr = strMetaPath.Append( "/Root" );
if( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error appending metapath, hr = 0x%x.\n",
hr ));
return hr;
}
hr = strMetaPath.Append( achURL, dwURL - 1 );
if( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error appending URL, hr = 0x%x.\n",
hr ));
return hr;
}
//
// Get the HTTPODBC metadata PoolIDCTimeout
//
hr = GetPoolIDCTimeout( ( unsigned char * )strMetaPath.QueryStr(),
&dwPoolIDCTimeout );
if( FAILED( hr ) )
{
dwPoolIDCTimeout = IDC_POOL_TIMEOUT;
}
//
// Create an odbc request as we will either use it for the query
// or as the key for the cache lookup
//
podbcreq = new ODBC_REQ( pecb,
dwPoolIDCTimeout,
nCharset );
if( !podbcreq )
{
pstrError->LoadString( ERROR_NOT_ENOUGH_MEMORY );
return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
}
hr = podbcreq->Create( pszQueryFile, pszParamList );
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error creating ODBC_REQ object, hr = 0x%x.\n",
hr ));
// Best effort
pstrError->LoadString( GetLastError() );
delete podbcreq;
podbcreq = NULL;
return hr;
}
//
// Check to see if user already authentified
//
CHAR achLoggedOnUser[UNLEN + 1];
DWORD dwLoggedOnUser = sizeof( achLoggedOnUser );
BOOL fIsAuth = pecb->GetServerVariable( (HCONN)pecb->ConnID,
"LOGON_USER",
achLoggedOnUser,
&dwLoggedOnUser ) &&
achLoggedOnUser[0] != '\0';
//
// Check to see if the client specified "Pragma: no-cache"
//
/* We don't do cache on HTTPODBC any more
if ( pecb->GetServerVariable( pecb->ConnID,
"HTTP_PRAGMA",
achPragmas,
&cbPragmas ))
{
CHAR * pch;
//
// Look for "no-cache"
//
pch = _strupr( achPragmas );
while ( pch = strchr( pch, 'N' ))
{
if ( !memcmp( pch, "NO-CACHE", 8 ))
{
fRetrieveFromCache = FALSE;
goto Found;
}
pch++;
}
}*/
//
// Open the query file and do the query
//
hr = podbcreq->OpenQueryFile( pfAccessDenied );
if( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error opening query file, hr = 0x%x.\n",
hr ));
goto Exit;
}
hr = podbcreq->ParseAndQuery( achLoggedOnUser );
if( FAILED( hr ) )
{
goto Exit;
}
hr = podbcreq->AppendHeaders( &strHeaders );
if( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error appending headers, hr = 0x%x.\n",
hr ));
goto Exit;
}
hr = podbcreq->OutputResults( (ODBC_REQ_CALLBACK)OdbcExtensionOutput,
pecb, &strHeaders,
(ODBC_REQ_HEADER)OdbcExtensionHeader,
fIsAuth,
pfAccessDenied );
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error in OutputResults(), hr = 0x%x.\n",
hr ));
goto Exit;
}
delete podbcreq;
podbcreq = NULL;
return S_OK;
Exit:
//
// Get the ODBC error to report to client
//
podbcreq->GetLastErrorText( pstrError );
delete podbcreq;
podbcreq = NULL;
return hr;
}
DWORD
OdbcExtensionOutput(
EXTENSION_CONTROL_BLOCK * pecb,
const CHAR * pchOutput,
DWORD cbOutput
)
{
if ( !pecb->WriteClient( pecb->ConnID,
(VOID *) pchOutput,
&cbOutput,
0 ))
{
return GetLastError();
}
return NO_ERROR;
}
BOOL
OdbcExtensionHeader(
EXTENSION_CONTROL_BLOCK * pecb,
const CHAR * pchStatus,
const CHAR * pchHeaders
)
{
return pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER,
(LPDWORD) "200 OK",
NULL,
(LPDWORD) pchHeaders );
}
BOOL
WINAPI
DllMain(
HINSTANCE hDll,
DWORD dwReason,
LPVOID lpvReserved
)
{
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
CREATE_DEBUG_PRINT_OBJECT( "httpodbc.dll");
SET_DEBUG_FLAGS( 0 );
DisableThreadLibraryCalls( hDll );
break;
case DLL_PROCESS_DETACH:
DELETE_DEBUG_PRINT_OBJECT();
break;
default:
break;
}
return TRUE;
}
BOOL
GetExtensionVersion(
HSE_VERSION_INFO * pver
)
{
HRESULT hr;
pver->dwExtensionVersion = MAKELONG( 0, 3 );
strcpy( pver->lpszExtensionDesc,
"Microsoft HTTP ODBC Gateway, v3.0" );
hr = ODBCInitialize();
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error on HTTPODBC initialization." ));
SetLastError( hr );
return FALSE;
}
hr = CoCreateInstance(
CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void**)&g_pMetabase
);
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error getting IMSAdminBase interface." ));
SetLastError( hr );
ODBCTerminate();
return FALSE;
}
return TRUE;
}
BOOL
TerminateExtension(
DWORD dwFlags
)
{
ODBCTerminate();
if ( g_pMetabase )
{
g_pMetabase->Release();
g_pMetabase = NULL;
}
return TRUE;
}
HRESULT
ODBCInitialize(
VOID
)
{
HRESULT hr = E_FAIL;
HKEY hKey;
if( !InitializeOdbcPool() )
{
return hr;
}
hr = ODBC_REQ::Initialize();
if( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error initializing ODBC_REQ, hr = 0x%x.\n",
hr ));
TerminateOdbcPool();
return hr;
}
hr = ODBC_STATEMENT::Initialize();
if( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error initializing ODBC_STATEMENT, hr = 0x%x.\n",
hr ));
TerminateOdbcPool();
ODBC_REQ::Terminate();
return hr;
}
hr = ODBC_CONN_POOL::Initialize();
if( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error initializing ODBC_CONN_POOL, hr = 0x%x.\n",
hr ));
TerminateOdbcPool();
ODBC_REQ::Terminate();
ODBC_STATEMENT::Terminate();
return hr;
}
g_fIsSystemDBCS = IsSystemDBCS();
return hr;
}
VOID
ODBCTerminate(
VOID
)
{
TerminateOdbcPool();
ODBC_REQ::Terminate();
ODBC_STATEMENT::Terminate();
ODBC_CONN_POOL::Terminate();
}
CHAR * skipwhite( CHAR * pch )
{
CHAR ch;
while ( 0 != (ch = *pch) )
{
if ( ' ' != ch && '\t' != ch )
break;
++pch;
}
return pch;
}
CHAR * nextline( CHAR * pch )
{
CHAR ch;
while ( 0 != (ch = *pch) )
{
++pch;
if ( '\n' == ch )
{
break;
}
}
return pch;
}
HRESULT
GetIDCCharset(
CONST CHAR * pszPath,
int * pnCharset,
STRA * pstrError
)
{
BUFFER buff;
HANDLE hFile;
DWORD dwSize;
DWORD dwErr;
#define QUERYFILE_READSIZE 4096
if ( (!pnCharset) || (!pszPath) )
{
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
}
*pnCharset = CODE_ONLY_SBCS;
if ( !buff.Resize( QUERYFILE_READSIZE + sizeof(TCHAR) ) )
{
pstrError->LoadString( ERROR_NOT_ENOUGH_MEMORY );
return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
}
hFile = CreateFileA( pszPath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_SEQUENTIAL_SCAN,
NULL );
if ( ( INVALID_HANDLE_VALUE == hFile ) ||
( NULL == hFile ) )
{
LPCSTR apsz[1];
DBGPRINTF(( DBG_CONTEXT,
"Error opening query file, hr = 0x%x.\n",
HRESULT_FROM_WIN32( GetLastError() )
));
apsz[0] = pszPath;
pstrError->FormatString( ODBCMSG_QUERY_FILE_NOT_FOUND,
apsz,
IIS_RESOURCE_DLL_NAME_A );
return HRESULT_FROM_WIN32( GetLastError() );
}
if ( !ReadFile( hFile,
buff.QueryPtr(),
QUERYFILE_READSIZE,
&dwSize,
NULL ) )
{
dwErr = GetLastError();
pstrError->LoadString( dwErr );
CloseHandle( hFile );
return HRESULT_FROM_WIN32( dwErr );
}
CloseHandle( hFile );
*((CHAR *) buff.QueryPtr() + dwSize) = '\0';
CHAR * pch = (CHAR *)buff.QueryPtr();
while ( *pch )
{
pch = skipwhite( pch );
if ( 'C' == toupper( *pch ) &&
!_strnicmp( IDC_FIELDNAME_CHARSET,
pch,
sizeof(IDC_FIELDNAME_CHARSET)-1 ) )
{
pch += sizeof(IDC_FIELDNAME_CHARSET) - 1;
pch = skipwhite( pch );
if ( 932 == GetACP() )
{
if ( !_strnicmp( IDC_CHARSET_JIS1,
pch,
sizeof(IDC_CHARSET_JIS1)-1 ) ||
!_strnicmp( IDC_CHARSET_JIS2,
pch,
sizeof(IDC_CHARSET_JIS2)-1 ) )
{
*pnCharset = CODE_JPN_JIS;
break;
}
else if ( !_strnicmp( IDC_CHARSET_EUCJP,
pch,
sizeof(IDC_CHARSET_EUCJP)-1 ) )
{
*pnCharset = CODE_JPN_EUC;
break;
}
else if ( !_strnicmp( IDC_CHARSET_SJIS,
pch,
sizeof(IDC_CHARSET_SJIS)-1 ) )
{
*pnCharset = CODE_ONLY_SBCS;
break;
}
else
{
LPCSTR apsz[1];
//
// illegal value for Charset: field
//
apsz[0] = pszPath;
pstrError->FormatString( ODBCMSG_UNREC_FIELD,
apsz,
IIS_RESOURCE_DLL_NAME_A );
return E_FAIL;
}
}
//
// please add code here to support other FE character encoding(FEFEFE)
//
// else if ( 949 == GetACP() )
// ...
}
pch = nextline( pch );
}
return S_OK;
}
HRESULT
ConvertUrlEncodedStringToSJIS(
int nCharset,
STRA * pstrParams
)
{
STACK_STRA( strTemp, MAX_PATH);
int cbSJISSize;
int nResult;
HRESULT hr;
//
// Pre-process the URL encoded parameters
//
for ( char * pch = pstrParams->QueryStr(); *pch; ++pch )
{
if ( *pch == '&' )
{
*pch = '\n';
}
else if ( *pch == '+' )
{
*pch = ' ';
}
}
//
// URL decoding (decode %nn only)
//
hr = pstrParams->Unescape();
if( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error unescaping param string, hr = 0x%x.\n",
hr ));
return hr;
}
//
// charset conversion
//
hr = pstrParams->Clone( &strTemp );
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error cloning param string, hr = 0x%x.\n",
hr ));
return hr;
}
hr = strTemp.Copy( pstrParams->QueryStr() );
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error copying param string, hr = 0x%x.\n",
hr ));
return hr;
}
cbSJISSize = UNIX_to_PC( GetACP(),
nCharset,
(UCHAR *)strTemp.QueryStr(),
strTemp.QueryCB(),
NULL,
0 );
hr = pstrParams->Resize( cbSJISSize + sizeof(TCHAR) );
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error resizing param string buffer, hr = 0x%x.\n",
hr ));
return hr;
}
nResult = UNIX_to_PC( GetACP(),
nCharset,
(UCHAR *)strTemp.QueryStr(),
strTemp.QueryCB(),
(UCHAR *)pstrParams->QueryStr(),
cbSJISSize );
if ( -1 == nResult || nResult != cbSJISSize )
{
return E_FAIL;
}
DBG_REQUIRE ( pstrParams->SetLen( cbSJISSize) );
//
// URL encoding
//
hr = pstrParams->Escape();
if ( FAILED( hr ) )
{
DBGPRINTF(( DBG_CONTEXT,
"Error escaping param string, hr = 0x%x.\n",
hr ));
return hr;
}
return S_OK;
}
BOOL
IsSystemDBCS(
VOID
)
{
WORD wPrimaryLangID = PRIMARYLANGID( GetSystemDefaultLangID() );
return ( wPrimaryLangID == LANG_JAPANESE ||
wPrimaryLangID == LANG_CHINESE ||
wPrimaryLangID == LANG_KOREAN );
}
CHAR * FlipSlashes( CHAR * pszPath )
{
CHAR ch;
CHAR * pszScan = pszPath;
while( ( ch = *pszScan ) != '\0' )
{
if( ch == '/' )
{
*pszScan = '\\';
}
pszScan++;
}
return pszPath;
} // FlipSlashes
HRESULT
GetPoolIDCTimeout(
unsigned char * szMdPath,
DWORD * pdwPoolIDCTimeout
)
{
HRESULT hr = NOERROR;
DWORD cbBufferRequired;
const DWORD dwTimeout = 2000;
STACK_STRU( strMetaPath, MAX_PATH );
if ( g_pMetabase == NULL )
{
return E_NOINTERFACE;
}
hr = strMetaPath.CopyA( (LPSTR)szMdPath );
if( FAILED(hr) )
{
return hr;
}
METADATA_HANDLE hKey = NULL;
METADATA_RECORD MetadataRecord;
hr = g_pMetabase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
strMetaPath.QueryStr(),
METADATA_PERMISSION_READ,
dwTimeout,
&hKey
);
if( SUCCEEDED(hr) )
{
MetadataRecord.dwMDIdentifier = MD_POOL_IDC_TIMEOUT;
MetadataRecord.dwMDAttributes = METADATA_INHERIT;
MetadataRecord.dwMDUserType = IIS_MD_UT_FILE;
MetadataRecord.dwMDDataType = DWORD_METADATA;
MetadataRecord.dwMDDataLen = sizeof( DWORD );
MetadataRecord.pbMDData = (unsigned char *) pdwPoolIDCTimeout;
MetadataRecord.dwMDDataTag = 0;
hr = g_pMetabase->GetData( hKey,
L"",
&MetadataRecord,
&cbBufferRequired
);
g_pMetabase->CloseKey( hKey );
}
return hr;
}
HRESULT
SendCustomError(
EXTENSION_CONTROL_BLOCK *pecb,
const CHAR *pszStatus
)
/*++
Routine Description:
reports custom error
Arguments:
pecb
pszStatus - Status to be reported. If NULL "500" will be sent.
Return Value:
HRESULT
--*/
{
// Locals
HRESULT hr = S_OK;
BOOL fRet;
HSE_CUSTOM_ERROR_INFO *pCustomErrorInfo = NULL;
DWORD cch;
// Check args
DBG_ASSERT( pecb );
if ( !pecb )
{
hr = E_INVALIDARG;
goto Exit;
}
// If supplied status
if (pszStatus)
{
cch = strlen( pszStatus )+1;
}
else
{
pszStatus = c_sz500InternalServerError;
cch = ARRAYSIZE( c_sz500InternalServerError );
}
// Allocate
pCustomErrorInfo = (HSE_CUSTOM_ERROR_INFO*)(new BYTE[sizeof(HSE_CUSTOM_ERROR_INFO)+cch]);
if ( !pCustomErrorInfo )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Exit;
}
pCustomErrorInfo->pszStatus = (CHAR*)pCustomErrorInfo+sizeof(HSE_CUSTOM_ERROR_INFO);
// Set the callback
fRet = pecb->ServerSupportFunction( pecb->ConnID,
HSE_REQ_IO_COMPLETION,
CustomErrorCompletion,
0,
(DWORD*)pCustomErrorInfo );
if ( !fRet )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Exit;
}
// All custom errors must be asynchronous
pCustomErrorInfo->fAsync = TRUE;
// Copy the status
memmove( pCustomErrorInfo->pszStatus,
pszStatus,
cch*sizeof(CHAR));
pCustomErrorInfo->uHttpSubError = 0;
fRet = pecb->ServerSupportFunction( pecb->ConnID,
HSE_REQ_SEND_CUSTOM_ERROR,
pCustomErrorInfo,
NULL,
NULL );
if ( !fRet )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Exit;
}
// Don't free
pCustomErrorInfo = NULL;
Exit:
// Cleanup
if (pCustomErrorInfo)
{
delete[] (BYTE*)pCustomErrorInfo;
pCustomErrorInfo = NULL;
}
return hr;
}
VOID WINAPI
CustomErrorCompletion(
EXTENSION_CONTROL_BLOCK *pecb,
PVOID pContext,
DWORD /*cbIO*/,
DWORD /*dwError*/
)
/*++
Routine Description:
completion routine (for async custom error send)
Arguments:
Return Value:
VOID
--*/
{
HRESULT hr = S_OK;
BOOL fRet;
// Check args
if ( pecb == NULL)
{
hr = E_INVALIDARG;
DBGPRINTF(( DBG_CONTEXT,
"NULL pecb in CustomErrorCompletion().\n"));
goto Exit;
}
// Notify IIS that we are done with processing
fRet = pecb->ServerSupportFunction( pecb->ConnID,
HSE_REQ_DONE_WITH_SESSION,
NULL,
NULL,
NULL );
if ( !fRet )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
DBGPRINTF(( DBG_CONTEXT,
"HSE_REQ_DONE_WITH_SESSION failed, hr = 0x%x.\n",
hr ));
goto Exit;
}
Exit:
// Cleanup
if ( pContext )
{
// Free
delete[] (BYTE*)pContext;
pContext = NULL;
}
}
HRESULT
SendErrorResponse(
EXTENSION_CONTROL_BLOCK *pecb,
const CHAR *pszStatus,
DWORD dwResID,
const CHAR *pszParam
)
/*++
Routine Description:
reports error via HSE_REQ_SEND_RESPONSE_HEADER
Arguments:
pecb
pszStatus - Status to be reported. If NULL "500" will be sent.
dwResID - Error message to be sent in the body.
pszParam - string parameter for the message. Can NULL.
Return Value:
HRESULT
--*/
{
// Locals
HRESULT hr=S_OK;
BOOL fRet;
STRA str;
CHAR szParam[1024];
const CHAR *rgszT[1] = { szParam };
// Check args
if ( !pecb )
{
hr = E_INVALIDARG;
goto Exit;
}
// If no status given set "500 Internal Server Error"
if ( !pszStatus )
{
pszStatus = c_sz500InternalServerError;
}
if ( !pszParam )
{
// If no parameter given set emtpy string
*szParam = '\0';
}
else
{
//
// Note we terminate the error message (ODBC sometimes generates
// 22k errors)
//
strncpy( szParam,
pszParam,
ARRAYSIZE( szParam )-1 );
szParam[ ARRAYSIZE( szParam )-1 ] = '\0';
}
//
// *and* we double the buffer size we pass to FormatString()
// because the win32 API FormatMessage() has a bug that doesn't
// account for Unicode conversion
//
hr = str.FormatString( dwResID,
rgszT,
IIS_RESOURCE_DLL_NAME_A,
2*ARRAYSIZE( szParam ) );
if ( FAILED( hr ) )
{
goto Exit;
}
// Send the error
fRet = pecb->ServerSupportFunction( pecb->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER,
(DWORD*)pszStatus,
NULL,
(DWORD*)str.QueryStr() );
if ( !fRet )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Exit;
}
Exit:
// Done
return hr;
}
HRESULT
SendErrorResponseFromHr(
EXTENSION_CONTROL_BLOCK *pecb,
const CHAR *pszStatus,
DWORD dwResID,
HRESULT hrError
)
/*++
Routine Description:
reports error via HSE_REQ_SEND_RESPONSE_HEADER
Arguments:
pecb
pszStatus - Status to be reported. If NULL "500" will be sent.
dwResID - Error message to be sent in the body.
hrError - HRESULT to be reported. The description of the error will be
used as a parameter for the message. MUST be a failure.
Return Value:
HRESULT
--*/
{
// Locals
HRESULT hr=S_OK;
STRA strError;
// Check args
if ( !pecb )
{
hr = E_INVALIDARG;
goto Exit;
}
if ( SUCCEEDED( hrError ) )
{
hr = E_INVALIDARG;
goto Exit;
}
// Get the description of the last error
hr = strError.LoadString( WIN32_FROM_HRESULT( hrError ),
(LPCSTR)NULL );
if ( FAILED( hr ) )
{
goto Exit;
}
// Call SendErrorResponse
hr = SendErrorResponse( pecb,
pszStatus,
dwResID,
strError.QueryStr() );
Exit:
// Done
return hr;
}