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.
1173 lines
29 KiB
1173 lines
29 KiB
/*===================================================================
|
|
Microsoft Denali
|
|
|
|
Microsoft Confidential.
|
|
Copyright 1996 Microsoft Corporation. All Rights Reserved.
|
|
|
|
Component: Server object
|
|
|
|
File: Server.cpp
|
|
|
|
Owner: CGrant
|
|
|
|
This file contains the code for the implementation of the Server object.
|
|
===================================================================*/
|
|
#include "denpre.h"
|
|
#pragma hdrstop
|
|
|
|
#include "Server.h"
|
|
#include "tlbcache.h"
|
|
#include "memchk.h"
|
|
|
|
/*
|
|
*
|
|
* C S e r v e r
|
|
*
|
|
*/
|
|
|
|
/*===================================================================
|
|
CServer::CServer
|
|
|
|
Constructor
|
|
|
|
Parameters:
|
|
punkOuter object to ref count (can be NULL)
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CServer::CServer(IUnknown *punkOuter)
|
|
:
|
|
m_fInited(FALSE),
|
|
m_fDiagnostics(FALSE),
|
|
m_pUnkFTM(NULL),
|
|
m_pData(NULL)
|
|
{
|
|
CDispatch::Init(IID_IServer);
|
|
|
|
if (punkOuter)
|
|
{
|
|
m_punkOuter = punkOuter;
|
|
m_fOuterUnknown = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_cRefs = 1;
|
|
m_fOuterUnknown = FALSE;
|
|
}
|
|
|
|
#ifdef DBG
|
|
m_fDiagnostics = TRUE;
|
|
#endif // DBG
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::~CServer
|
|
|
|
Destructor
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
===================================================================*/
|
|
CServer::~CServer()
|
|
{
|
|
Assert(!m_fInited);
|
|
Assert(m_fOuterUnknown || m_cRefs == 0); // must have 0 ref count
|
|
|
|
if ( m_pUnkFTM != NULL )
|
|
{
|
|
m_pUnkFTM->Release();
|
|
m_pUnkFTM = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::Init
|
|
|
|
Allocates m_pData.
|
|
Performs any intiailization of a CServer that's prone to failure
|
|
that we also use internally before exposing the object outside.
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
S_OK on success.
|
|
===================================================================*/
|
|
|
|
HRESULT CServer::Init()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_fInited)
|
|
return S_OK; // already inited
|
|
|
|
Assert(!m_pData);
|
|
|
|
// Create the FTM
|
|
if (m_pUnkFTM == NULL)
|
|
{
|
|
hr = CoCreateFreeThreadedMarshaler( (IUnknown*)this, &m_pUnkFTM );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
Assert( m_pUnkFTM == NULL );
|
|
return (hr);
|
|
}
|
|
}
|
|
|
|
Assert( m_pUnkFTM != NULL );
|
|
|
|
|
|
m_pData = new CServerData;
|
|
if (!m_pData)
|
|
return E_OUTOFMEMORY;
|
|
|
|
m_pData->m_pIReq = NULL;
|
|
m_pData->m_pHitObj = NULL;
|
|
|
|
m_pData->m_ISupportErrImp.Init(static_cast<IServer *>(this),
|
|
static_cast<IServer *>(this),
|
|
IID_IServer);
|
|
|
|
m_fInited = TRUE;
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::UnInit
|
|
|
|
Remove m_pData. Make tombstone (UnInited state).
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT (S_OK)
|
|
===================================================================*/
|
|
HRESULT CServer::UnInit()
|
|
{
|
|
if (!m_fInited)
|
|
return S_OK; // already uninited
|
|
|
|
Assert(m_pData);
|
|
delete m_pData;
|
|
m_pData = NULL;
|
|
|
|
// Disconnect proxies NOW (in case we are in shutdown, or enter shutdown later & a proxy has a ref.)
|
|
CoDisconnectObject(static_cast<IServerImpl *>(this), 0);
|
|
|
|
m_fInited = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::ReInit
|
|
|
|
The only need for a re-init here is to update the CIsapiReqInfo
|
|
for this request, the CIsapiReqInfo is required to access the
|
|
MapPath Method. Ideally this method should be part of the Request
|
|
object
|
|
|
|
Parameters:
|
|
CIsapiReqInfo *
|
|
CHitObj *
|
|
|
|
Returns:
|
|
S_OK on success.
|
|
|
|
===================================================================*/
|
|
HRESULT CServer::ReInit
|
|
(
|
|
CIsapiReqInfo * pIReq,
|
|
CHitObj *pHitObj
|
|
)
|
|
{
|
|
Assert(m_fInited);
|
|
Assert(m_pData);
|
|
|
|
m_pData->m_pIReq = pIReq;
|
|
m_pData->m_pHitObj = pHitObj;
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::MapPathInternal
|
|
|
|
Map virtual path BSTR into single char buffer
|
|
Used by MapPath(), Execute(), Transfer()
|
|
|
|
Parameters:
|
|
dwContextId for error messages
|
|
wszVirtPath path to translate
|
|
szPhysPath [out] translate into this buffer (MAX_PATH sized)
|
|
szVirtPath [out, optional] mb virtual path buffer (MAX_PATH sized)
|
|
|
|
Returns:
|
|
S_OK on success.
|
|
===================================================================*/
|
|
HRESULT CServer::MapPathInternal
|
|
(
|
|
DWORD dwContextId,
|
|
WCHAR *wszVirtPath,
|
|
TCHAR *szPhysPath,
|
|
TCHAR *szVirtPath
|
|
)
|
|
{
|
|
// increment the pointer past leading white spaces
|
|
wchar_t *wszLogicalPath = wszVirtPath;
|
|
while (iswspace(*wszLogicalPath))
|
|
++wszLogicalPath;
|
|
|
|
unsigned cchLogicalPath = wcslen(wszLogicalPath);
|
|
if (cchLogicalPath > MAX_PATH-1)
|
|
{
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer, dwContextId, IDE_SERVER_EXCEDED_MAX_PATH);
|
|
return E_FAIL;
|
|
}
|
|
|
|
else if (cchLogicalPath == 0)
|
|
{
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_STR);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Is this a physical path?
|
|
if (iswalpha(wszLogicalPath[0]) && wszLogicalPath[1] == L':')
|
|
{
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_PHY_STR);
|
|
return E_FAIL;
|
|
}
|
|
|
|
// simple validation: look for invalid characters in string [*?<>,;:'"]
|
|
// and multiple slash characters ie "//" or "\\"
|
|
//
|
|
BOOL fParentPath = FALSE;
|
|
BOOL fEnableParentPaths = m_pData->m_pHitObj->QueryAppConfig()->fEnableParentPaths();
|
|
BOOL fAnyBackslashes = FALSE;
|
|
wchar_t *pwchT = wszLogicalPath;
|
|
while (*pwchT != L'\0')
|
|
{
|
|
switch (*pwchT)
|
|
{
|
|
case L'*': case L':': case L'?': case L'<':
|
|
case L'>': case L',': case L'"':
|
|
if (dwContextId)
|
|
ExceptionId( IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_CHR);
|
|
return E_FAIL;
|
|
|
|
case L'.':
|
|
if (*++pwchT == L'.')
|
|
{
|
|
if (!fEnableParentPaths)
|
|
{
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_CHR3);
|
|
return E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
fParentPath = TRUE;
|
|
++pwchT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case L'\\':
|
|
fAnyBackslashes = TRUE;
|
|
case L'/':
|
|
++pwchT;
|
|
if (*pwchT == L'/' || *pwchT == L'\\')
|
|
{
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_CHR2);
|
|
return E_FAIL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
++pwchT;
|
|
}
|
|
}
|
|
|
|
// whew! Error handling done!
|
|
// Convert wszLogicalPath to multi-byte
|
|
|
|
TCHAR szLogicalPath[MAX_PATH];
|
|
#if UNICODE
|
|
wcscpy(szLogicalPath, wszLogicalPath);
|
|
#else
|
|
HRESULT hr;
|
|
CWCharToMBCS convStr;
|
|
|
|
if (hr = convStr.Init(wszLogicalPath)) {
|
|
if ((hr == E_OUTOFMEMORY) && dwContextId)
|
|
ExceptionId(IID_IServer, dwContextId, IDE_OOM);
|
|
return hr;
|
|
}
|
|
|
|
if (convStr.GetStringLen() > (MAX_PATH-1)) {
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer, dwContextId, IDE_SERVER_EXCEDED_MAX_PATH);
|
|
return E_FAIL;
|
|
}
|
|
strcpy(szLogicalPath,convStr.GetString());
|
|
#endif
|
|
|
|
// change all backslashes to forward slashes
|
|
if (fAnyBackslashes)
|
|
{
|
|
TCHAR *pbBackslash = szLogicalPath;
|
|
while (pbBackslash = _tcschr(pbBackslash, _T('\\')))
|
|
*pbBackslash = _T('/');
|
|
}
|
|
|
|
// is this a Relative path request. I.E. no leading slash
|
|
// if so prepend the path_info string to szLogicalPath
|
|
|
|
BOOL fPathAlreadyIsMapped = FALSE; // Some cases map the path earlier
|
|
if (szLogicalPath[0] != _T('/'))
|
|
{
|
|
if (_tcslen(m_pData->m_pIReq->QueryPszPathInfo()) >= MAX_PATH)
|
|
{
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer, dwContextId, IDE_SERVER_EXCEDED_MAX_PATH);
|
|
return E_FAIL;
|
|
}
|
|
|
|
TCHAR szParentPath[MAX_PATH];
|
|
_tcscpy(szParentPath, m_pData->m_pIReq->QueryPszPathInfo());
|
|
|
|
szParentPath[MAX_PATH-1] = _T('\0');
|
|
|
|
// Trim off the ASP file name from the PATH_INFO
|
|
TCHAR *pchT = _tcsrchr(szParentPath, _T('/'));
|
|
if (pchT != NULL) *pchT = '\0';
|
|
|
|
// If there were parent paths, map the parent now, then append the relative path
|
|
// the relative path to the parent path
|
|
if (fParentPath)
|
|
{
|
|
Assert (fEnableParentPaths); // Errors should have been flagged upstairs
|
|
DWORD dwPathSize = sizeof(szParentPath);
|
|
if (! m_pData->m_pIReq->MapUrlToPath(szParentPath, &dwPathSize))
|
|
{
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer,
|
|
dwContextId,
|
|
::GetLastError() == ERROR_INSUFFICIENT_BUFFER? IDE_SERVER_EXCEDED_MAX_PATH : IDE_SERVER_MAPPATH_FAILED);
|
|
return E_FAIL;
|
|
}
|
|
|
|
fPathAlreadyIsMapped = TRUE;
|
|
}
|
|
|
|
// Resolve relative paths
|
|
if (! DotPathToPath(szLogicalPath, szLogicalPath, szParentPath))
|
|
{
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_FAILED);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
// return virtual path if requested
|
|
if (szVirtPath)
|
|
_tcscpy(szVirtPath, szLogicalPath);
|
|
|
|
// Map this to a physical file name (if required)
|
|
if (!fPathAlreadyIsMapped)
|
|
{
|
|
DWORD dwPathSize = sizeof(szLogicalPath);
|
|
if (! m_pData->m_pIReq->MapUrlToPath(szLogicalPath, &dwPathSize))
|
|
{
|
|
if (dwContextId)
|
|
ExceptionId(IID_IServer,
|
|
dwContextId,
|
|
::GetLastError() == ERROR_INSUFFICIENT_BUFFER? IDE_SERVER_EXCEDED_MAX_PATH : IDE_SERVER_MAPPATH_FAILED);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
// remove any ending delimiters (unless it's the root directory. The root always starts with drive letter)
|
|
TCHAR *pchT = CharPrev(szLogicalPath, szLogicalPath + _tcslen(szLogicalPath));
|
|
if ((*pchT == _T('/') || *pchT == _T('\\')) && pchT[-1] != _T(':'))
|
|
{
|
|
*pchT = _T('\0');
|
|
}
|
|
|
|
// Replace forward slash with back slash
|
|
for (pchT = szLogicalPath; *pchT != _T('\0'); ++pchT)
|
|
{
|
|
if (*pchT == _T('/'))
|
|
*pchT = _T('\\');
|
|
}
|
|
|
|
_tcscpy(szPhysPath, szLogicalPath);
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::QueryInterface
|
|
CServer::AddRef
|
|
CServer::Release
|
|
|
|
IUnknown members for CServer object.
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::QueryInterface
|
|
(
|
|
REFIID riid,
|
|
PPVOID ppv
|
|
)
|
|
{
|
|
*ppv = NULL;
|
|
|
|
/*
|
|
* The only calls for IUnknown are either in a nonaggregated
|
|
* case or when created in an aggregation, so in either case
|
|
* always return our IUnknown for IID_IUnknown.
|
|
*/
|
|
|
|
// BUG FIX 683 added IID_IDenaliIntrinsic to prevent the user from
|
|
// storing intrinsic objects in the application and session object
|
|
|
|
if (IID_IUnknown == riid ||
|
|
IID_IDispatch == riid ||
|
|
IID_IServer == riid ||
|
|
IID_IDenaliIntrinsic == riid)
|
|
*ppv = static_cast<IServer *>(this);
|
|
|
|
//Indicate that we support error information
|
|
if (IID_ISupportErrorInfo == riid)
|
|
{
|
|
if (m_pData)
|
|
*ppv = & (m_pData->m_ISupportErrImp);
|
|
}
|
|
|
|
if (IID_IMarshal == riid)
|
|
{
|
|
Assert( m_pUnkFTM != NULL );
|
|
|
|
if ( m_pUnkFTM == NULL )
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
return m_pUnkFTM->QueryInterface( riid, ppv );
|
|
|
|
}
|
|
|
|
//AddRef any interface we'll return.
|
|
if (NULL != *ppv)
|
|
{
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CServer::AddRef()
|
|
{
|
|
if (m_fOuterUnknown)
|
|
return m_punkOuter->AddRef();
|
|
|
|
return InterlockedIncrement((LPLONG)&m_cRefs);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CServer::Release()
|
|
{
|
|
if (m_fOuterUnknown)
|
|
return m_punkOuter->Release();
|
|
|
|
DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs);
|
|
if (cRefs)
|
|
return cRefs;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::GetIDsOfNames
|
|
|
|
Special-case implementation for CreateObject, Execute, Transfer
|
|
|
|
Parameters:
|
|
riid REFIID reserved. Must be IID_NULL.
|
|
rgszNames OLECHAR ** pointing to the array of names to be mapped.
|
|
cNames UINT number of names to be mapped.
|
|
lcid LCID of the locale.
|
|
rgDispID DISPID * caller allocated array containing IDs
|
|
corresponging to those names in rgszNames.
|
|
|
|
Return Value:
|
|
HRESULT S_OK or a general error code.
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::GetIDsOfNames
|
|
(
|
|
REFIID riid,
|
|
OLECHAR **rgszNames,
|
|
UINT cNames,
|
|
LCID lcid,
|
|
DISPID *rgDispID
|
|
)
|
|
{
|
|
const DISPID dispidCreateObject = 0x60020002;
|
|
const DISPID dispidExecute = 0x60020007;
|
|
const DISPID dispidTransfer = 0x60020008;
|
|
|
|
if (cNames == 1)
|
|
{
|
|
switch (rgszNames[0][0])
|
|
{
|
|
case L'C':
|
|
case L'c':
|
|
if (wcsicmp(rgszNames[0]+1, L"reateobject") == 0)
|
|
{
|
|
*rgDispID = dispidCreateObject;
|
|
return S_OK;
|
|
}
|
|
break;
|
|
|
|
case L'E':
|
|
case L'e':
|
|
if (wcsicmp(rgszNames[0]+1, L"xecute") == 0)
|
|
{
|
|
*rgDispID = dispidExecute;
|
|
return S_OK;
|
|
}
|
|
break;
|
|
|
|
case L'T':
|
|
case L't':
|
|
if (wcsicmp(rgszNames[0]+1, L"ransfer") == 0)
|
|
{
|
|
*rgDispID = dispidTransfer;
|
|
return S_OK;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// default to CDispatch's implementation
|
|
return CDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispID);
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::CheckForTombstone
|
|
|
|
Tombstone stub for IServer methods. If the object is
|
|
tombstone, does ExceptionId and fails.
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
HRESULT E_FAIL if Tombstone
|
|
S_OK if not
|
|
===================================================================*/
|
|
HRESULT CServer::CheckForTombstone()
|
|
{
|
|
if (m_fInited)
|
|
{
|
|
// inited - good object
|
|
Assert(m_pData); // must be present for inited objects
|
|
return S_OK;
|
|
}
|
|
|
|
ExceptionId
|
|
(
|
|
IID_IServer,
|
|
IDE_SERVER,
|
|
IDE_INTRINSIC_OUT_OF_SCOPE
|
|
);
|
|
return E_FAIL;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::CreateObject
|
|
|
|
Parameters: BSTR containing ProgID
|
|
Variant to fillin with IUknown pointer
|
|
|
|
Returns: S_OK if successful E_FAIL otherwise
|
|
|
|
Side effects:
|
|
Creates an instance of an ole automation object
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::CreateObject(BSTR bstrProgID, IDispatch **ppDispObj)
|
|
{
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
if (bstrProgID == NULL)
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_EXPECTING_STR);
|
|
return E_FAIL;
|
|
}
|
|
|
|
Assert(m_pData->m_pHitObj);
|
|
|
|
*ppDispObj = NULL;
|
|
|
|
HRESULT hr;
|
|
CLSID clsid;
|
|
|
|
if (Glob(fEnableTypelibCache))
|
|
{
|
|
// Use typelib cache to create the component
|
|
|
|
hr = g_TypelibCache.CreateComponent
|
|
(
|
|
bstrProgID,
|
|
m_pData->m_pHitObj,
|
|
ppDispObj,
|
|
&clsid
|
|
);
|
|
|
|
if (FAILED(hr) && clsid == CLSID_NULL)
|
|
{
|
|
// bad prog id or something
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_FAILED, hr);
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Don't use typelib cache
|
|
|
|
hr = CLSIDFromProgID((LPCOLESTR)bstrProgID, &clsid);
|
|
if (FAILED(hr))
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_FAILED, hr);
|
|
return hr;
|
|
}
|
|
|
|
hr = m_pData->m_pHitObj->CreateComponent(clsid, ppDispObj);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
return S_OK;
|
|
|
|
// Check if a custom error was already posted
|
|
IErrorInfo *pErrInfo = NULL;
|
|
if (GetErrorInfo(0, &pErrInfo) == S_OK && pErrInfo)
|
|
{
|
|
SetErrorInfo(0, pErrInfo);
|
|
pErrInfo->Release();
|
|
}
|
|
// Standard errors
|
|
else if (hr == E_ACCESSDENIED)
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_DENIED);
|
|
else
|
|
{
|
|
if (hr == REGDB_E_CLASSNOTREG)
|
|
{
|
|
BOOL fInProc;
|
|
if (SUCCEEDED(CompModelFromCLSID(clsid, NULL, &fInProc)) && !fInProc)
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_NOTINPROC);
|
|
}
|
|
}
|
|
else
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_FAILED, hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::MapPath
|
|
|
|
Return the physical path translated from a logical path
|
|
|
|
Parameters:
|
|
BSTR bstrLogicalPath
|
|
BSTR FAR * pbstrPhysicalPath
|
|
|
|
Returns:
|
|
HRESULT S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::MapPath(BSTR bstrLogicalPath, BSTR FAR * pbstrPhysicalPath)
|
|
{
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
// Bug 1361: error if no CIsapiReqInfo (presumably called during
|
|
// Application_OnEnd or Session_OnEnd)
|
|
if (m_pData->m_pIReq == NULL)
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL);
|
|
return E_FAIL;
|
|
}
|
|
|
|
AssertValid();
|
|
Assert (pbstrPhysicalPath != NULL);
|
|
*pbstrPhysicalPath = NULL;
|
|
|
|
// use MapPathInternal() to do the mapping
|
|
TCHAR szLogicalPath[MAX_PATH];
|
|
HRESULT hr = MapPathInternal(IDE_SERVER_MAPPATH, bstrLogicalPath, szLogicalPath);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
#if UNICODE
|
|
*pbstrPhysicalPath = SysAllocString(szLogicalPath);
|
|
if (*pbstrPhysicalPath == NULL) {
|
|
ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_OOM);
|
|
return E_FAIL;
|
|
}
|
|
#else
|
|
// Convert the path to wide character
|
|
if (FAILED(SysAllocStringFromSz(szLogicalPath, 0, pbstrPhysicalPath, CP_ACP))) {
|
|
ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_OOM);
|
|
return E_FAIL;
|
|
}
|
|
#endif
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::HTMLEncode
|
|
|
|
Encodes a string to HTML standards
|
|
|
|
Parameters:
|
|
BSTR bstrIn value: string to be encoded
|
|
BSTR FAR * pbstrEncoded value: pointer to HTML encoded version of string
|
|
|
|
Returns:
|
|
HRESULT S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::HTMLEncode ( BSTR bstrIn, BSTR FAR * pbstrEncoded )
|
|
{
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
char* pszstrIn = NULL;
|
|
char* pszEncodedstr = NULL;
|
|
char* pszStartEncodestr = NULL;
|
|
int nbstrLen = 0;
|
|
int nstrLen = 0;
|
|
HRESULT hr = S_OK;
|
|
UINT uCodePage = m_pData->m_pHitObj->GetCodePage();
|
|
CWCharToMBCS convIn;
|
|
|
|
STACK_BUFFER( tempHTML, 2048 );
|
|
|
|
if (bstrIn)
|
|
nbstrLen = wcslen(bstrIn);
|
|
else
|
|
nbstrLen = 0;
|
|
|
|
if (nbstrLen <= 0)
|
|
return S_OK;
|
|
|
|
if (FAILED(hr = convIn.Init(bstrIn, uCodePage))) {
|
|
if (hr == E_OUTOFMEMORY)
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
|
|
goto L_Exit;
|
|
}
|
|
|
|
pszstrIn = convIn.GetString();
|
|
|
|
nstrLen = HTMLEncodeLen(pszstrIn, uCodePage, bstrIn);
|
|
|
|
if (nstrLen > 0)
|
|
{
|
|
|
|
//Encode string , NOTE this function returns a pointer to the
|
|
// NULL so you need to keep a pointer to the start of the string
|
|
//
|
|
|
|
if (!tempHTML.Resize(nstrLen + 2)) {
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
|
|
hr = E_FAIL;
|
|
goto L_Exit;
|
|
}
|
|
|
|
pszEncodedstr = (char*)tempHTML.QueryPtr();
|
|
|
|
pszStartEncodestr = pszEncodedstr;
|
|
pszEncodedstr = ::HTMLEncode( pszEncodedstr, pszstrIn, uCodePage, bstrIn);
|
|
|
|
// convert result to bstr
|
|
//
|
|
if (FAILED(SysAllocStringFromSz(pszStartEncodestr, 0, pbstrEncoded, uCodePage)))
|
|
{
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
|
|
hr = E_FAIL;
|
|
goto L_Exit;
|
|
}
|
|
}
|
|
|
|
L_Exit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
CServer::URLEncode
|
|
|
|
Encodes a query string to URL standards
|
|
|
|
Parameters:
|
|
BSTR bstrIn value: string to be URL encoded
|
|
BSTR FAR * pbstrEncoded value: pointer to URL encoded version of string
|
|
|
|
Returns:
|
|
HRESULT S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::URLEncode ( BSTR bstrIn, BSTR FAR * pbstrEncoded )
|
|
{
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
char* pszstrIn = NULL;
|
|
char* pszEncodedstr = NULL;
|
|
char* pszStartEncodestr = NULL;
|
|
int nbstrLen = 0;
|
|
int nstrLen = 0;
|
|
HRESULT hr = S_OK;
|
|
CWCharToMBCS convIn;
|
|
|
|
STACK_BUFFER( tempURL, 256 );
|
|
|
|
if (bstrIn)
|
|
nbstrLen = wcslen(bstrIn);
|
|
else
|
|
nbstrLen = 0;
|
|
|
|
if (nbstrLen <= 0)
|
|
return S_OK;
|
|
|
|
if (FAILED(hr = convIn.Init(bstrIn, m_pData->m_pHitObj->GetCodePage()))) {
|
|
if (hr == E_OUTOFMEMORY)
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
|
|
goto L_Exit;
|
|
}
|
|
|
|
pszstrIn = convIn.GetString();
|
|
|
|
nstrLen = URLEncodeLen(pszstrIn);
|
|
if (nstrLen > 0)
|
|
{
|
|
|
|
//Encode string , NOTE this function returns a pointer to the
|
|
// NULL so you need to keep a pointer to the start of the string
|
|
//
|
|
|
|
if (!tempURL.Resize(nstrLen + 2)) {
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
|
|
hr = E_FAIL;
|
|
goto L_Exit;
|
|
}
|
|
|
|
pszEncodedstr = (char *)tempURL.QueryPtr();
|
|
|
|
pszStartEncodestr = pszEncodedstr;
|
|
pszEncodedstr = ::URLEncode( pszEncodedstr, pszstrIn );
|
|
|
|
// convert result to bstr
|
|
//
|
|
if (FAILED(SysAllocStringFromSz(pszStartEncodestr, 0, pbstrEncoded)))
|
|
{
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
|
|
hr = E_FAIL;
|
|
goto L_Exit;
|
|
}
|
|
}
|
|
|
|
L_Exit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::URLPathEncode
|
|
|
|
Encodes the path portion of a URL or a full URL. All characters
|
|
up to the first '?' are encoded with the following rules:
|
|
o Charcters that are needed to parse the URL are left alone
|
|
o RFC 1630 safe characters are left alone
|
|
o Non-foreign alphanumberic characters are left alone
|
|
o Anything else is escape encoded
|
|
Everything after the '?' is not encoded.
|
|
|
|
Parameters:
|
|
BSTR bstrIn value: string to be URL path encoded
|
|
BSTR FAR * pbstrEncoded value: pointer to URL path encoded version of string
|
|
|
|
Returns:
|
|
HRESULT S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::URLPathEncode ( BSTR bstrIn, BSTR FAR * pbstrEncoded )
|
|
{
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
char* pszstrIn = NULL;
|
|
char* pszEncodedstr = NULL;
|
|
char* pszStartEncodestr = NULL;
|
|
int nbstrLen = 0;
|
|
int nstrLen = 0;
|
|
HRESULT hr = S_OK;
|
|
CWCharToMBCS convIn;
|
|
|
|
STACK_BUFFER( tempPath, 256 );
|
|
|
|
if (bstrIn)
|
|
nbstrLen = wcslen(bstrIn);
|
|
else
|
|
nbstrLen = 0;
|
|
|
|
if (nbstrLen <= 0)
|
|
return S_OK;
|
|
|
|
if (FAILED(hr = convIn.Init(bstrIn, m_pData->m_pHitObj->GetCodePage()))) {
|
|
if (hr == E_OUTOFMEMORY)
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
|
|
goto L_Exit;
|
|
}
|
|
|
|
pszstrIn = convIn.GetString();
|
|
|
|
nstrLen = URLPathEncodeLen(pszstrIn);
|
|
if (nstrLen > 0)
|
|
{
|
|
|
|
//Encode string , NOTE this function returns a pointer to the
|
|
// NULL so you need to keep a pointer to the start of the string
|
|
//
|
|
|
|
if (!tempPath.Resize(nstrLen+2)) {
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
|
|
hr = E_FAIL;
|
|
goto L_Exit;
|
|
}
|
|
|
|
pszEncodedstr = (char *)tempPath.QueryPtr();
|
|
|
|
pszStartEncodestr = pszEncodedstr;
|
|
pszEncodedstr = ::URLPathEncode( pszEncodedstr, pszstrIn );
|
|
|
|
// convert result to bstr
|
|
//
|
|
if (FAILED(SysAllocStringFromSz(pszStartEncodestr, 0, pbstrEncoded)))
|
|
{
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
|
|
hr = E_FAIL;
|
|
goto L_Exit;
|
|
}
|
|
}
|
|
|
|
L_Exit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::get_ScriptTimeout
|
|
|
|
Will return the script timeout interval (in seconds)
|
|
|
|
Parameters:
|
|
long *plTimeoutSeconds
|
|
|
|
Returns:
|
|
HRESULT S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::get_ScriptTimeout( long * plTimeoutSeconds )
|
|
{
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
if (m_pData->m_pHitObj == NULL)
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL);
|
|
return(E_FAIL);
|
|
}
|
|
*plTimeoutSeconds = m_pData->m_pHitObj->GetScriptTimeout();
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::put_ScriptTimeout
|
|
|
|
Allows the user to set the timeout interval for a script (in seconds)
|
|
|
|
Parameters:
|
|
long lTimeoutSeconds
|
|
|
|
Returns:
|
|
HRESULT S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::put_ScriptTimeout( long lTimeoutSeconds )
|
|
{
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
if ( lTimeoutSeconds < 0 )
|
|
{
|
|
ExceptionId( IID_IServer, IDE_SERVER, IDE_SERVER_INVALID_TIMEOUT );
|
|
return E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
if (m_pData->m_pHitObj == NULL)
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL);
|
|
return(E_FAIL);
|
|
}
|
|
m_pData->m_pHitObj->SetScriptTimeout(lTimeoutSeconds);
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::Execute
|
|
|
|
Execute an ASP
|
|
|
|
Parameters:
|
|
bstrURL URL to execute
|
|
|
|
Returns:
|
|
HRESULT S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::Execute(BSTR bstrURL)
|
|
{
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
if (m_pData->m_pIReq == NULL || m_pData->m_pHitObj == NULL)
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_INVALID_CALL);
|
|
return E_FAIL;
|
|
}
|
|
|
|
TCHAR szTemplate[MAX_PATH], szVirtTemp[MAX_PATH];
|
|
HRESULT hr = MapPathInternal(IDE_SERVER, bstrURL, szTemplate, szVirtTemp);
|
|
if (FAILED(hr))
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_EXECUTE_INVALID_PATH);
|
|
return hr;
|
|
}
|
|
Normalize(szTemplate);
|
|
|
|
hr = m_pData->m_pHitObj->ExecuteChildRequest(FALSE, szTemplate, szVirtTemp);
|
|
if (FAILED(hr))
|
|
{
|
|
if (m_pData->m_pHitObj->FHasASPError()) // error already reported
|
|
return hr;
|
|
|
|
ExceptionId(IID_IServer, IDE_SERVER, (hr == E_COULDNT_OPEN_SOURCE_FILE) ?
|
|
IDE_SERVER_EXECUTE_CANTLOAD : IDE_SERVER_EXECUTE_FAILED);
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::Transfer
|
|
|
|
Transfer execution an ASP
|
|
|
|
Parameters:
|
|
bstrURL URL to execute
|
|
|
|
Returns:
|
|
HRESULT S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::Transfer(BSTR bstrURL)
|
|
{
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
if (m_pData->m_pIReq == NULL || m_pData->m_pHitObj == NULL)
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL);
|
|
return E_FAIL;
|
|
}
|
|
|
|
TCHAR szTemplate[MAX_PATH], szVirtTemp[MAX_PATH];
|
|
HRESULT hr = MapPathInternal(IDE_SERVER, bstrURL, szTemplate, szVirtTemp);
|
|
if (FAILED(hr))
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_TRANSFER_INVALID_PATH);
|
|
return hr;
|
|
}
|
|
Normalize(szTemplate);
|
|
|
|
hr = m_pData->m_pHitObj->ExecuteChildRequest(TRUE, szTemplate, szVirtTemp);
|
|
if (FAILED(hr))
|
|
{
|
|
if (m_pData->m_pHitObj->FHasASPError()) // error already reported
|
|
return hr;
|
|
|
|
ExceptionId(IID_IServer, IDE_SERVER, (hr == E_COULDNT_OPEN_SOURCE_FILE) ?
|
|
IDE_SERVER_TRANSFER_CANTLOAD : IDE_SERVER_TRANSFER_FAILED);
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CServer::GetLastError
|
|
|
|
Get ASPError object for the last error
|
|
|
|
Parameters:
|
|
ppASPErrorObject [out] the error object
|
|
|
|
Returns:
|
|
HRESULT S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CServer::GetLastError(IASPError **ppASPErrorObject)
|
|
{
|
|
*ppASPErrorObject = NULL;
|
|
|
|
if (FAILED(CheckForTombstone()))
|
|
return E_FAIL;
|
|
|
|
if (m_pData->m_pIReq == NULL || m_pData->m_pHitObj == NULL)
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_INVALID_CALL);
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT hr = m_pData->m_pHitObj->GetASPError(ppASPErrorObject);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ExceptionId(IID_IServer, IDE_SERVER, IDE_UNEXPECTED);
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#ifdef DBG
|
|
/*===================================================================
|
|
CServer::AssertValid
|
|
|
|
Test to make sure that the CServer object is currently correctly formed
|
|
and assert if it is not.
|
|
|
|
Returns:
|
|
|
|
Side effects:
|
|
None.
|
|
===================================================================*/
|
|
void CServer::AssertValid() const
|
|
{
|
|
Assert(m_fInited);
|
|
Assert(m_pData);
|
|
Assert(m_pData->m_pIReq);
|
|
}
|
|
#endif DBG
|