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.
 
 
 
 
 
 

1608 lines
54 KiB

/*===================================================================
Microsoft Denali
Microsoft Confidential.
Copyright 1996 Microsoft Corporation. All Rights Reserved.
Component: CIsapiReqInfo implementation....
File: IsapiReq.cpp
Owner: AndyMorr
===================================================================*/
#include "denpre.h"
#pragma hdrstop
#include "memchk.h"
// undef these here so that we can call the WXI and ECB functions with
// the same name and not be victims of the substituition.
#undef MapUrlToPath
#undef GetCustomError
#undef GetAspMDData
#undef GetAspMDAllData
#undef GetServerVariable
LONG g_nOutstandingAsyncWrites = 0;
/*===================================================================
CIsapiReqInfo::CIsapiReqInfo
===================================================================*/
CIsapiReqInfo::CIsapiReqInfo(EXTENSION_CONTROL_BLOCK *pECB) {
m_cRefs = 1;
m_fApplnMDPathAInited = 0;
m_fApplnMDPathWInited = 0;
m_fAppPoolIdAInited = 0;
m_fAppPoolIdWInited = 0;
m_fPathInfoWInited = 0;
m_fPathTranslatedWInited = 0;
m_fCookieInited = 0;
m_fUserAgentInited = 0;
m_fInstanceIDInited = 0;
m_fVersionInited = 0;
m_fFKeepConnInited = 0;
m_fPendSendCSInited = 0;
m_fIOCompletionRegistered = 0;
m_fHeadersWritten = 0;
m_dwInstanceID = 0;
m_dwVersionMajor = 1;
m_dwVersionMinor = 0;
m_cchQueryString = -1;
m_cchApplnMDPathA = -1;
m_cchPathTranslatedA = -1;
m_cchPathInfoA = -1;
m_cchApplnMDPathW = -1;
m_cchPathTranslatedW = -1;
m_cchPathInfoW = -1;
m_cchAppPoolIdW = -1;
m_cchAppPoolIdA = -1;
m_fKeepConn = FALSE;
m_pIAdminBase = NULL;
m_pECB = pECB;
m_dwRequestStatus = HSE_STATUS_SUCCESS;
m_dwAsyncError = NOERROR;
}
/*===================================================================
CIsapiReqInfo::~CIsapiReqInfo
===================================================================*/
CIsapiReqInfo::~CIsapiReqInfo() {
Assert(m_listPendingSends.FIsEmpty());
if (m_pIAdminBase != NULL) {
m_pIAdminBase->Release();
m_pIAdminBase = NULL;
}
if (m_fPendSendCSInited)
DeleteCriticalSection(&m_csPendingSendCS);
if (m_pECB) {
DWORD dwRequestStatus = HSE_STATUS_SUCCESS;
if ((m_pECB->dwHttpStatusCode >= 500) && (m_pECB->dwHttpStatusCode < 600))
dwRequestStatus = HSE_STATUS_ERROR;
else if (m_dwRequestStatus == HSE_STATUS_PENDING)
dwRequestStatus = m_dwAsyncError ? HSE_STATUS_ERROR : HSE_STATUS_SUCCESS;
ServerSupportFunction(HSE_REQ_DONE_WITH_SESSION,
&dwRequestStatus,
NULL,
NULL);
}
}
/*===================================================================
CIsapiReqInfo::QueryPszQueryString
===================================================================*/
LPSTR CIsapiReqInfo::QueryPszQueryString()
{
return m_pECB->lpszQueryString;
}
/*===================================================================
CIsapiReqInfo::QueryCchQueryString
===================================================================*/
DWORD CIsapiReqInfo::QueryCchQueryString()
{
if (m_cchQueryString == -1) {
m_cchQueryString = QueryPszQueryString() ? strlen(QueryPszQueryString()) : 0;
}
return m_cchQueryString;
}
/*===================================================================
CIsapiReqInfo::QueryPszApplnMDPathA
===================================================================*/
LPSTR CIsapiReqInfo::QueryPszApplnMDPathA()
{
if (m_fApplnMDPathAInited == FALSE) {
*((LPSTR)m_ApplnMDPathA.QueryPtr()) = '\0';
m_fApplnMDPathAInited = InternalGetServerVariable("APPL_MD_PATH", &m_ApplnMDPathA);
}
ASSERT(m_fApplnMDPathAInited);
return (LPSTR)m_ApplnMDPathA.QueryPtr();
}
/*===================================================================
CIsapiReqInfo::QueryCchApplnMDPathA
===================================================================*/
DWORD CIsapiReqInfo::QueryCchApplnMDPathA()
{
if (m_cchApplnMDPathA == -1) {
m_cchApplnMDPathA = QueryPszApplnMDPathA()
? strlen(QueryPszApplnMDPathA())
: 0;
}
return(m_cchApplnMDPathA);
}
/*===================================================================
CIsapiReqInfo::QueryPszApplnMDPathW
===================================================================*/
LPWSTR CIsapiReqInfo::QueryPszApplnMDPathW()
{
if (m_fApplnMDPathWInited == FALSE) {
*((LPWSTR)m_ApplnMDPathW.QueryPtr()) = L'\0';
m_fApplnMDPathWInited = InternalGetServerVariable("UNICODE_APPL_MD_PATH", &m_ApplnMDPathW);
}
ASSERT(m_fApplnMDPathWInited);
return (LPWSTR)m_ApplnMDPathW.QueryPtr();
}
/*===================================================================
CIsapiReqInfo::QueryCchApplnMDPathW
===================================================================*/
DWORD CIsapiReqInfo::QueryCchApplnMDPathW()
{
if (m_cchApplnMDPathW == -1) {
m_cchApplnMDPathW = QueryPszApplnMDPathW()
? wcslen(QueryPszApplnMDPathW())
: 0;
}
return(m_cchApplnMDPathW);
}
/*===================================================================
CIsapiReqInfo::QueryPszAppPoolIdA
===================================================================*/
LPSTR CIsapiReqInfo::QueryPszAppPoolIdA()
{
if (m_fAppPoolIdAInited == FALSE) {
*((LPSTR)m_AppPoolIdA.QueryPtr()) = '\0';
m_fAppPoolIdAInited = InternalGetServerVariable("APP_POOL_ID", &m_AppPoolIdA);
}
ASSERT(m_fAppPoolIdAInited);
return (LPSTR)m_AppPoolIdA.QueryPtr();
}
/*===================================================================
CIsapiReqInfo::QueryCchAppPoolIdA
===================================================================*/
DWORD CIsapiReqInfo::QueryCchAppPoolIdA()
{
if (m_cchAppPoolIdA == -1) {
m_cchAppPoolIdA = QueryPszAppPoolIdA()
? strlen(QueryPszAppPoolIdA())
: 0;
}
return(m_cchAppPoolIdA);
}
/*===================================================================
CIsapiReqInfo::QueryPszAppPoolIdW
===================================================================*/
LPWSTR CIsapiReqInfo::QueryPszAppPoolIdW()
{
if (m_fAppPoolIdWInited == FALSE) {
*((LPWSTR)m_AppPoolIdW.QueryPtr()) = L'\0';
m_fAppPoolIdWInited = InternalGetServerVariable("UNICODE_APP_POOL_ID", &m_AppPoolIdW);
}
ASSERT(m_fAppPoolIdWInited);
return (LPWSTR)m_AppPoolIdW.QueryPtr();
}
/*===================================================================
CIsapiReqInfo::QueryCchAppPoolIdW
===================================================================*/
DWORD CIsapiReqInfo::QueryCchAppPoolIdW()
{
if (m_cchAppPoolIdW == -1) {
m_cchAppPoolIdW = QueryPszAppPoolIdW()
? wcslen(QueryPszAppPoolIdW())
: 0;
}
return(m_cchAppPoolIdW);
}
/*===================================================================
CIsapiReqInfo::QueryPszPathInfoA
===================================================================*/
LPSTR CIsapiReqInfo::QueryPszPathInfoA()
{
return m_pECB->lpszPathInfo;
}
/*===================================================================
CIsapiReqInfo::QueryCchPathInfoA
===================================================================*/
DWORD CIsapiReqInfo::QueryCchPathInfoA()
{
if (m_cchPathInfoA == -1) {
m_cchPathInfoA = QueryPszPathInfoA()
? strlen(QueryPszPathInfoA())
: 0;
}
return m_cchPathInfoA;
}
/*===================================================================
CIsapiReqInfo::QueryPszPathInfoW
===================================================================*/
LPWSTR CIsapiReqInfo::QueryPszPathInfoW()
{
if (m_fPathInfoWInited == FALSE) {
*((LPWSTR)m_PathInfoW.QueryPtr()) = L'\0';
m_fPathInfoWInited = InternalGetServerVariable("UNICODE_PATH_INFO", &m_PathInfoW);
}
ASSERT(m_fPathInfoWInited);
return (LPWSTR)m_PathInfoW.QueryPtr();
}
/*===================================================================
CIsapiReqInfo::QueryCchPathInfoW
===================================================================*/
DWORD CIsapiReqInfo::QueryCchPathInfoW()
{
if (m_cchPathInfoW == -1) {
m_cchPathInfoW = QueryPszPathInfoW()
? wcslen(QueryPszPathInfoW())
: 0;
}
return m_cchPathInfoW;
}
/*===================================================================
CIsapiReqInfo::QueryPszPathTranslatedA
===================================================================*/
LPSTR CIsapiReqInfo::QueryPszPathTranslatedA()
{
return m_pECB->lpszPathTranslated;
}
/*===================================================================
CIsapiReqInfo::QueryCchPathTranslatedA
===================================================================*/
DWORD CIsapiReqInfo::QueryCchPathTranslatedA()
{
if (m_cchPathTranslatedA == -1) {
m_cchPathTranslatedA = QueryPszPathTranslatedA()
? strlen(QueryPszPathTranslatedA())
: 0;
}
return m_cchPathTranslatedA;
}
/*===================================================================
CIsapiReqInfo::QueryPszPathTranslatedW
===================================================================*/
LPWSTR CIsapiReqInfo::QueryPszPathTranslatedW()
{
if (m_fPathTranslatedWInited == FALSE) {
*((LPWSTR)m_PathTranslatedW.QueryPtr()) = L'\0';
m_fPathTranslatedWInited = InternalGetServerVariable("UNICODE_PATH_TRANSLATED", &m_PathTranslatedW);
}
return (LPWSTR)m_PathTranslatedW.QueryPtr();
}
/*===================================================================
CIsapiReqInfo::QueryCchPathTranslatedW
===================================================================*/
DWORD CIsapiReqInfo::QueryCchPathTranslatedW()
{
if (m_cchPathTranslatedW == -1) {
m_cchPathTranslatedW = QueryPszPathTranslatedW()
? wcslen(QueryPszPathTranslatedW())
: 0;
}
return m_cchPathTranslatedW;
}
/*===================================================================
CIsapiReqInfo::QueryPszCookie
===================================================================*/
LPSTR CIsapiReqInfo::QueryPszCookie()
{
if (m_fCookieInited == FALSE) {
*((LPSTR)m_Cookie.QueryPtr()) = '\0';
InternalGetServerVariable("HTTP_COOKIE", &m_Cookie);
m_fCookieInited = TRUE;
}
return (LPSTR)m_Cookie.QueryPtr();
}
/*===================================================================
CIsapiReqInfo::SetDwHttpStatusCode
===================================================================*/
VOID CIsapiReqInfo::SetDwHttpStatusCode(DWORD dwStatus)
{
m_pECB->dwHttpStatusCode = dwStatus;
}
/*===================================================================
CIsapiReqInfo::QueryPbData
===================================================================*/
LPBYTE CIsapiReqInfo::QueryPbData()
{
return m_pECB->lpbData;
}
/*===================================================================
CIsapiReqInfo::QueryCbAvailable
===================================================================*/
DWORD CIsapiReqInfo::QueryCbAvailable()
{
return m_pECB->cbAvailable;
}
/*===================================================================
CIsapiReqInfo::QueryCbTotalBytes
===================================================================*/
DWORD CIsapiReqInfo::QueryCbTotalBytes()
{
return m_pECB->cbTotalBytes;
}
/*===================================================================
CIsapiReqInfo::QueryPszContentType
===================================================================*/
LPSTR CIsapiReqInfo::QueryPszContentType()
{
return m_pECB->lpszContentType;
}
/*===================================================================
CIsapiReqInfo::QueryPszMethod
===================================================================*/
LPSTR CIsapiReqInfo::QueryPszMethod()
{
return m_pECB->lpszMethod;
}
/*===================================================================
CIsapiReqInfo::QueryPszUserAgent
===================================================================*/
LPSTR CIsapiReqInfo::QueryPszUserAgent()
{
if (m_fUserAgentInited == FALSE) {
*((LPSTR)m_UserAgent.QueryPtr()) = '\0';
InternalGetServerVariable("HTTP_USER_AGENT", &m_UserAgent);
}
return (LPSTR)m_UserAgent.QueryPtr();
}
/*===================================================================
CIsapiReqInfo::QueryInstanceId
===================================================================*/
DWORD CIsapiReqInfo::QueryInstanceId()
{
if (m_fInstanceIDInited == FALSE) {
BUFFER instanceID;
m_fInstanceIDInited = InternalGetServerVariable("INSTANCE_ID", &instanceID);
if (m_fInstanceIDInited == TRUE) {
m_dwInstanceID = atoi((char *)instanceID.QueryPtr());
}
else {
m_dwInstanceID = 1;
}
}
return m_dwInstanceID;
}
/*===================================================================
CIsapiReqInfo::IsChild
===================================================================*/
BOOL CIsapiReqInfo::IsChild()
{
// BUGBUG: This needs to be implemented
return FALSE;
}
/*===================================================================
CIsapiReqInfo::FInPool
===================================================================*/
BOOL CIsapiReqInfo::FInPool()
{
DWORD dwAppFlag;
if (ServerSupportFunction(HSE_REQ_IS_IN_PROCESS,
&dwAppFlag,
NULL,
NULL) == FALSE) {
// BUGBUG: Need to enable this Assert in future builds.
//Assert(0);
// if error, the best we can do is return TRUE here so
// that ASP picks up its settings from the service level
return TRUE;
}
return !(dwAppFlag == HSE_APP_FLAG_ISOLATED_OOP);
}
/*===================================================================
CIsapiReqInfo::QueryHttpVersionMajor
===================================================================*/
DWORD CIsapiReqInfo::QueryHttpVersionMajor()
{
InitVersionInfo();
return m_dwVersionMajor;
}
/*===================================================================
CIsapiReqInfo::QueryHttpVersionMinor
===================================================================*/
DWORD CIsapiReqInfo::QueryHttpVersionMinor()
{
InitVersionInfo();
return m_dwVersionMinor;
}
/*===================================================================
CIsapiReqInfo::GetAspMDData
===================================================================*/
HRESULT CIsapiReqInfo::GetAspMDDataA(CHAR * pszMDPath,
DWORD dwMDIdentifier,
DWORD dwMDAttributes,
DWORD dwMDUserType,
DWORD dwMDDataType,
DWORD dwMDDataLen,
DWORD dwMDDataTag,
unsigned char * pbMDData,
DWORD * pdwRequiredBufferSize)
{
return E_NOTIMPL;
}
/*===================================================================
CIsapiReqInfo::GetAspMDData
===================================================================*/
HRESULT CIsapiReqInfo::GetAspMDDataW(WCHAR * pszMDPath,
DWORD dwMDIdentifier,
DWORD dwMDAttributes,
DWORD dwMDUserType,
DWORD dwMDDataType,
DWORD dwMDDataLen,
DWORD dwMDDataTag,
unsigned char * pbMDData,
DWORD * pdwRequiredBufferSize)
{
IMSAdminBase *pMetabase;
METADATA_HANDLE hKey = NULL;
METADATA_RECORD MetadataRecord;
DWORD dwTimeout = 30000;
HRESULT hr = S_OK;
HANDLE hCurrentUser = INVALID_HANDLE_VALUE;
AspDoRevertHack( &hCurrentUser );
pMetabase = GetMetabaseIF(&hr);
ASSERT(pMetabase);
if (pMetabase)
{
hr = pMetabase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
pszMDPath,
METADATA_PERMISSION_READ,
dwTimeout,
&hKey
);
ASSERT(SUCCEEDED(hr));
if( SUCCEEDED(hr) )
{
MetadataRecord.dwMDIdentifier = dwMDIdentifier;
MetadataRecord.dwMDAttributes = dwMDAttributes;
MetadataRecord.dwMDUserType = dwMDUserType;
MetadataRecord.dwMDDataType = dwMDDataType;
MetadataRecord.dwMDDataLen = dwMDDataLen;
MetadataRecord.pbMDData = pbMDData;
MetadataRecord.dwMDDataTag = dwMDDataTag;
hr = pMetabase->GetData( hKey,
L"",
&MetadataRecord,
pdwRequiredBufferSize);
ASSERT(SUCCEEDED(hr));
pMetabase->CloseKey( hKey );
}
}
else // pMetabase == NULL, but there was No HRESULT set then we will explicitly set it.
{
if (SUCCEEDED(hr))
hr = E_FAIL;
}
AspUndoRevertHack( &hCurrentUser );
return hr;
}
/*===================================================================
CIsapiReqInfo::GetAspMDAllData
===================================================================*/
HRESULT CIsapiReqInfo::GetAspMDAllDataA(LPSTR pszMDPath,
DWORD dwMDUserType,
DWORD dwDefaultBufferSize,
LPVOID pvBuffer,
DWORD * pdwRequiredBufferSize,
DWORD * pdwNumDataEntries)
{
return E_NOTIMPL;
}
/*===================================================================
CIsapiReqInfo::GetAspMDAllData
===================================================================*/
HRESULT CIsapiReqInfo::GetAspMDAllDataW(LPWSTR pwszMDPath,
DWORD dwMDUserType,
DWORD dwDefaultBufferSize,
LPVOID pvBuffer,
DWORD * pdwRequiredBufferSize,
DWORD * pdwNumDataEntries)
{
HRESULT hr = S_OK;
IMSAdminBase *pMetabase;
METADATA_HANDLE hKey = NULL;
DWORD dwTimeout = 30000;
DWORD dwDataSet;
HANDLE hCurrentUser = INVALID_HANDLE_VALUE;
AspDoRevertHack( &hCurrentUser );
//
// Wide-ize the metabase path
//
pMetabase = GetMetabaseIF(&hr);
ASSERT(pMetabase);
if (pMetabase)
{
hr = pMetabase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
pwszMDPath,
METADATA_PERMISSION_READ,
dwTimeout,
&hKey);
if( SUCCEEDED(hr) )
{
hr = pMetabase->GetAllData( hKey,
L"",
METADATA_INHERIT,
dwMDUserType,
ALL_METADATA,
pdwNumDataEntries,
&dwDataSet,
dwDefaultBufferSize,
(UCHAR *)pvBuffer,
pdwRequiredBufferSize);
ASSERT(SUCCEEDED(hr));
pMetabase->CloseKey( hKey );
}
}
else // pMetabase == NULL, but there was No HRESULT set then we will explicitly set it.
{
if (SUCCEEDED(hr))
hr = E_FAIL;
}
AspUndoRevertHack( &hCurrentUser );
return hr;
}
/*===================================================================
CIsapiReqInfo::GetCustomErrorA
===================================================================*/
BOOL CIsapiReqInfo::GetCustomErrorA(DWORD dwError,
DWORD dwSubError,
DWORD dwBufferSize,
CHAR *pvBuffer,
DWORD *pdwRequiredBufferSize,
BOOL *pfIsFileError,
BOOL *pfSendErrorBody)
{
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return FALSE;
}
/*===================================================================
CIsapiReqInfo::GetCustomErrorW
===================================================================*/
BOOL CIsapiReqInfo::GetCustomErrorW(DWORD dwError,
DWORD dwSubError,
DWORD dwBufferSize,
WCHAR *pvBuffer,
DWORD *pdwRequiredBufferSize,
BOOL *pfIsFileError,
BOOL *pfSendErrorBody)
{
BOOL fRet;
HSE_CUSTOM_ERROR_PAGE_INFO cei;
STACK_BUFFER(ansiBuf, 1024);
cei.dwError = dwError;
cei.dwSubError = dwSubError;
cei.dwBufferSize = ansiBuf.QuerySize();
cei.pBuffer = (CHAR *)ansiBuf.QueryPtr();
cei.pdwBufferRequired = pdwRequiredBufferSize;
cei.pfIsFileError = pfIsFileError;
cei.pfSendErrorBody = pfSendErrorBody;
fRet = ServerSupportFunction(HSE_REQ_GET_CUSTOM_ERROR_PAGE,
&cei,
NULL,
NULL);
if (!fRet) {
DWORD dwErr = GetLastError();
if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
if (ansiBuf.Resize(*pdwRequiredBufferSize) == FALSE) {
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
cei.dwBufferSize = ansiBuf.QuerySize();
cei.pBuffer = (CHAR *)ansiBuf.QueryPtr();
fRet = ServerSupportFunction(HSE_REQ_GET_CUSTOM_ERROR_PAGE,
&cei,
NULL,
NULL);
}
if (!fRet) {
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
}
CMBCSToWChar convError;
if (FAILED(convError.Init((LPCSTR)ansiBuf.QueryPtr()))) {
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
*pdwRequiredBufferSize = (convError.GetStringLen()+1)*sizeof(WCHAR);
if (*pdwRequiredBufferSize > dwBufferSize) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
memcpy(pvBuffer, convError.GetString(), *pdwRequiredBufferSize);
if (*pfIsFileError) {
CMBCSToWChar convMime;
DWORD fileNameLen = *pdwRequiredBufferSize;
if (FAILED(convMime.Init((LPCSTR)ansiBuf.QueryPtr()+strlen((LPCSTR)ansiBuf.QueryPtr())+1))) {
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
*pdwRequiredBufferSize += (convMime.GetStringLen()+1)*sizeof(WCHAR);
if (*pdwRequiredBufferSize > dwBufferSize) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
memcpy(&((BYTE *)pvBuffer)[fileNameLen], convMime.GetString(), (convMime.GetStringLen()+1)*sizeof(WCHAR));
}
return TRUE;
}
/*===================================================================
CIsapiReqInfo::QueryImpersonationToken
===================================================================*/
HANDLE CIsapiReqInfo::QueryImpersonationToken()
{
HANDLE hToken = INVALID_HANDLE_VALUE;
ServerSupportFunction(HSE_REQ_GET_IMPERSONATION_TOKEN,
&hToken,
NULL,
NULL);
return hToken;
}
/*===================================================================
CIsapiReqInfo::AppendLogParameter
===================================================================*/
HRESULT CIsapiReqInfo::AppendLogParameter(LPSTR extraParam)
{
if (ServerSupportFunction(HSE_APPEND_LOG_PARAMETER,
extraParam,
NULL,
NULL) == FALSE) {
return HRESULT_FROM_WIN32(GetLastError());
}
return S_OK;
}
/*===================================================================
CIsapiReqInfo::SendHeader
===================================================================*/
BOOL CIsapiReqInfo::SendHeader(LPVOID pvStatus,
DWORD cchStatus,
LPVOID pvHeader,
DWORD cchHeader,
BOOL fIsaKeepConn)
{
HSE_SEND_HEADER_EX_INFO HeaderInfo;
HeaderInfo.pszStatus = (LPCSTR)pvStatus;
HeaderInfo.cchStatus = cchStatus;
HeaderInfo.pszHeader = (LPCSTR) pvHeader;
HeaderInfo.cchHeader = cchHeader;
HeaderInfo.fKeepConn = fIsaKeepConn;
m_fHeadersWritten = TRUE;
return ServerSupportFunction( HSE_REQ_SEND_RESPONSE_HEADER_EX,
&HeaderInfo,
NULL,
NULL );
}
/*===================================================================
CIsapiReqInfo::GetServerVariableA
===================================================================*/
BOOL CIsapiReqInfo::GetServerVariableA(LPSTR szVarName,
LPSTR pBuffer,
LPDWORD pdwSize )
{
return m_pECB->GetServerVariable( (HCONN)m_pECB->ConnID,
szVarName,
pBuffer,
pdwSize );
}
/*===================================================================
CIsapiReqInfo::GetServerVariableW
===================================================================*/
BOOL CIsapiReqInfo::GetServerVariableW(LPSTR szVarName,
LPWSTR pBuffer,
LPDWORD pdwSize )
{
return m_pECB->GetServerVariable( (HCONN)m_pECB->ConnID,
szVarName,
pBuffer,
pdwSize );
}
/*===================================================================
CIsapiReqInfo::GetVirtualPathTokenA
===================================================================*/
HRESULT CIsapiReqInfo::GetVirtualPathTokenA(LPCSTR szPath,
HANDLE *hToken)
{
HRESULT hr = S_OK;
if (!ServerSupportFunction(HSE_REQ_GET_VIRTUAL_PATH_TOKEN,
(LPVOID)szPath,
(DWORD *)hToken,
NULL)) {
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
/*===================================================================
CIsapiReqInfo::GetVirtualPathTokenW
===================================================================*/
HRESULT CIsapiReqInfo::GetVirtualPathTokenW(LPCWSTR szPath,
HANDLE *hToken)
{
HRESULT hr = S_OK;
if (!ServerSupportFunction(HSE_REQ_GET_UNICODE_VIRTUAL_PATH_TOKEN,
(LPVOID)szPath,
(DWORD *)hToken,
NULL)) {
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
/*===================================================================
CIsapiReqInfo::ServerSupportFunction
===================================================================*/
BOOL CIsapiReqInfo::ServerSupportFunction(DWORD dwHSERequest,
LPVOID pvData,
LPDWORD pdwSize,
LPDWORD pdwDataType)
{
return m_pECB->ServerSupportFunction( (HCONN)m_pECB->ConnID,
dwHSERequest,
pvData,
pdwSize,
pdwDataType );
}
/*===================================================================
CIsapiReqInfo::SendClinetResponse
this routine is used to send all of ASP data to the client. the data
may consist of any combination of the following:
- header information as contained in pResponseInfo->HeaderInfo
- contents of a file if pResponseInfo->cWsaBuf == 0xFFFFFFFF
- non-buffered data if pResponseInfo->cWsaBuf > 0
- buffered data if pResponseVectors != NULL
Note, we are changing the semantics of the HSE_SEND_ENTIRE_RESPONSE_INFO
structure as follows:
- if pResponseInfo->cWsaBuf == 0xFFFFFFFF, then pResponseInfo->rgWsaBuf
is a pointer to a single WSABUF, containing a file handle rather than
memory buffer pointer
- we are not reserving entry 0 of the pResponseInfo->rgWsaBuf array, so
entries 0 - (N-1) contain relevant data
Note, the HeaderInfo strings pszStatus and pszContent are set to NULL
after their placed in the AsyncCB SEND_VECTOR structure to indicate
that we've taken ownership of the memory. Note that it is also
assumed that the memory was allocated using malloc().
===================================================================*/
BOOL CIsapiReqInfo::SendClientResponse(PFN_CLIENT_IO_COMPLETION pComplFunc,
VOID *pComplArg,
LPHSE_SEND_ENTIRE_RESPONSE_INFO pResponseInfo,
LPWSABUF_VECTORS pResponseVectors)
{
HRESULT hr = S_OK;
DWORD nElementCount = 0;
DWORD dwTotalBytes = 0;
HSE_VECTOR_ELEMENT *pVectorElement = NULL;
HSE_RESPONSE_VECTOR *pRespVector;
BOOL fKeepConn;
CAsyncVectorSendCB syncVectorSendCB; // use the async class to manage the resp vector
CAsyncVectorSendCB *pVectorSendCB = &syncVectorSendCB;
// if an error has been recorded during an Async completion, bail out
// early
if (m_dwAsyncError) {
SetLastError(m_dwAsyncError);
return FALSE;
}
// if a completion function was provided, allocate a CAsyncVectorSendCB
// instead of the stack version
if (pComplFunc) {
pVectorSendCB = new CAsyncVectorSendCB(this, pComplArg, pComplFunc);
if (pVectorSendCB == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
}
pRespVector = &pVectorSendCB->m_hseResponseVector;
Assert( pResponseInfo );
Assert( (pResponseInfo->cWsaBuf == 0xFFFFFFFF) ||
(pResponseInfo->cWsaBuf < 0x3FFF) ); // arbitrary logical limit
Assert( (pResponseInfo->cWsaBuf == 0) || (pResponseInfo->rgWsaBuf != NULL));
//
// Set the keep connection flag. It can only be TRUE if the
// ISAPI and the client both want keep alive.
//
fKeepConn = FKeepConn() && pResponseInfo->HeaderInfo.fKeepConn;
//
// Munge the input structure into something that IIsapiCore can
// understand. Note that ASP sets the number of buffer to be one more
// than actual and the first buffer is not valid
//
if (pResponseInfo->cWsaBuf == 0xFFFFFFFF)
{
// indicates a file handle in a single WSABUF
nElementCount ++;
}
else
{
nElementCount += pResponseInfo->cWsaBuf;
}
// Add the optional raw response vectors
if (pResponseVectors)
{
Assert(pResponseVectors->dwVectorLen1 <= RESPONSE_VECTOR_INTRINSIC_SIZE);
Assert(pResponseVectors->dwVectorLen2 < 0x3FFF);
nElementCount += pResponseVectors->dwVectorLen1 + pResponseVectors->dwVectorLen2;
}
if (nElementCount == 0) {
// no body to send. pVectorElement already set to NULL
goto FillHeaderAndSend;
}
Assert( nElementCount < 0x3FFF); // arbitrary logical limit
// let the VectorSendCB know how many elements are needed.
if (FAILED(hr = pVectorSendCB->SetElementCount(nElementCount)))
{
goto Exit;
}
pVectorElement = pVectorSendCB->m_pVectorElements;
#define FILL_HSE_VECTOR_LOOP(cElements, WsaBuf) \
\
for (DWORD i = 0; i < cElements; i++) \
{ \
if (WsaBuf[i].len == 0) \
{ \
Assert( nElementCount > 0); \
nElementCount--; \
continue; \
} \
\
Assert( !IsBadReadPtr( WsaBuf[i].buf, WsaBuf[i].len)); \
\
pVectorElement->ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER; \
pVectorElement->pvContext = WsaBuf[i].buf; \
pVectorElement->cbSize = WsaBuf[i].len; \
dwTotalBytes += WsaBuf[i].len; \
pVectorElement++; \
}
if (pResponseInfo->cWsaBuf == 0xFFFFFFFF) {
// we have a file handle rather than a memory buffer
pVectorElement->ElementType = HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE;
pVectorElement->pvContext = pResponseInfo->rgWsaBuf[0].buf;
pVectorElement->cbSize = pResponseInfo->rgWsaBuf[0].len;
dwTotalBytes += pResponseInfo->rgWsaBuf[0].len;
pVectorElement++;
} else {
FILL_HSE_VECTOR_LOOP( pResponseInfo->cWsaBuf, pResponseInfo->rgWsaBuf)
}
if (pResponseVectors) {
FILL_HSE_VECTOR_LOOP( pResponseVectors->dwVectorLen1, pResponseVectors->pVector1)
FILL_HSE_VECTOR_LOOP( pResponseVectors->dwVectorLen2, pResponseVectors->pVector2)
}
#undef FILL_HSE_VECTOR_LOOP
// reset to the begining of buffer
pVectorElement = pVectorSendCB->m_pVectorElements;
FillHeaderAndSend:
pRespVector->dwFlags = (pComplFunc ? HSE_IO_ASYNC : HSE_IO_SYNC) |
(!fKeepConn ? HSE_IO_DISCONNECT_AFTER_SEND : 0) |
(pResponseInfo->HeaderInfo.pszHeader ? HSE_IO_SEND_HEADERS : 0);
pRespVector->pszStatus = (LPSTR)pResponseInfo->HeaderInfo.pszStatus;
pRespVector->pszHeaders = (LPSTR)pResponseInfo->HeaderInfo.pszHeader;
pRespVector->nElementCount = nElementCount;
pRespVector->lpElementArray = pVectorElement;
dwTotalBytes += pResponseInfo->HeaderInfo.cchStatus;
dwTotalBytes += pResponseInfo->HeaderInfo.cchHeader;
// Note that the headers have been written
if (pResponseInfo->HeaderInfo.pszHeader)
m_fHeadersWritten = TRUE;
// by moving these pointers into our SEND_VECTOR, we are taking
// ownership of the memory.
pResponseInfo->HeaderInfo.pszStatus = NULL;
pResponseInfo->HeaderInfo.pszHeader = NULL;
if (pComplFunc) {
hr = AddToPendingList(pVectorSendCB);
}
else {
//
// Send it
//
if (ServerSupportFunction(HSE_REQ_VECTOR_SEND,
pRespVector,
NULL,
NULL) == FALSE) {
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
if (SUCCEEDED(hr)) {
pResponseInfo->cbWritten = dwTotalBytes;
}
Exit:
if (FAILED(hr))
{
SetLastError((HRESULT_FACILITY(hr) == (HRESULT)FACILITY_WIN32)
? HRESULT_CODE(hr)
: ERROR_INVALID_PARAMETER);
if (pVectorSendCB && (pVectorSendCB != &syncVectorSendCB)) {
delete pVectorSendCB;
}
return FALSE;
}
return TRUE;
}
/*===================================================================
CIsapiReqInfo::TestConnection
===================================================================*/
BOOL CIsapiReqInfo::TestConnection(BOOL *pfIsConnected)
{
return ServerSupportFunction(HSE_REQ_IS_CONNECTED,
pfIsConnected,
NULL,
NULL);
}
/*===================================================================
CIsapiReqInfo::MapUrlToPathA
===================================================================*/
BOOL CIsapiReqInfo::MapUrlToPathA(LPSTR pBuffer, LPDWORD pdwBytes)
{
return ServerSupportFunction( HSE_REQ_MAP_URL_TO_PATH,
pBuffer,
pdwBytes,
NULL );
}
/*===================================================================
CIsapiReqInfo::MapUrlToPathW
===================================================================*/
BOOL CIsapiReqInfo::MapUrlToPathW(LPWSTR pBuffer, LPDWORD pdwBytes)
{
return ServerSupportFunction( HSE_REQ_MAP_UNICODE_URL_TO_PATH,
pBuffer,
pdwBytes,
NULL );
}
/*===================================================================
CIsapiReqInfo::SyncReadClient
===================================================================*/
BOOL CIsapiReqInfo::SyncReadClient(LPVOID pvBuffer, LPDWORD pdwBytes )
{
return m_pECB->ReadClient(m_pECB->ConnID, pvBuffer, pdwBytes);
}
/*===================================================================
CIsapiReqInfo::SyncWriteClient
===================================================================*/
BOOL CIsapiReqInfo::SyncWriteClient(LPVOID pvBuffer, LPDWORD pdwBytes)
{
return m_pECB->WriteClient(m_pECB->ConnID, pvBuffer, pdwBytes, HSE_IO_SYNC);
}
/*********************************************************************
PRIVATE FUNCTIONS
*********************************************************************/
/*===================================================================
CIsapiReqInfo::InitVersionInfo
===================================================================*/
void CIsapiReqInfo::InitVersionInfo()
{
if (m_fVersionInited == FALSE) {
BUFFER version;
m_fVersionInited = TRUE;
m_dwVersionMajor = 1;
m_dwVersionMinor = 0;
if (InternalGetServerVariable("SERVER_PROTOCOL", &version)) {
char *pVersionStr = (char *)version.QueryPtr();
if ((strlen(pVersionStr) >= 8)
&& (isdigit((UCHAR)pVersionStr[5]))
&& (isdigit((UCHAR)pVersionStr[7]))) {
m_dwVersionMajor = pVersionStr[5] - '0';
m_dwVersionMinor = pVersionStr[7] - '0';
}
}
}
}
/*===================================================================
CIsapiReqInfo::InternalGetServerVariable
===================================================================*/
BOOL CIsapiReqInfo::InternalGetServerVariable(LPSTR pszVarName, BUFFER *pBuf)
{
BOOL bRet;
DWORD dwRequiredBufSize = pBuf->QuerySize();
bRet = m_pECB->GetServerVariable(m_pECB->ConnID,
pszVarName,
pBuf->QueryPtr(),
&dwRequiredBufSize);
if ((bRet == FALSE) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
if (!pBuf->Resize(dwRequiredBufSize)) {
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
bRet = m_pECB->GetServerVariable(m_pECB->ConnID,
pszVarName,
pBuf->QueryPtr(),
&dwRequiredBufSize);
}
return(bRet);
}
/*===================================================================
CIsapiReqInfo::FKeepConn
===================================================================*/
BOOL CIsapiReqInfo::FKeepConn()
{
if (m_fFKeepConnInited == FALSE) {
m_fFKeepConnInited = TRUE;
m_fKeepConn = FALSE;
InitVersionInfo();
if (m_dwVersionMajor == 1) {
if (m_dwVersionMinor == 1) {
m_fKeepConn = TRUE;
}
BUFFER connectStr;
if (InternalGetServerVariable("HTTP_CONNECTION", &connectStr)) {
if (m_dwVersionMinor == 0) {
m_fKeepConn = !(_stricmp((char *)connectStr.QueryPtr(), "keep-alive"));
}
else if (m_dwVersionMinor == 1) {
m_fKeepConn = !!(_stricmp((char *)connectStr.QueryPtr(), "close"));
}
}
}
}
return m_fKeepConn;
}
/*===================================================================
CIsapiReqInfo::GetMetabaseIF
===================================================================*/
IMSAdminBase *CIsapiReqInfo::GetMetabaseIF(HRESULT *pHr)
{
IMSAdminBase *pMetabase;
//
//Set *pHr to S_OK in case its not initialized
//
*pHr = S_OK;
if (m_pIAdminBase == NULL) {
*pHr = CoCreateInstance(CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void**)&pMetabase);
ASSERT(SUCCEEDED(*pHr));
if ( InterlockedCompareExchangePointer( (VOID**)&m_pIAdminBase, pMetabase, NULL) != NULL )
{
pMetabase->Release();
pMetabase = NULL;
}
}
return m_pIAdminBase;
}
/*===================================================================
CIsapiReqInfo::AddToPendingList
Places an CAsyncVectorSendCB on the PendingSendCS. If this is
the first entry placed on the list, then IssueNextSend() is called
to start the possible chain of sends.
===================================================================*/
HRESULT CIsapiReqInfo::AddToPendingList(CAsyncVectorSendCB *pVectorCB)
{
HRESULT hr = S_OK;
// initialize the critical section if it hasn't already
// been initialized. Note that there isn't a race condition
// here because there can't be any other thread contenting for
// this CS until AsyncIOs start to complete. It's safe to
// assume that the IO hasn't begun if we've never enterred
// this routine before...
if (m_fPendSendCSInited == FALSE) {
ErrInitCriticalSection(&m_csPendingSendCS, hr);
if (SUCCEEDED(hr))
m_fPendSendCSInited = TRUE;
}
// similar to the CS above, register the completion function
if (SUCCEEDED(hr) && (m_fIOCompletionRegistered == FALSE)) {
if (ServerSupportFunction(HSE_REQ_IO_COMPLETION,
AsyncCompletion,
NULL,
(LPDWORD)this) == FALSE)
hr = HRESULT_FROM_WIN32(GetLastError());
if (SUCCEEDED(hr))
m_fIOCompletionRegistered = TRUE;
}
// do not queue new requests if an error was previously recorded
if (SUCCEEDED(hr)) {
hr = HRESULT_FROM_WIN32(m_dwAsyncError);
}
// we'll return error here if anything went wrong. Otherwise, we're
// going to execute the rest of the logic and return S_OK. Any
// errors downstream from here will report through the completion
// functions.
if (FAILED(hr))
return hr;
m_dwRequestStatus = HSE_STATUS_PENDING;
EnterCriticalSection(&m_csPendingSendCS);
BOOL fFirstEntry = m_listPendingSends.FIsEmpty();
pVectorCB->AppendTo(m_listPendingSends);
LeaveCriticalSection(&m_csPendingSendCS);
// if the list was empty, then call IssueNextSend() to get things started
if (fFirstEntry)
IssueNextSend();
return S_OK;
}
/*===================================================================
CIsapiReqInfo::IssueNextSend
Enters the critical section to grab the first entry on the queue.
Note that the entry is left on the list. This is the easiest
way to communicate with the completion routine which
CAsyncVectorSendCB just completed.
Errors are handled by creating a "fake" completion - i.e the
registered completion function is called from here instead of
by the core.
===================================================================*/
void CIsapiReqInfo::IssueNextSend()
{
CAsyncVectorSendCB *pVectorSendCB = NULL;
HRESULT hr = S_OK;
DWORD dwIOError = 0;
EnterCriticalSection(&m_csPendingSendCS);
if (!m_listPendingSends.FIsEmpty()) {
pVectorSendCB = (CAsyncVectorSendCB *)m_listPendingSends.PNext();
}
LeaveCriticalSection(&m_csPendingSendCS);
if (pVectorSendCB) {
// increment here that there is about to be an outstanding
// async write. Note that it is possible that an error
// condition could result in the AsyncCompletion being called
// and that routine decrements this counter. Again, once were
// at this point, one way or another, the async completion
// routine is going to be called.
InterlockedIncrement(&g_nOutstandingAsyncWrites);
// check to see if an error was previously recorded
if (m_dwAsyncError) {
dwIOError = m_dwAsyncError;
}
// otherwise, call HSE_REQ_VECTOR_SEND
else if (ServerSupportFunction(HSE_REQ_VECTOR_SEND,
&pVectorSendCB->m_hseResponseVector,
NULL,
NULL) == FALSE) {
dwIOError = GetLastError();
}
// if an error has been noted, call the AsyncCompletion to clean
// things up
if (dwIOError) {
CIsapiReqInfo::AsyncCompletion(pVectorSendCB->m_pIReq->m_pECB,
pVectorSendCB->m_pIReq,
0,
dwIOError);
}
}
}
/*===================================================================
CIsapiReqInfo::AsyncCompletion
Called to handle the successful, or unsuccessful, completion of
a pending async send.
The logic is pretty straightforward. Grab the head entry on the
async pending queue, call the completion function, call
call IssueNextSend() to keep the send chain going, release this
reference on the IsapiReqInfo.
===================================================================*/
WINAPI CIsapiReqInfo::AsyncCompletion(EXTENSION_CONTROL_BLOCK * pECB,
PVOID pContext,
DWORD cbIO,
DWORD dwError)
{
CIsapiReqInfo *pIReq = (CIsapiReqInfo *)pContext;
CAsyncVectorSendCB *pCB;
BOOL fIsEmpty;
InterlockedDecrement(&g_nOutstandingAsyncWrites);
// if an error is being reported, note it.
// do it here, so subsequent new requests do not get added to the queue and dispatched
if (dwError)
pIReq->m_dwAsyncError = dwError;
//
// the following block is normally executed once, to handle the completed control
// block. However, in case of an error, we'll itterate on the queue until it drains.
//
do {
// lock the CS and get the head
EnterCriticalSection(&pIReq->m_csPendingSendCS);
Assert(!pIReq->m_listPendingSends.FIsEmpty());
pCB = (CAsyncVectorSendCB *)pIReq->m_listPendingSends.PNext();
// this wouldn't be good, and likely impossible because if
// the list is empty, it will return the head pointer.
Assert(pCB);
Assert(pIReq == pCB->m_pIReq);
// remove it from the list
pCB->UnLink();
fIsEmpty = pIReq->m_listPendingSends.FIsEmpty();
LeaveCriticalSection(&pIReq->m_csPendingSendCS);
// call the client's completion function
pCB->m_pCallerFunc(pCB->m_pIReq, pCB->m_pCallerContext, cbIO, dwError);
// we are done with this CAsyncVectorSendCB
delete pCB;
// if no error occured, break out and keep going
if (!dwError) {
break;
}
} while ( !fIsEmpty );
// keep the sends going, if there are sends to do
if (!fIsEmpty)
pIReq->IssueNextSend();
}
/*===================================================================
CAsyncVectorSendCB::CAsyncVectorSendCB
Base Constructor - clear everything
===================================================================*/
CAsyncVectorSendCB::CAsyncVectorSendCB() {
m_pIReq = NULL;
m_pCallerContext = NULL;
m_pCallerFunc = NULL;
m_pVectorElements = m_aVectorElements;
ZeroMemory(&m_hseResponseVector, sizeof(HSE_RESPONSE_VECTOR));
ZeroMemory(m_pVectorElements,
sizeof(m_aVectorElements));
}
/*===================================================================
CAsyncVectorSendCB::CAsyncVectorSendCB
Overriden Constructor - sets some members based on passed in
values.
===================================================================*/
CAsyncVectorSendCB::CAsyncVectorSendCB(CIsapiReqInfo *pIReq,
void *pContext,
PFN_CLIENT_IO_COMPLETION pFunc) {
ZeroMemory(&m_hseResponseVector, sizeof(HSE_RESPONSE_VECTOR));
m_pIReq = pIReq;
m_pCallerContext = pContext;
m_pCallerFunc = pFunc;
m_pVectorElements = m_aVectorElements;
ZeroMemory(m_pVectorElements,
sizeof(m_aVectorElements));
pIReq->AddRef();
}
/*===================================================================
CAsyncVectorSendCB::~CAsyncVectorSendCB
Destructor - cleans up
===================================================================*/
CAsyncVectorSendCB::~CAsyncVectorSendCB() {
// if m_pVectorElements is not pointing to the built-in array,
// then it must be allocated memory. Free it.
if (m_pVectorElements && (m_pVectorElements != m_aVectorElements))
free(m_pVectorElements);
// free the Headers and Status strings, if allocated
if (m_hseResponseVector.pszHeaders)
free(m_hseResponseVector.pszHeaders);
if (m_hseResponseVector.pszStatus)
free(m_hseResponseVector.pszStatus);
if (m_pIReq) {
m_pIReq->Release();
m_pIReq = NULL;
}
}
/*===================================================================
CAsyncVectorSendCB::SetElementCount
Makes sure that m_pVectorElements is sufficiently sized. If the
number of elements is less than or equal to the size of the
built-in array, it is used. If not, one is allocated.
===================================================================*/
HRESULT CAsyncVectorSendCB::SetElementCount(DWORD nElements)
{
if (nElements <= (sizeof(m_aVectorElements)/sizeof(HSE_VECTOR_ELEMENT)))
return S_OK;
m_pVectorElements = (HSE_VECTOR_ELEMENT *)malloc(sizeof(HSE_VECTOR_ELEMENT)*nElements);
if (m_pVectorElements == NULL) {
return E_OUTOFMEMORY;
}
ZeroMemory(m_pVectorElements,
nElements * sizeof(HSE_VECTOR_ELEMENT));
return S_OK;
}