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