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.

1173 lines
29 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Server object
  6. File: Server.cpp
  7. Owner: CGrant
  8. This file contains the code for the implementation of the Server object.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "Server.h"
  13. #include "tlbcache.h"
  14. #include "memchk.h"
  15. /*
  16. *
  17. * C S e r v e r
  18. *
  19. */
  20. /*===================================================================
  21. CServer::CServer
  22. Constructor
  23. Parameters:
  24. punkOuter object to ref count (can be NULL)
  25. Returns:
  26. ===================================================================*/
  27. CServer::CServer(IUnknown *punkOuter)
  28. :
  29. m_fInited(FALSE),
  30. m_fDiagnostics(FALSE),
  31. m_pUnkFTM(NULL),
  32. m_pData(NULL)
  33. {
  34. CDispatch::Init(IID_IServer);
  35. if (punkOuter)
  36. {
  37. m_punkOuter = punkOuter;
  38. m_fOuterUnknown = TRUE;
  39. }
  40. else
  41. {
  42. m_cRefs = 1;
  43. m_fOuterUnknown = FALSE;
  44. }
  45. #ifdef DBG
  46. m_fDiagnostics = TRUE;
  47. #endif // DBG
  48. }
  49. /*===================================================================
  50. CServer::~CServer
  51. Destructor
  52. Parameters:
  53. Returns:
  54. ===================================================================*/
  55. CServer::~CServer()
  56. {
  57. Assert(!m_fInited);
  58. Assert(m_fOuterUnknown || m_cRefs == 0); // must have 0 ref count
  59. if ( m_pUnkFTM != NULL )
  60. {
  61. m_pUnkFTM->Release();
  62. m_pUnkFTM = NULL;
  63. }
  64. }
  65. /*===================================================================
  66. CServer::Init
  67. Allocates m_pData.
  68. Performs any intiailization of a CServer that's prone to failure
  69. that we also use internally before exposing the object outside.
  70. Parameters:
  71. None
  72. Returns:
  73. S_OK on success.
  74. ===================================================================*/
  75. HRESULT CServer::Init()
  76. {
  77. HRESULT hr = S_OK;
  78. if (m_fInited)
  79. return S_OK; // already inited
  80. Assert(!m_pData);
  81. // Create the FTM
  82. if (m_pUnkFTM == NULL)
  83. {
  84. hr = CoCreateFreeThreadedMarshaler( (IUnknown*)this, &m_pUnkFTM );
  85. if ( FAILED(hr) )
  86. {
  87. Assert( m_pUnkFTM == NULL );
  88. return (hr);
  89. }
  90. }
  91. Assert( m_pUnkFTM != NULL );
  92. m_pData = new CServerData;
  93. if (!m_pData)
  94. return E_OUTOFMEMORY;
  95. m_pData->m_pIReq = NULL;
  96. m_pData->m_pHitObj = NULL;
  97. m_pData->m_ISupportErrImp.Init(static_cast<IServer *>(this),
  98. static_cast<IServer *>(this),
  99. IID_IServer);
  100. m_fInited = TRUE;
  101. return hr;
  102. }
  103. /*===================================================================
  104. CServer::UnInit
  105. Remove m_pData. Make tombstone (UnInited state).
  106. Parameters:
  107. Returns:
  108. HRESULT (S_OK)
  109. ===================================================================*/
  110. HRESULT CServer::UnInit()
  111. {
  112. if (!m_fInited)
  113. return S_OK; // already uninited
  114. Assert(m_pData);
  115. delete m_pData;
  116. m_pData = NULL;
  117. // Disconnect proxies NOW (in case we are in shutdown, or enter shutdown later & a proxy has a ref.)
  118. CoDisconnectObject(static_cast<IServerImpl *>(this), 0);
  119. m_fInited = FALSE;
  120. return S_OK;
  121. }
  122. /*===================================================================
  123. CServer::ReInit
  124. The only need for a re-init here is to update the CIsapiReqInfo
  125. for this request, the CIsapiReqInfo is required to access the
  126. MapPath Method. Ideally this method should be part of the Request
  127. object
  128. Parameters:
  129. CIsapiReqInfo *
  130. CHitObj *
  131. Returns:
  132. S_OK on success.
  133. ===================================================================*/
  134. HRESULT CServer::ReInit
  135. (
  136. CIsapiReqInfo * pIReq,
  137. CHitObj *pHitObj
  138. )
  139. {
  140. Assert(m_fInited);
  141. Assert(m_pData);
  142. m_pData->m_pIReq = pIReq;
  143. m_pData->m_pHitObj = pHitObj;
  144. return S_OK;
  145. }
  146. /*===================================================================
  147. CServer::MapPathInternal
  148. Map virtual path BSTR into single char buffer
  149. Used by MapPath(), Execute(), Transfer()
  150. Parameters:
  151. dwContextId for error messages
  152. wszVirtPath path to translate
  153. szPhysPath [out] translate into this buffer (MAX_PATH sized)
  154. szVirtPath [out, optional] mb virtual path buffer (MAX_PATH sized)
  155. Returns:
  156. S_OK on success.
  157. ===================================================================*/
  158. HRESULT CServer::MapPathInternal
  159. (
  160. DWORD dwContextId,
  161. WCHAR *wszVirtPath,
  162. TCHAR *szPhysPath,
  163. TCHAR *szVirtPath
  164. )
  165. {
  166. // increment the pointer past leading white spaces
  167. wchar_t *wszLogicalPath = wszVirtPath;
  168. while (iswspace(*wszLogicalPath))
  169. ++wszLogicalPath;
  170. unsigned cchLogicalPath = wcslen(wszLogicalPath);
  171. if (cchLogicalPath > MAX_PATH-1)
  172. {
  173. if (dwContextId)
  174. ExceptionId(IID_IServer, dwContextId, IDE_SERVER_EXCEDED_MAX_PATH);
  175. return E_FAIL;
  176. }
  177. else if (cchLogicalPath == 0)
  178. {
  179. if (dwContextId)
  180. ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_STR);
  181. return E_FAIL;
  182. }
  183. // Is this a physical path?
  184. if (iswalpha(wszLogicalPath[0]) && wszLogicalPath[1] == L':')
  185. {
  186. if (dwContextId)
  187. ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_PHY_STR);
  188. return E_FAIL;
  189. }
  190. // simple validation: look for invalid characters in string [*?<>,;:'"]
  191. // and multiple slash characters ie "//" or "\\"
  192. //
  193. BOOL fParentPath = FALSE;
  194. BOOL fEnableParentPaths = m_pData->m_pHitObj->QueryAppConfig()->fEnableParentPaths();
  195. BOOL fAnyBackslashes = FALSE;
  196. wchar_t *pwchT = wszLogicalPath;
  197. while (*pwchT != L'\0')
  198. {
  199. switch (*pwchT)
  200. {
  201. case L'*': case L':': case L'?': case L'<':
  202. case L'>': case L',': case L'"':
  203. if (dwContextId)
  204. ExceptionId( IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_CHR);
  205. return E_FAIL;
  206. case L'.':
  207. if (*++pwchT == L'.')
  208. {
  209. if (!fEnableParentPaths)
  210. {
  211. if (dwContextId)
  212. ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_CHR3);
  213. return E_FAIL;
  214. }
  215. else
  216. {
  217. fParentPath = TRUE;
  218. ++pwchT;
  219. }
  220. }
  221. break;
  222. case L'\\':
  223. fAnyBackslashes = TRUE;
  224. case L'/':
  225. ++pwchT;
  226. if (*pwchT == L'/' || *pwchT == L'\\')
  227. {
  228. if (dwContextId)
  229. ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_INVALID_CHR2);
  230. return E_FAIL;
  231. }
  232. break;
  233. default:
  234. ++pwchT;
  235. }
  236. }
  237. // whew! Error handling done!
  238. // Convert wszLogicalPath to multi-byte
  239. TCHAR szLogicalPath[MAX_PATH];
  240. #if UNICODE
  241. wcscpy(szLogicalPath, wszLogicalPath);
  242. #else
  243. HRESULT hr;
  244. CWCharToMBCS convStr;
  245. if (hr = convStr.Init(wszLogicalPath)) {
  246. if ((hr == E_OUTOFMEMORY) && dwContextId)
  247. ExceptionId(IID_IServer, dwContextId, IDE_OOM);
  248. return hr;
  249. }
  250. if (convStr.GetStringLen() > (MAX_PATH-1)) {
  251. if (dwContextId)
  252. ExceptionId(IID_IServer, dwContextId, IDE_SERVER_EXCEDED_MAX_PATH);
  253. return E_FAIL;
  254. }
  255. strcpy(szLogicalPath,convStr.GetString());
  256. #endif
  257. // change all backslashes to forward slashes
  258. if (fAnyBackslashes)
  259. {
  260. TCHAR *pbBackslash = szLogicalPath;
  261. while (pbBackslash = _tcschr(pbBackslash, _T('\\')))
  262. *pbBackslash = _T('/');
  263. }
  264. // is this a Relative path request. I.E. no leading slash
  265. // if so prepend the path_info string to szLogicalPath
  266. BOOL fPathAlreadyIsMapped = FALSE; // Some cases map the path earlier
  267. if (szLogicalPath[0] != _T('/'))
  268. {
  269. if (_tcslen(m_pData->m_pIReq->QueryPszPathInfo()) >= MAX_PATH)
  270. {
  271. if (dwContextId)
  272. ExceptionId(IID_IServer, dwContextId, IDE_SERVER_EXCEDED_MAX_PATH);
  273. return E_FAIL;
  274. }
  275. TCHAR szParentPath[MAX_PATH];
  276. _tcscpy(szParentPath, m_pData->m_pIReq->QueryPszPathInfo());
  277. szParentPath[MAX_PATH-1] = _T('\0');
  278. // Trim off the ASP file name from the PATH_INFO
  279. TCHAR *pchT = _tcsrchr(szParentPath, _T('/'));
  280. if (pchT != NULL) *pchT = '\0';
  281. // If there were parent paths, map the parent now, then append the relative path
  282. // the relative path to the parent path
  283. if (fParentPath)
  284. {
  285. Assert (fEnableParentPaths); // Errors should have been flagged upstairs
  286. DWORD dwPathSize = sizeof(szParentPath);
  287. if (! m_pData->m_pIReq->MapUrlToPath(szParentPath, &dwPathSize))
  288. {
  289. if (dwContextId)
  290. ExceptionId(IID_IServer,
  291. dwContextId,
  292. ::GetLastError() == ERROR_INSUFFICIENT_BUFFER? IDE_SERVER_EXCEDED_MAX_PATH : IDE_SERVER_MAPPATH_FAILED);
  293. return E_FAIL;
  294. }
  295. fPathAlreadyIsMapped = TRUE;
  296. }
  297. // Resolve relative paths
  298. if (! DotPathToPath(szLogicalPath, szLogicalPath, szParentPath))
  299. {
  300. if (dwContextId)
  301. ExceptionId(IID_IServer, dwContextId, IDE_SERVER_MAPPATH_FAILED);
  302. return E_FAIL;
  303. }
  304. }
  305. // return virtual path if requested
  306. if (szVirtPath)
  307. _tcscpy(szVirtPath, szLogicalPath);
  308. // Map this to a physical file name (if required)
  309. if (!fPathAlreadyIsMapped)
  310. {
  311. DWORD dwPathSize = sizeof(szLogicalPath);
  312. if (! m_pData->m_pIReq->MapUrlToPath(szLogicalPath, &dwPathSize))
  313. {
  314. if (dwContextId)
  315. ExceptionId(IID_IServer,
  316. dwContextId,
  317. ::GetLastError() == ERROR_INSUFFICIENT_BUFFER? IDE_SERVER_EXCEDED_MAX_PATH : IDE_SERVER_MAPPATH_FAILED);
  318. return E_FAIL;
  319. }
  320. }
  321. // remove any ending delimiters (unless it's the root directory. The root always starts with drive letter)
  322. TCHAR *pchT = CharPrev(szLogicalPath, szLogicalPath + _tcslen(szLogicalPath));
  323. if ((*pchT == _T('/') || *pchT == _T('\\')) && pchT[-1] != _T(':'))
  324. {
  325. *pchT = _T('\0');
  326. }
  327. // Replace forward slash with back slash
  328. for (pchT = szLogicalPath; *pchT != _T('\0'); ++pchT)
  329. {
  330. if (*pchT == _T('/'))
  331. *pchT = _T('\\');
  332. }
  333. _tcscpy(szPhysPath, szLogicalPath);
  334. return S_OK;
  335. }
  336. /*===================================================================
  337. CServer::QueryInterface
  338. CServer::AddRef
  339. CServer::Release
  340. IUnknown members for CServer object.
  341. ===================================================================*/
  342. STDMETHODIMP CServer::QueryInterface
  343. (
  344. REFIID riid,
  345. PPVOID ppv
  346. )
  347. {
  348. *ppv = NULL;
  349. /*
  350. * The only calls for IUnknown are either in a nonaggregated
  351. * case or when created in an aggregation, so in either case
  352. * always return our IUnknown for IID_IUnknown.
  353. */
  354. // BUG FIX 683 added IID_IDenaliIntrinsic to prevent the user from
  355. // storing intrinsic objects in the application and session object
  356. if (IID_IUnknown == riid ||
  357. IID_IDispatch == riid ||
  358. IID_IServer == riid ||
  359. IID_IDenaliIntrinsic == riid)
  360. *ppv = static_cast<IServer *>(this);
  361. //Indicate that we support error information
  362. if (IID_ISupportErrorInfo == riid)
  363. {
  364. if (m_pData)
  365. *ppv = & (m_pData->m_ISupportErrImp);
  366. }
  367. if (IID_IMarshal == riid)
  368. {
  369. Assert( m_pUnkFTM != NULL );
  370. if ( m_pUnkFTM == NULL )
  371. {
  372. return E_UNEXPECTED;
  373. }
  374. return m_pUnkFTM->QueryInterface( riid, ppv );
  375. }
  376. //AddRef any interface we'll return.
  377. if (NULL != *ppv)
  378. {
  379. ((LPUNKNOWN)*ppv)->AddRef();
  380. return S_OK;
  381. }
  382. return E_NOINTERFACE;
  383. }
  384. STDMETHODIMP_(ULONG) CServer::AddRef()
  385. {
  386. if (m_fOuterUnknown)
  387. return m_punkOuter->AddRef();
  388. return InterlockedIncrement((LPLONG)&m_cRefs);
  389. }
  390. STDMETHODIMP_(ULONG) CServer::Release()
  391. {
  392. if (m_fOuterUnknown)
  393. return m_punkOuter->Release();
  394. DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs);
  395. if (cRefs)
  396. return cRefs;
  397. delete this;
  398. return 0;
  399. }
  400. /*===================================================================
  401. CServer::GetIDsOfNames
  402. Special-case implementation for CreateObject, Execute, Transfer
  403. Parameters:
  404. riid REFIID reserved. Must be IID_NULL.
  405. rgszNames OLECHAR ** pointing to the array of names to be mapped.
  406. cNames UINT number of names to be mapped.
  407. lcid LCID of the locale.
  408. rgDispID DISPID * caller allocated array containing IDs
  409. corresponging to those names in rgszNames.
  410. Return Value:
  411. HRESULT S_OK or a general error code.
  412. ===================================================================*/
  413. STDMETHODIMP CServer::GetIDsOfNames
  414. (
  415. REFIID riid,
  416. OLECHAR **rgszNames,
  417. UINT cNames,
  418. LCID lcid,
  419. DISPID *rgDispID
  420. )
  421. {
  422. const DISPID dispidCreateObject = 0x60020002;
  423. const DISPID dispidExecute = 0x60020007;
  424. const DISPID dispidTransfer = 0x60020008;
  425. if (cNames == 1)
  426. {
  427. switch (rgszNames[0][0])
  428. {
  429. case L'C':
  430. case L'c':
  431. if (wcsicmp(rgszNames[0]+1, L"reateobject") == 0)
  432. {
  433. *rgDispID = dispidCreateObject;
  434. return S_OK;
  435. }
  436. break;
  437. case L'E':
  438. case L'e':
  439. if (wcsicmp(rgszNames[0]+1, L"xecute") == 0)
  440. {
  441. *rgDispID = dispidExecute;
  442. return S_OK;
  443. }
  444. break;
  445. case L'T':
  446. case L't':
  447. if (wcsicmp(rgszNames[0]+1, L"ransfer") == 0)
  448. {
  449. *rgDispID = dispidTransfer;
  450. return S_OK;
  451. }
  452. break;
  453. }
  454. }
  455. // default to CDispatch's implementation
  456. return CDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispID);
  457. }
  458. /*===================================================================
  459. CServer::CheckForTombstone
  460. Tombstone stub for IServer methods. If the object is
  461. tombstone, does ExceptionId and fails.
  462. Parameters:
  463. Returns:
  464. HRESULT E_FAIL if Tombstone
  465. S_OK if not
  466. ===================================================================*/
  467. HRESULT CServer::CheckForTombstone()
  468. {
  469. if (m_fInited)
  470. {
  471. // inited - good object
  472. Assert(m_pData); // must be present for inited objects
  473. return S_OK;
  474. }
  475. ExceptionId
  476. (
  477. IID_IServer,
  478. IDE_SERVER,
  479. IDE_INTRINSIC_OUT_OF_SCOPE
  480. );
  481. return E_FAIL;
  482. }
  483. /*===================================================================
  484. CServer::CreateObject
  485. Parameters: BSTR containing ProgID
  486. Variant to fillin with IUknown pointer
  487. Returns: S_OK if successful E_FAIL otherwise
  488. Side effects:
  489. Creates an instance of an ole automation object
  490. ===================================================================*/
  491. STDMETHODIMP CServer::CreateObject(BSTR bstrProgID, IDispatch **ppDispObj)
  492. {
  493. if (FAILED(CheckForTombstone()))
  494. return E_FAIL;
  495. if (bstrProgID == NULL)
  496. {
  497. ExceptionId(IID_IServer, IDE_SERVER, IDE_EXPECTING_STR);
  498. return E_FAIL;
  499. }
  500. Assert(m_pData->m_pHitObj);
  501. *ppDispObj = NULL;
  502. HRESULT hr;
  503. CLSID clsid;
  504. if (Glob(fEnableTypelibCache))
  505. {
  506. // Use typelib cache to create the component
  507. hr = g_TypelibCache.CreateComponent
  508. (
  509. bstrProgID,
  510. m_pData->m_pHitObj,
  511. ppDispObj,
  512. &clsid
  513. );
  514. if (FAILED(hr) && clsid == CLSID_NULL)
  515. {
  516. // bad prog id or something
  517. ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_FAILED, hr);
  518. return hr;
  519. }
  520. }
  521. else
  522. {
  523. // Don't use typelib cache
  524. hr = CLSIDFromProgID((LPCOLESTR)bstrProgID, &clsid);
  525. if (FAILED(hr))
  526. {
  527. ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_FAILED, hr);
  528. return hr;
  529. }
  530. hr = m_pData->m_pHitObj->CreateComponent(clsid, ppDispObj);
  531. }
  532. if (SUCCEEDED(hr))
  533. return S_OK;
  534. // Check if a custom error was already posted
  535. IErrorInfo *pErrInfo = NULL;
  536. if (GetErrorInfo(0, &pErrInfo) == S_OK && pErrInfo)
  537. {
  538. SetErrorInfo(0, pErrInfo);
  539. pErrInfo->Release();
  540. }
  541. // Standard errors
  542. else if (hr == E_ACCESSDENIED)
  543. ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_DENIED);
  544. else
  545. {
  546. if (hr == REGDB_E_CLASSNOTREG)
  547. {
  548. BOOL fInProc;
  549. if (SUCCEEDED(CompModelFromCLSID(clsid, NULL, &fInProc)) && !fInProc)
  550. {
  551. ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_NOTINPROC);
  552. }
  553. }
  554. else
  555. ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_CREATEOBJ_FAILED, hr);
  556. }
  557. return hr;
  558. }
  559. /*===================================================================
  560. CServer::MapPath
  561. Return the physical path translated from a logical path
  562. Parameters:
  563. BSTR bstrLogicalPath
  564. BSTR FAR * pbstrPhysicalPath
  565. Returns:
  566. HRESULT S_OK on success
  567. ===================================================================*/
  568. STDMETHODIMP CServer::MapPath(BSTR bstrLogicalPath, BSTR FAR * pbstrPhysicalPath)
  569. {
  570. if (FAILED(CheckForTombstone()))
  571. return E_FAIL;
  572. // Bug 1361: error if no CIsapiReqInfo (presumably called during
  573. // Application_OnEnd or Session_OnEnd)
  574. if (m_pData->m_pIReq == NULL)
  575. {
  576. ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL);
  577. return E_FAIL;
  578. }
  579. AssertValid();
  580. Assert (pbstrPhysicalPath != NULL);
  581. *pbstrPhysicalPath = NULL;
  582. // use MapPathInternal() to do the mapping
  583. TCHAR szLogicalPath[MAX_PATH];
  584. HRESULT hr = MapPathInternal(IDE_SERVER_MAPPATH, bstrLogicalPath, szLogicalPath);
  585. if (FAILED(hr))
  586. return hr;
  587. #if UNICODE
  588. *pbstrPhysicalPath = SysAllocString(szLogicalPath);
  589. if (*pbstrPhysicalPath == NULL) {
  590. ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_OOM);
  591. return E_FAIL;
  592. }
  593. #else
  594. // Convert the path to wide character
  595. if (FAILED(SysAllocStringFromSz(szLogicalPath, 0, pbstrPhysicalPath, CP_ACP))) {
  596. ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_OOM);
  597. return E_FAIL;
  598. }
  599. #endif
  600. return S_OK;
  601. }
  602. /*===================================================================
  603. CServer::HTMLEncode
  604. Encodes a string to HTML standards
  605. Parameters:
  606. BSTR bstrIn value: string to be encoded
  607. BSTR FAR * pbstrEncoded value: pointer to HTML encoded version of string
  608. Returns:
  609. HRESULT S_OK on success
  610. ===================================================================*/
  611. STDMETHODIMP CServer::HTMLEncode ( BSTR bstrIn, BSTR FAR * pbstrEncoded )
  612. {
  613. if (FAILED(CheckForTombstone()))
  614. return E_FAIL;
  615. char* pszstrIn = NULL;
  616. char* pszEncodedstr = NULL;
  617. char* pszStartEncodestr = NULL;
  618. int nbstrLen = 0;
  619. int nstrLen = 0;
  620. HRESULT hr = S_OK;
  621. UINT uCodePage = m_pData->m_pHitObj->GetCodePage();
  622. CWCharToMBCS convIn;
  623. STACK_BUFFER( tempHTML, 2048 );
  624. if (bstrIn)
  625. nbstrLen = wcslen(bstrIn);
  626. else
  627. nbstrLen = 0;
  628. if (nbstrLen <= 0)
  629. return S_OK;
  630. if (FAILED(hr = convIn.Init(bstrIn, uCodePage))) {
  631. if (hr == E_OUTOFMEMORY)
  632. ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
  633. goto L_Exit;
  634. }
  635. pszstrIn = convIn.GetString();
  636. nstrLen = HTMLEncodeLen(pszstrIn, uCodePage, bstrIn);
  637. if (nstrLen > 0)
  638. {
  639. //Encode string , NOTE this function returns a pointer to the
  640. // NULL so you need to keep a pointer to the start of the string
  641. //
  642. if (!tempHTML.Resize(nstrLen + 2)) {
  643. ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
  644. hr = E_FAIL;
  645. goto L_Exit;
  646. }
  647. pszEncodedstr = (char*)tempHTML.QueryPtr();
  648. pszStartEncodestr = pszEncodedstr;
  649. pszEncodedstr = ::HTMLEncode( pszEncodedstr, pszstrIn, uCodePage, bstrIn);
  650. // convert result to bstr
  651. //
  652. if (FAILED(SysAllocStringFromSz(pszStartEncodestr, 0, pbstrEncoded, uCodePage)))
  653. {
  654. ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
  655. hr = E_FAIL;
  656. goto L_Exit;
  657. }
  658. }
  659. L_Exit:
  660. return hr;
  661. }
  662. /*===================================================================
  663. CServer::URLEncode
  664. Encodes a query string to URL standards
  665. Parameters:
  666. BSTR bstrIn value: string to be URL encoded
  667. BSTR FAR * pbstrEncoded value: pointer to URL encoded version of string
  668. Returns:
  669. HRESULT S_OK on success
  670. ===================================================================*/
  671. STDMETHODIMP CServer::URLEncode ( BSTR bstrIn, BSTR FAR * pbstrEncoded )
  672. {
  673. if (FAILED(CheckForTombstone()))
  674. return E_FAIL;
  675. char* pszstrIn = NULL;
  676. char* pszEncodedstr = NULL;
  677. char* pszStartEncodestr = NULL;
  678. int nbstrLen = 0;
  679. int nstrLen = 0;
  680. HRESULT hr = S_OK;
  681. CWCharToMBCS convIn;
  682. STACK_BUFFER( tempURL, 256 );
  683. if (bstrIn)
  684. nbstrLen = wcslen(bstrIn);
  685. else
  686. nbstrLen = 0;
  687. if (nbstrLen <= 0)
  688. return S_OK;
  689. if (FAILED(hr = convIn.Init(bstrIn, m_pData->m_pHitObj->GetCodePage()))) {
  690. if (hr == E_OUTOFMEMORY)
  691. ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
  692. goto L_Exit;
  693. }
  694. pszstrIn = convIn.GetString();
  695. nstrLen = URLEncodeLen(pszstrIn);
  696. if (nstrLen > 0)
  697. {
  698. //Encode string , NOTE this function returns a pointer to the
  699. // NULL so you need to keep a pointer to the start of the string
  700. //
  701. if (!tempURL.Resize(nstrLen + 2)) {
  702. ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
  703. hr = E_FAIL;
  704. goto L_Exit;
  705. }
  706. pszEncodedstr = (char *)tempURL.QueryPtr();
  707. pszStartEncodestr = pszEncodedstr;
  708. pszEncodedstr = ::URLEncode( pszEncodedstr, pszstrIn );
  709. // convert result to bstr
  710. //
  711. if (FAILED(SysAllocStringFromSz(pszStartEncodestr, 0, pbstrEncoded)))
  712. {
  713. ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
  714. hr = E_FAIL;
  715. goto L_Exit;
  716. }
  717. }
  718. L_Exit:
  719. return hr;
  720. }
  721. /*===================================================================
  722. CServer::URLPathEncode
  723. Encodes the path portion of a URL or a full URL. All characters
  724. up to the first '?' are encoded with the following rules:
  725. o Charcters that are needed to parse the URL are left alone
  726. o RFC 1630 safe characters are left alone
  727. o Non-foreign alphanumberic characters are left alone
  728. o Anything else is escape encoded
  729. Everything after the '?' is not encoded.
  730. Parameters:
  731. BSTR bstrIn value: string to be URL path encoded
  732. BSTR FAR * pbstrEncoded value: pointer to URL path encoded version of string
  733. Returns:
  734. HRESULT S_OK on success
  735. ===================================================================*/
  736. STDMETHODIMP CServer::URLPathEncode ( BSTR bstrIn, BSTR FAR * pbstrEncoded )
  737. {
  738. if (FAILED(CheckForTombstone()))
  739. return E_FAIL;
  740. char* pszstrIn = NULL;
  741. char* pszEncodedstr = NULL;
  742. char* pszStartEncodestr = NULL;
  743. int nbstrLen = 0;
  744. int nstrLen = 0;
  745. HRESULT hr = S_OK;
  746. CWCharToMBCS convIn;
  747. STACK_BUFFER( tempPath, 256 );
  748. if (bstrIn)
  749. nbstrLen = wcslen(bstrIn);
  750. else
  751. nbstrLen = 0;
  752. if (nbstrLen <= 0)
  753. return S_OK;
  754. if (FAILED(hr = convIn.Init(bstrIn, m_pData->m_pHitObj->GetCodePage()))) {
  755. if (hr == E_OUTOFMEMORY)
  756. ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
  757. goto L_Exit;
  758. }
  759. pszstrIn = convIn.GetString();
  760. nstrLen = URLPathEncodeLen(pszstrIn);
  761. if (nstrLen > 0)
  762. {
  763. //Encode string , NOTE this function returns a pointer to the
  764. // NULL so you need to keep a pointer to the start of the string
  765. //
  766. if (!tempPath.Resize(nstrLen+2)) {
  767. ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
  768. hr = E_FAIL;
  769. goto L_Exit;
  770. }
  771. pszEncodedstr = (char *)tempPath.QueryPtr();
  772. pszStartEncodestr = pszEncodedstr;
  773. pszEncodedstr = ::URLPathEncode( pszEncodedstr, pszstrIn );
  774. // convert result to bstr
  775. //
  776. if (FAILED(SysAllocStringFromSz(pszStartEncodestr, 0, pbstrEncoded)))
  777. {
  778. ExceptionId( IID_IServer, IDE_SERVER, IDE_OOM);
  779. hr = E_FAIL;
  780. goto L_Exit;
  781. }
  782. }
  783. L_Exit:
  784. return hr;
  785. }
  786. /*===================================================================
  787. CServer::get_ScriptTimeout
  788. Will return the script timeout interval (in seconds)
  789. Parameters:
  790. long *plTimeoutSeconds
  791. Returns:
  792. HRESULT S_OK on success
  793. ===================================================================*/
  794. STDMETHODIMP CServer::get_ScriptTimeout( long * plTimeoutSeconds )
  795. {
  796. if (FAILED(CheckForTombstone()))
  797. return E_FAIL;
  798. if (m_pData->m_pHitObj == NULL)
  799. {
  800. ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL);
  801. return(E_FAIL);
  802. }
  803. *plTimeoutSeconds = m_pData->m_pHitObj->GetScriptTimeout();
  804. return S_OK;
  805. }
  806. /*===================================================================
  807. CServer::put_ScriptTimeout
  808. Allows the user to set the timeout interval for a script (in seconds)
  809. Parameters:
  810. long lTimeoutSeconds
  811. Returns:
  812. HRESULT S_OK on success
  813. ===================================================================*/
  814. STDMETHODIMP CServer::put_ScriptTimeout( long lTimeoutSeconds )
  815. {
  816. if (FAILED(CheckForTombstone()))
  817. return E_FAIL;
  818. if ( lTimeoutSeconds < 0 )
  819. {
  820. ExceptionId( IID_IServer, IDE_SERVER, IDE_SERVER_INVALID_TIMEOUT );
  821. return E_FAIL;
  822. }
  823. else
  824. {
  825. if (m_pData->m_pHitObj == NULL)
  826. {
  827. ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL);
  828. return(E_FAIL);
  829. }
  830. m_pData->m_pHitObj->SetScriptTimeout(lTimeoutSeconds);
  831. return S_OK;
  832. }
  833. }
  834. /*===================================================================
  835. CServer::Execute
  836. Execute an ASP
  837. Parameters:
  838. bstrURL URL to execute
  839. Returns:
  840. HRESULT S_OK on success
  841. ===================================================================*/
  842. STDMETHODIMP CServer::Execute(BSTR bstrURL)
  843. {
  844. if (FAILED(CheckForTombstone()))
  845. return E_FAIL;
  846. if (m_pData->m_pIReq == NULL || m_pData->m_pHitObj == NULL)
  847. {
  848. ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_INVALID_CALL);
  849. return E_FAIL;
  850. }
  851. TCHAR szTemplate[MAX_PATH], szVirtTemp[MAX_PATH];
  852. HRESULT hr = MapPathInternal(IDE_SERVER, bstrURL, szTemplate, szVirtTemp);
  853. if (FAILED(hr))
  854. {
  855. ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_EXECUTE_INVALID_PATH);
  856. return hr;
  857. }
  858. Normalize(szTemplate);
  859. hr = m_pData->m_pHitObj->ExecuteChildRequest(FALSE, szTemplate, szVirtTemp);
  860. if (FAILED(hr))
  861. {
  862. if (m_pData->m_pHitObj->FHasASPError()) // error already reported
  863. return hr;
  864. ExceptionId(IID_IServer, IDE_SERVER, (hr == E_COULDNT_OPEN_SOURCE_FILE) ?
  865. IDE_SERVER_EXECUTE_CANTLOAD : IDE_SERVER_EXECUTE_FAILED);
  866. return E_FAIL;
  867. }
  868. return S_OK;
  869. }
  870. /*===================================================================
  871. CServer::Transfer
  872. Transfer execution an ASP
  873. Parameters:
  874. bstrURL URL to execute
  875. Returns:
  876. HRESULT S_OK on success
  877. ===================================================================*/
  878. STDMETHODIMP CServer::Transfer(BSTR bstrURL)
  879. {
  880. if (FAILED(CheckForTombstone()))
  881. return E_FAIL;
  882. if (m_pData->m_pIReq == NULL || m_pData->m_pHitObj == NULL)
  883. {
  884. ExceptionId(IID_IServer, IDE_SERVER_MAPPATH, IDE_SERVER_INVALID_CALL);
  885. return E_FAIL;
  886. }
  887. TCHAR szTemplate[MAX_PATH], szVirtTemp[MAX_PATH];
  888. HRESULT hr = MapPathInternal(IDE_SERVER, bstrURL, szTemplate, szVirtTemp);
  889. if (FAILED(hr))
  890. {
  891. ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_TRANSFER_INVALID_PATH);
  892. return hr;
  893. }
  894. Normalize(szTemplate);
  895. hr = m_pData->m_pHitObj->ExecuteChildRequest(TRUE, szTemplate, szVirtTemp);
  896. if (FAILED(hr))
  897. {
  898. if (m_pData->m_pHitObj->FHasASPError()) // error already reported
  899. return hr;
  900. ExceptionId(IID_IServer, IDE_SERVER, (hr == E_COULDNT_OPEN_SOURCE_FILE) ?
  901. IDE_SERVER_TRANSFER_CANTLOAD : IDE_SERVER_TRANSFER_FAILED);
  902. return E_FAIL;
  903. }
  904. return S_OK;
  905. }
  906. /*===================================================================
  907. CServer::GetLastError
  908. Get ASPError object for the last error
  909. Parameters:
  910. ppASPErrorObject [out] the error object
  911. Returns:
  912. HRESULT S_OK on success
  913. ===================================================================*/
  914. STDMETHODIMP CServer::GetLastError(IASPError **ppASPErrorObject)
  915. {
  916. *ppASPErrorObject = NULL;
  917. if (FAILED(CheckForTombstone()))
  918. return E_FAIL;
  919. if (m_pData->m_pIReq == NULL || m_pData->m_pHitObj == NULL)
  920. {
  921. ExceptionId(IID_IServer, IDE_SERVER, IDE_SERVER_INVALID_CALL);
  922. return E_FAIL;
  923. }
  924. HRESULT hr = m_pData->m_pHitObj->GetASPError(ppASPErrorObject);
  925. if (FAILED(hr))
  926. {
  927. ExceptionId(IID_IServer, IDE_SERVER, IDE_UNEXPECTED);
  928. return hr;
  929. }
  930. return S_OK;
  931. }
  932. #ifdef DBG
  933. /*===================================================================
  934. CServer::AssertValid
  935. Test to make sure that the CServer object is currently correctly formed
  936. and assert if it is not.
  937. Returns:
  938. Side effects:
  939. None.
  940. ===================================================================*/
  941. void CServer::AssertValid() const
  942. {
  943. Assert(m_fInited);
  944. Assert(m_pData);
  945. Assert(m_pData->m_pIReq);
  946. }
  947. #endif DBG