Source code of Windows XP (NT5)
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.

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