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.

5808 lines
161 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: request object
  6. File: request.cpp
  7. Owner: CGrant, DGottner
  8. This file contains the code for the implementation of the Request object.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "objbase.h"
  13. #include "request.h"
  14. #include "cookies.h"
  15. #include "clcert.h"
  16. #include "memchk.h"
  17. #pragma warning (disable: 4355) // ignore: "'this' used in base member init
  18. static char HexToChar(LPSTR);
  19. static char DecodeFromURL(char **pszSource, char *szStop, char *szDest, UINT uCodePage, BOOL fIgnoreCase = FALSE);
  20. #define toupper(x) BYTE(CharUpper(LPSTR(BYTE(x))))
  21. #if _IIS_6_0
  22. struct {
  23. int varLen;
  24. char *szVarName;
  25. } g_sUNICODEVars [] = {
  26. {3, "URL"},
  27. {9, "PATH_INFO"},
  28. {9, "AUTH_USER"},
  29. {10,"LOGON_USER"},
  30. {11,"REMOTE_USER"},
  31. {11,"SCRIPT_NAME"},
  32. {11,"APP_POOL_ID"},
  33. {12,"APPL_MD_PATH"},
  34. {15,"PATH_TRANSLATED"},
  35. {17,"SCRIPT_TRANSLATED"},
  36. {18,"APPL_PHYSICAL_PATH"},
  37. {20,"UNMAPPED_REMOTE_USER"},
  38. {-1,""}
  39. };
  40. #endif
  41. /*------------------------------------------------------------------
  42. * C R e q u e s t H i t
  43. */
  44. /*===================================================================
  45. CRequestHit::CRequestHit
  46. Constructor
  47. Parameters:
  48. None
  49. ===================================================================*/
  50. CRequestHit::CRequestHit()
  51. {
  52. m_fInited = FALSE;
  53. m_fDuplicate = FALSE;
  54. m_pQueryData = m_pFormData = NULL;
  55. m_pCookieData = NULL;
  56. m_pClCertData = NULL;
  57. }
  58. /*===================================================================
  59. CRequestHit::~CRequestHit
  60. Destructor
  61. ===================================================================*/
  62. CRequestHit::~CRequestHit()
  63. {
  64. if (m_pQueryData != NULL)
  65. m_pQueryData->Release();
  66. if (m_pFormData != NULL)
  67. m_pFormData->Release();
  68. if (m_pCookieData != NULL)
  69. m_pCookieData->Release();
  70. if (m_pClCertData != NULL)
  71. m_pClCertData->Release();
  72. if (m_fDuplicate)
  73. delete m_pKey;
  74. }
  75. /*===================================================================
  76. CRequestHit::Init
  77. Constructor
  78. Parameters:
  79. szName - pointer to string containing name
  80. fDuplicate - TRUE if we should dup the string
  81. Returns:
  82. E_OUTOFMEMORY, E_FAIL, or S_OK
  83. ===================================================================*/
  84. HRESULT CRequestHit::Init(char *szName, BOOL fDuplicate)
  85. {
  86. if (m_fInited)
  87. return E_FAIL;
  88. m_fDuplicate = fDuplicate;
  89. if (fDuplicate)
  90. {
  91. char *szNewKey = new char [strlen(szName) + 1];
  92. if (szNewKey == NULL)
  93. return E_OUTOFMEMORY;
  94. if (FAILED(CLinkElem::Init(strcpy(szNewKey, szName), strlen(szName))))
  95. return E_FAIL;
  96. }
  97. else
  98. if (FAILED(CLinkElem::Init(szName, strlen(szName))))
  99. return E_FAIL;
  100. m_fInited = TRUE;
  101. return S_OK;
  102. }
  103. /*===================================================================
  104. CRequestHit::AddValue
  105. Parameters:
  106. source - type of the value (QueryString or Body)
  107. szValue - the value as a null-terminated string.
  108. lCodePage - the CodePage used when retrieve the data
  109. Returns:
  110. Nothing.
  111. ===================================================================*/
  112. HRESULT CRequestHit::AddValue
  113. (
  114. CollectionType Source,
  115. char *szValue,
  116. CIsapiReqInfo *pIReq,
  117. UINT lCodePage
  118. )
  119. {
  120. HRESULT hResult;
  121. CStringList **ppValues = NULL;
  122. switch (Source)
  123. {
  124. case QUERYSTRING:
  125. ppValues = &m_pQueryData;
  126. break;
  127. case FORM:
  128. ppValues = &m_pFormData;
  129. break;
  130. case COOKIE:
  131. if (m_pCookieData == NULL)
  132. {
  133. m_pCookieData = new CCookie(pIReq, lCodePage);
  134. if (m_pCookieData == NULL)
  135. return E_OUTOFMEMORY;
  136. if (FAILED(hResult = m_pCookieData->Init()))
  137. return hResult;
  138. }
  139. return m_pCookieData->AddValue(szValue);
  140. case CLCERT:
  141. if (m_pClCertData == NULL)
  142. {
  143. m_pClCertData = new CClCert;
  144. if (m_pClCertData == NULL)
  145. return E_OUTOFMEMORY;
  146. if (FAILED(hResult = m_pClCertData->Init()))
  147. return hResult;
  148. }
  149. return m_pClCertData->AddValue(szValue);
  150. default:
  151. return E_FAIL;
  152. }
  153. if (*ppValues == NULL)
  154. {
  155. *ppValues = new CStringList;
  156. if (*ppValues == NULL)
  157. return E_OUTOFMEMORY;
  158. }
  159. if (FAILED(hResult = (*ppValues)->AddValue(szValue, FALSE, lCodePage)))
  160. return hResult;
  161. return S_OK;
  162. }
  163. HRESULT CRequestHit::AddCertValue(VARENUM ve, LPBYTE pValue, UINT cLen )
  164. {
  165. HRESULT hResult;
  166. if (m_pClCertData == NULL)
  167. {
  168. m_pClCertData = new CClCert;
  169. if (m_pClCertData == NULL)
  170. return E_OUTOFMEMORY;
  171. if (FAILED(hResult = m_pClCertData->Init()))
  172. return hResult;
  173. }
  174. return m_pClCertData->AddValue( (LPSTR)pValue, ve, cLen );
  175. }
  176. /*===================================================================
  177. CRequestHit::AddKeyAndValue
  178. Add a value based on keys for collections that support them. Currently,
  179. only cookies support them.
  180. Parameters:
  181. source - type of the value (must be Cookie)
  182. szKey - the key
  183. szValue - the value as a null-terminated string.
  184. Returns:
  185. Returns E_OUTOFMEMORY if memory cannot be allocated,
  186. E_FAIL if source collection does not support keys,
  187. ===================================================================*/
  188. HRESULT CRequestHit::AddKeyAndValue
  189. (
  190. CollectionType Source,
  191. char *szKey,
  192. char *szValue,
  193. CIsapiReqInfo *pIReq,
  194. UINT lCodePage
  195. )
  196. {
  197. HRESULT hResult;
  198. switch ( Source )
  199. {
  200. case COOKIE:
  201. if (m_pCookieData == NULL)
  202. {
  203. m_pCookieData = new CCookie( pIReq , lCodePage);
  204. if (m_pCookieData == NULL)
  205. return E_OUTOFMEMORY;
  206. if (FAILED(hResult = m_pCookieData->Init()))
  207. return hResult;
  208. }
  209. return m_pCookieData->AddKeyAndValue(szKey, szValue);
  210. default:
  211. return E_FAIL;
  212. }
  213. }
  214. /*------------------------------------------------------------------
  215. * C R e q u e s t H i t s A r r a y
  216. */
  217. /*===================================================================
  218. CRequestHitsArray::CRequestHitsArray
  219. Constructor
  220. Parameters:
  221. Returns:
  222. ===================================================================*/
  223. CRequestHitsArray::CRequestHitsArray()
  224. : m_dwCount(0), m_dwHitMax(0), m_rgRequestHit(NULL)
  225. {
  226. }
  227. /*===================================================================
  228. CRequestHitsArray::~CRequestHitsArray
  229. Destructor
  230. Parameters:
  231. Returns:
  232. ===================================================================*/
  233. CRequestHitsArray::~CRequestHitsArray()
  234. {
  235. if (m_rgRequestHit)
  236. delete [] m_rgRequestHit;
  237. }
  238. /*===================================================================
  239. CRequestHitsArray::AddRequestHit
  240. Add an element to the array
  241. Parameters:
  242. pHit element to add
  243. Returns:
  244. ===================================================================*/
  245. BOOL CRequestHitsArray::AddRequestHit
  246. (
  247. CRequestHit *pHit
  248. )
  249. {
  250. Assert(pHit);
  251. if (m_dwCount == m_dwHitMax)
  252. {
  253. DWORD dwNewSize = m_dwHitMax + NUM_REQUEST_HITS;
  254. CRequestHit **ppNewArray = new CRequestHit *[dwNewSize];
  255. if (ppNewArray == NULL)
  256. return FALSE;
  257. if (m_dwCount)
  258. {
  259. Assert(m_rgRequestHit);
  260. // Copy pointers from old array
  261. memcpy
  262. (
  263. ppNewArray,
  264. m_rgRequestHit,
  265. m_dwCount * sizeof(CRequestHit *)
  266. );
  267. // free old array
  268. delete [] m_rgRequestHit;
  269. }
  270. else
  271. {
  272. Assert(m_rgRequestHit == NULL);
  273. }
  274. m_rgRequestHit = ppNewArray;
  275. m_dwHitMax = dwNewSize;
  276. }
  277. m_rgRequestHit[m_dwCount++] = pHit;
  278. return TRUE;
  279. }
  280. /*------------------------------------------------------------------
  281. * C Q u e r y S t r i n g
  282. */
  283. /*===================================================================
  284. CQueryString::CQueryString
  285. Constructor
  286. Parameters:
  287. pRequest Pointer to main Request object
  288. pUnkOuter LPUNKNOWN of a controlling unknown.
  289. Returns:
  290. Nothing.
  291. Note:
  292. This object is NOT ref counted since it is created & destroyed
  293. automatically by C++.
  294. ===================================================================*/
  295. CQueryString::CQueryString(CRequest *pRequest, IUnknown *pUnkOuter)
  296. : m_ISupportErrImp(this, pUnkOuter, IID_IRequestDictionary)
  297. {
  298. m_punkOuter = pUnkOuter;
  299. if (pRequest)
  300. pRequest->AddRef();
  301. m_pRequest = pRequest;
  302. CDispatch::Init(IID_IRequestDictionary);
  303. }
  304. /*===================================================================
  305. CQueryString::~CQueryString
  306. Destructor
  307. Parameters:
  308. None
  309. Returns:
  310. Nothing.
  311. ===================================================================*/
  312. CQueryString::~CQueryString()
  313. {
  314. if (m_pRequest)
  315. m_pRequest->Release();
  316. }
  317. /*===================================================================
  318. HRESULT CQueryString::Init
  319. Parameters:
  320. None
  321. Returns:
  322. E_OUTOFMEMORY if allocation fails.
  323. ===================================================================*/
  324. HRESULT CQueryString::Init()
  325. {
  326. return CRequestHitsArray::Init();
  327. }
  328. /*===================================================================
  329. HRESULT CQueryString::ReInit
  330. Parameters:
  331. None
  332. Returns:
  333. S_OK
  334. ===================================================================*/
  335. HRESULT CQueryString::ReInit()
  336. {
  337. return CRequestHitsArray::ReInit();
  338. }
  339. /*===================================================================
  340. CQueryString::QueryInterface
  341. CQueryString::AddRef
  342. CQueryString::Release
  343. IUnknown members for CQueryString object.
  344. ===================================================================*/
  345. STDMETHODIMP CQueryString::QueryInterface(REFIID iid, void **ppvObj)
  346. {
  347. *ppvObj = NULL;
  348. if (iid == IID_IUnknown || iid == IID_IRequestDictionary || iid == IID_IDispatch)
  349. *ppvObj = this;
  350. else if (iid == IID_ISupportErrorInfo)
  351. *ppvObj = &m_ISupportErrImp;
  352. if (*ppvObj != NULL)
  353. {
  354. static_cast<IUnknown *>(*ppvObj)->AddRef();
  355. return S_OK;
  356. }
  357. return ResultFromScode(E_NOINTERFACE);
  358. }
  359. STDMETHODIMP_(ULONG) CQueryString::AddRef(void)
  360. {
  361. return m_punkOuter->AddRef();
  362. }
  363. STDMETHODIMP_(ULONG) CQueryString::Release(void)
  364. {
  365. return m_punkOuter->Release();
  366. }
  367. /*===================================================================
  368. CQueryString::get_Item
  369. Function called from DispInvoke to get values from the QueryString collection.
  370. Parameters:
  371. vKey VARIANT [in], which parameter to get the value of - Empty means whole collection
  372. pvarReturn VARIANT *, [out] value of the requested parameter
  373. Returns:
  374. S_OK on success, E_FAIL on failure.
  375. ===================================================================*/
  376. HRESULT CQueryString::get_Item(VARIANT varKey, VARIANT *pvarReturn)
  377. {
  378. if (FAILED(m_pRequest->CheckForTombstone()))
  379. return E_FAIL;
  380. char *szKey;
  381. CWCharToMBCS convKey;
  382. CRequestHit *pRequestHit; // pointer to request bucket
  383. IDispatch *pSListReturn; // value of the key
  384. // Initialize things
  385. //
  386. VariantInit(pvarReturn);
  387. VARIANT *pvarKey = &varKey;
  388. HRESULT hrReturn = S_OK;
  389. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
  390. // produced by IEnumVariant
  391. //
  392. // Use VariantResolveDispatch which will:
  393. //
  394. // * Copy BYREF variants for us using VariantCopyInd
  395. // * handle E_OUTOFMEMORY for us
  396. // * get the default value from an IDispatch, which seems
  397. // like an appropriate conversion.
  398. //
  399. VARIANT varKeyCopy;
  400. VariantInit(&varKeyCopy);
  401. DWORD vt = V_VT(pvarKey);
  402. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  403. {
  404. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  405. goto LExit;
  406. pvarKey = &varKeyCopy;
  407. }
  408. vt = V_VT(pvarKey);
  409. switch (vt)
  410. {
  411. // Bug 95201 support all numberic sub-types
  412. case VT_I1: case VT_I2: case VT_I8:
  413. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  414. case VT_R4: case VT_R8:
  415. // Coerce all integral types to VT_I4
  416. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  417. goto LExit;
  418. // fallthru to VT_I4
  419. case VT_I4:
  420. case VT_BSTR:
  421. break;
  422. case VT_ERROR:
  423. if (V_ERROR(pvarKey) == DISP_E_PARAMNOTFOUND)
  424. {
  425. // Look up QueryString using the "ServerVariables" collection -
  426. // The LoadVariables() function trashes QueryPszQueryString() in the CIsapiReqInfo
  427. //
  428. DWORD dwQStrSize;
  429. STACK_BUFFER( queryStrBuff, 256 );
  430. if (!SERVER_GET(m_pRequest->GetIReq(), "QUERY_STRING", &queryStrBuff, &dwQStrSize)) {
  431. if (GetLastError() == E_OUTOFMEMORY) {
  432. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  433. hrReturn = E_OUTOFMEMORY;
  434. }
  435. else {
  436. hrReturn = E_FAIL;
  437. }
  438. goto LExit;
  439. }
  440. char *szQueryString = (char *)queryStrBuff.QueryPtr();
  441. BSTR bstrT;
  442. if (FAILED(SysAllocStringFromSz(szQueryString, 0, &bstrT,m_pRequest->GetCodePage())))
  443. {
  444. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  445. hrReturn = E_OUTOFMEMORY;
  446. goto LExit;
  447. }
  448. V_VT(pvarReturn) = VT_BSTR;
  449. V_BSTR(pvarReturn) = bstrT;
  450. goto LExit;
  451. }
  452. // Other error, FALL THROUGH to wrong type case
  453. default:
  454. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  455. hrReturn = E_FAIL;
  456. goto LExit;
  457. }
  458. if (m_pRequest->m_pData->m_fLoadQuery)
  459. {
  460. if (FAILED(m_pRequest->LoadVariables(QUERYSTRING, m_pRequest->GetIReq()->QueryPszQueryString(), m_pRequest->GetCodePage())))
  461. {
  462. hrReturn = E_FAIL;
  463. goto LExit;
  464. }
  465. m_pRequest->m_pData->m_fLoadQuery = FALSE;
  466. }
  467. if (vt == VT_BSTR)
  468. {
  469. // convert BSTR version to ANSI version of the key using current Session.CodePage
  470. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey), m_pRequest->GetCodePage()))) {
  471. if (hrReturn == E_OUTOFMEMORY) {
  472. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  473. goto LExit;
  474. }
  475. hrReturn = NO_ERROR;
  476. szKey = "";
  477. }
  478. else {
  479. szKey = convKey.GetString();
  480. }
  481. pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->FindElem(szKey, strlen(szKey)));
  482. }
  483. else
  484. {
  485. // Look up item by index
  486. int iCount;
  487. iCount = V_I4(pvarKey);
  488. // BUG 86117 test passes when m_dwCount == 0
  489. if ( ((iCount < 1) || (iCount > (int) m_dwCount)) || ((iCount > 0) && (int) m_dwCount == 0))
  490. {
  491. hrReturn = E_FAIL;
  492. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  493. goto LExit;
  494. }
  495. pRequestHit = m_rgRequestHit[iCount - 1];
  496. }
  497. if (pRequestHit)
  498. {
  499. CStringList *pValues = pRequestHit->m_pQueryData;
  500. if (pValues == NULL)
  501. goto LNotFound;
  502. if (FAILED(pValues->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&pSListReturn))))
  503. Assert (FALSE);
  504. V_VT(pvarReturn) = VT_DISPATCH;
  505. V_DISPATCH(pvarReturn) = pSListReturn;
  506. goto LExit;
  507. }
  508. LNotFound: // Return "Empty"
  509. if (FAILED(m_pRequest->m_pData->GetEmptyStringList(&pSListReturn)))
  510. hrReturn = E_FAIL;
  511. V_VT(pvarReturn) = VT_DISPATCH;
  512. V_DISPATCH(pvarReturn) = pSListReturn;
  513. LExit:
  514. VariantClear(&varKeyCopy);
  515. return hrReturn;
  516. }
  517. /*===================================================================
  518. CQueryString::get_Key
  519. Function called from DispInvoke to get keys from the QueryString collection.
  520. Parameters:
  521. vKey VARIANT [in], which parameter to get the key of
  522. pvarReturn VARIANT *, [out] value of the requested parameter
  523. Returns:
  524. S_OK on success, E_FAIL on failure.
  525. ===================================================================*/
  526. HRESULT CQueryString::get_Key(VARIANT varKey, VARIANT *pVar)
  527. {
  528. if (FAILED(m_pRequest->CheckForTombstone()))
  529. return E_FAIL;
  530. char *szKey; // ascii version of the key
  531. CWCharToMBCS convKey;
  532. CRequestHit *pRequestHit; // pointer to request bucket
  533. IDispatch *pSListReturn; // value of the key
  534. // Initialize things
  535. //
  536. VariantInit(pVar);
  537. VARIANT *pvarKey = &varKey;
  538. V_VT(pVar) = VT_BSTR;
  539. V_BSTR(pVar) = NULL;
  540. HRESULT hrReturn = S_OK;
  541. // Use VariantResolveDispatch which will:
  542. //
  543. // * Copy BYREF variants for us using VariantCopyInd
  544. // * handle E_OUTOFMEMORY for us
  545. // * get the default value from an IDispatch, which seems
  546. // like an appropriate conversion.
  547. //
  548. VARIANT varKeyCopy;
  549. VariantInit(&varKeyCopy);
  550. DWORD vt = V_VT(pvarKey);
  551. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  552. {
  553. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  554. goto LExit;
  555. pvarKey = &varKeyCopy;
  556. }
  557. vt = V_VT(pvarKey);
  558. switch (vt)
  559. {
  560. // Bug 95201 support all numberic sub-types
  561. case VT_I1: case VT_I2: case VT_I8:
  562. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  563. case VT_R4: case VT_R8:
  564. // Coerce all integral types to VT_I4
  565. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  566. goto LExit;
  567. // fallthru to VT_I4
  568. case VT_I4:
  569. case VT_BSTR:
  570. break;
  571. default:
  572. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  573. hrReturn = E_FAIL;
  574. goto LExit;
  575. }
  576. if (m_pRequest->m_pData->m_fLoadQuery)
  577. {
  578. if (FAILED(m_pRequest->LoadVariables(QUERYSTRING, m_pRequest->GetIReq()->QueryPszQueryString(), m_pRequest->GetCodePage())))
  579. {
  580. hrReturn = E_FAIL;
  581. goto LExit;
  582. }
  583. m_pRequest->m_pData->m_fLoadQuery = FALSE;
  584. }
  585. if (vt == VT_BSTR)
  586. {
  587. // convert BSTR version to ANSI version of the key using current Session.CodePage
  588. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey),m_pRequest->GetCodePage()))) {
  589. if (hrReturn == E_OUTOFMEMORY) {
  590. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  591. goto LExit;
  592. }
  593. hrReturn = NO_ERROR;
  594. szKey = "";
  595. }
  596. else {
  597. szKey = convKey.GetString();
  598. }
  599. pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->FindElem(szKey, strlen(szKey)));
  600. }
  601. else
  602. {
  603. int iCount;
  604. iCount = V_I4(pvarKey);
  605. // BUG 86117 test passes when m_dwCount == 0
  606. if ( ((iCount < 1) || (iCount > (int) m_dwCount)) || ((iCount > 0) && ((int) m_dwCount == 0)))
  607. {
  608. hrReturn = E_FAIL;
  609. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  610. goto LExit;
  611. }
  612. pRequestHit = m_rgRequestHit[iCount - 1];
  613. }
  614. if (pRequestHit)
  615. {
  616. // Create a BSTR containing the key for this variant
  617. BSTR bstrT = NULL;
  618. SysAllocStringFromSz((char *)pRequestHit->m_pKey,0,&bstrT,m_pRequest->GetCodePage());
  619. if (!bstrT)
  620. return E_OUTOFMEMORY;
  621. V_BSTR(pVar) = bstrT;
  622. }
  623. LExit:
  624. VariantClear(&varKeyCopy);
  625. return hrReturn;
  626. }
  627. /*===================================================================
  628. CQueryString::get_Count
  629. Parameters:
  630. pcValues - count is stored in *pcValues
  631. ===================================================================*/
  632. STDMETHODIMP CQueryString::get_Count(int *pcValues)
  633. {
  634. HRESULT hrReturn = S_OK;
  635. if (m_pRequest->m_pData->m_fLoadQuery)
  636. {
  637. if (FAILED(hrReturn = m_pRequest->LoadVariables(QUERYSTRING, m_pRequest->GetIReq()->QueryPszQueryString(), m_pRequest->GetCodePage())))
  638. {
  639. goto LExit;
  640. }
  641. m_pRequest->m_pData->m_fLoadQuery = FALSE;
  642. }
  643. *pcValues = m_dwCount;
  644. LExit:
  645. return hrReturn;
  646. }
  647. /*===================================================================
  648. CQueryString::get__NewEnum
  649. Return a new enumerator
  650. ===================================================================*/
  651. HRESULT CQueryString::get__NewEnum(IUnknown **ppEnumReturn)
  652. {
  653. if (FAILED(m_pRequest->CheckForTombstone()))
  654. return E_FAIL;
  655. return m_pRequest->GetRequestEnumerator(QUERYSTRING, ppEnumReturn);
  656. }
  657. /*------------------------------------------------------------------
  658. * C F o r m I n p u t s
  659. */
  660. /*===================================================================
  661. CFormInputs::CFormInputs
  662. Constructor
  663. Parameters:
  664. pRequest Pointer to main Request object
  665. pUnkOuter LPUNKNOWN of a controlling unknown.
  666. Returns:
  667. Nothing.
  668. Note:
  669. This object is NOT ref counted since it is created & destroyed
  670. automatically by C++.
  671. ===================================================================*/
  672. CFormInputs::CFormInputs(CRequest *pRequest, IUnknown *pUnkOuter)
  673. : m_ISupportErrImp(this, pUnkOuter, IID_IRequestDictionary)
  674. {
  675. m_punkOuter = pUnkOuter;
  676. if (pRequest)
  677. pRequest->AddRef();
  678. m_pRequest = pRequest;
  679. CDispatch::Init(IID_IRequestDictionary);
  680. }
  681. /*===================================================================
  682. CFormInputs::CFormInputs
  683. Destructor
  684. Parameters:
  685. None
  686. Returns:
  687. Nothing.
  688. ===================================================================*/
  689. CFormInputs::~CFormInputs()
  690. {
  691. if (m_pRequest)
  692. m_pRequest->Release();
  693. }
  694. /*===================================================================
  695. HRESULT CFormInputs::Init
  696. Parameters:
  697. None
  698. Returns:
  699. E_OUTOFMEMORY if allocation fails.
  700. ===================================================================*/
  701. HRESULT CFormInputs::Init()
  702. {
  703. return CRequestHitsArray::Init();
  704. }
  705. /*===================================================================
  706. HRESULT CFormInputs::ReInit
  707. Parameters:
  708. None
  709. Returns:
  710. S_OK
  711. ===================================================================*/
  712. HRESULT CFormInputs::ReInit()
  713. {
  714. return CRequestHitsArray::ReInit();
  715. }
  716. /*===================================================================
  717. CFormInputs::QueryInterface
  718. CFormInputs::AddRef
  719. CFormInputs::Release
  720. IUnknown members for CFormInputs object.
  721. ===================================================================*/
  722. STDMETHODIMP CFormInputs::QueryInterface(REFIID iid, void **ppvObj)
  723. {
  724. *ppvObj = NULL;
  725. if (iid == IID_IUnknown || iid == IID_IRequestDictionary || iid == IID_IDispatch)
  726. *ppvObj = this;
  727. else if (iid == IID_ISupportErrorInfo)
  728. *ppvObj = &m_ISupportErrImp;
  729. if (*ppvObj != NULL)
  730. {
  731. static_cast<IUnknown *>(*ppvObj)->AddRef();
  732. return S_OK;
  733. }
  734. return E_NOINTERFACE;
  735. }
  736. STDMETHODIMP_(ULONG) CFormInputs::AddRef(void)
  737. {
  738. return m_punkOuter->AddRef();
  739. }
  740. STDMETHODIMP_(ULONG) CFormInputs::Release(void)
  741. {
  742. return m_punkOuter->Release();
  743. }
  744. /*===================================================================
  745. CFormInputs::get_Item
  746. Function called from DispInvoke to get values from the QueryString collection.
  747. Parameters:
  748. vKey VARIANT [in], which parameter to get the value of - Empty means whole collection
  749. pvarReturn VARIANT *, [out] value of the requested parameter
  750. Returns:
  751. S_OK on success, S_OK if key not found, E_FAIL on failure.
  752. ===================================================================*/
  753. HRESULT CFormInputs::get_Item(VARIANT varKey, VARIANT *pvarReturn)
  754. {
  755. if (FAILED(m_pRequest->CheckForTombstone()))
  756. return E_FAIL;
  757. char *szKey; // ascii version of the key
  758. CWCharToMBCS convKey;
  759. IDispatch *pSListReturn; // value of the key
  760. CRequestHit *pRequestHit; // pointer to request bucket
  761. BOOL fDataAvail = FALSE; // true if data seen from client
  762. // Initialize things
  763. //
  764. VariantInit(pvarReturn);
  765. VARIANT *pvarKey = &varKey;
  766. HRESULT hrReturn = S_OK;
  767. // If BinaryRead has been called, the Form collection is no longer available
  768. if (m_pRequest->m_pData->m_FormDataStatus != AVAILABLE &&
  769. m_pRequest->m_pData->m_FormDataStatus != FORMCOLLECTIONONLY)
  770. {
  771. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_REQUEST_FORMCOLLECTION_NA);
  772. hrReturn = E_FAIL;
  773. }
  774. if (m_pRequest->m_pData->m_FormDataStatus == AVAILABLE)
  775. m_pRequest->m_pData->m_FormDataStatus = FORMCOLLECTIONONLY;
  776. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
  777. // produced by IEnumVariant
  778. //
  779. // Use VariantResolveDispatch which will:
  780. //
  781. // * Copy BYREF variants for us using VariantCopyInd
  782. // * handle E_OUTOFMEMORY for us
  783. // * get the default value from an IDispatch, which seems
  784. // like an appropriate conversion.
  785. //
  786. VARIANT varKeyCopy;
  787. VariantInit(&varKeyCopy);
  788. DWORD vt = V_VT(pvarKey);
  789. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  790. {
  791. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  792. goto LExit;
  793. pvarKey = &varKeyCopy;
  794. }
  795. vt = V_VT(pvarKey);
  796. if (m_pRequest->m_pData->m_fLoadForm)
  797. {
  798. if (FAILED(hrReturn = m_pRequest->CopyClientData()))
  799. goto LExit;
  800. if (FAILED(hrReturn = m_pRequest->LoadVariables(FORM, m_pRequest->m_pData->m_szFormData, m_pRequest->GetCodePage())))
  801. goto LExit;
  802. // BUG:895 (JHITTLE) added to check for null result set
  803. // this fixes the out of memory error when the form
  804. // data is NULL
  805. //
  806. fDataAvail = (m_pRequest->m_pData->m_szFormData != NULL);
  807. m_pRequest->m_pData->m_fLoadForm = FALSE;
  808. }
  809. else
  810. fDataAvail = (m_pRequest->m_pData->m_szFormData != NULL);
  811. switch (vt)
  812. {
  813. // Bug 95201 support all numberic sub-types
  814. case VT_I1: case VT_I2: case VT_I8:
  815. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  816. case VT_R4: case VT_R8:
  817. // Coerce all integral types to VT_I4
  818. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  819. goto LExit;
  820. // fallthru to VT_I4
  821. case VT_I4:
  822. case VT_BSTR:
  823. break;
  824. case VT_ERROR:
  825. if (V_ERROR(pvarKey) == DISP_E_PARAMNOTFOUND)
  826. {
  827. if (fDataAvail)
  828. {
  829. BSTR bstrT;
  830. if (FAILED(SysAllocStringFromSz(m_pRequest->m_pData->m_szFormClone, 0, &bstrT,m_pRequest->GetCodePage())))
  831. {
  832. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  833. hrReturn = E_OUTOFMEMORY;
  834. }
  835. V_VT(pvarReturn) = VT_BSTR;
  836. V_BSTR(pvarReturn) = bstrT;
  837. }
  838. // If there was no data available, status & return value are already set
  839. goto LExit;
  840. }
  841. // Other error, FALL THROUGH to wrong type case
  842. default:
  843. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  844. hrReturn = E_FAIL;
  845. goto LExit;
  846. }
  847. pRequestHit = NULL;
  848. if (! fDataAvail) // Quick check before we do an expensive lookup
  849. goto LNotFound;
  850. if (vt == VT_BSTR)
  851. {
  852. // convert BSTR version to ANSI version of the key using current Session.CodePage
  853. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey), m_pRequest->GetCodePage()))) {
  854. if (hrReturn == E_OUTOFMEMORY) {
  855. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  856. goto LExit;
  857. }
  858. hrReturn = NO_ERROR;
  859. szKey = "";
  860. }
  861. else {
  862. szKey = convKey.GetString();
  863. }
  864. pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->FindElem(szKey, strlen(szKey)));
  865. }
  866. else
  867. {
  868. // Look up item by index
  869. int iCount;
  870. iCount = V_I4(pvarKey);
  871. // BUG 86117 test passes when m_dwCount == 0
  872. if ( ((iCount < 1) || (iCount > (int) m_dwCount)) || ((iCount > 0) && ((int) m_dwCount == 0)))
  873. {
  874. hrReturn = E_FAIL;
  875. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  876. goto LExit;
  877. }
  878. pRequestHit = m_rgRequestHit[iCount - 1];
  879. }
  880. if (pRequestHit)
  881. {
  882. CStringList *pValues = pRequestHit->m_pFormData;
  883. if (pValues == NULL)
  884. goto LNotFound;
  885. if (FAILED(pValues->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&pSListReturn))))
  886. Assert (FALSE);
  887. V_VT(pvarReturn) = VT_DISPATCH;
  888. V_DISPATCH(pvarReturn) = pSListReturn;
  889. goto LExit;
  890. }
  891. LNotFound: // Return "Empty"
  892. if(vt != VT_BSTR)
  893. {
  894. hrReturn = E_FAIL;
  895. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  896. goto LExit;
  897. }
  898. if (FAILED(m_pRequest->m_pData->GetEmptyStringList(&pSListReturn)))
  899. hrReturn = E_FAIL;
  900. V_VT(pvarReturn) = VT_DISPATCH;
  901. V_DISPATCH(pvarReturn) = pSListReturn;
  902. LExit:
  903. VariantClear(&varKeyCopy);
  904. return hrReturn;
  905. }
  906. /*===================================================================
  907. CFormInputs::get_Count
  908. Parameters:
  909. pcValues - count is stored in *pcValues
  910. ===================================================================*/
  911. STDMETHODIMP CFormInputs::get_Count(int *pcValues)
  912. {
  913. if (FAILED(m_pRequest->CheckForTombstone()))
  914. return E_FAIL;
  915. HRESULT hrReturn = S_OK;
  916. // If BinaryRead has been called, the Form collection is no longer available
  917. if (m_pRequest->m_pData->m_FormDataStatus != AVAILABLE &&
  918. m_pRequest->m_pData->m_FormDataStatus != FORMCOLLECTIONONLY)
  919. {
  920. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_REQUEST_FORMCOLLECTION_NA);
  921. hrReturn = E_FAIL;
  922. }
  923. if (m_pRequest->m_pData->m_FormDataStatus == AVAILABLE)
  924. m_pRequest->m_pData->m_FormDataStatus = FORMCOLLECTIONONLY;
  925. if (m_pRequest->m_pData->m_fLoadForm)
  926. {
  927. if (FAILED(hrReturn = m_pRequest->CopyClientData()))
  928. goto LExit;
  929. if (FAILED(hrReturn = m_pRequest->LoadVariables(FORM, m_pRequest->m_pData->m_szFormData, m_pRequest->GetCodePage())))
  930. goto LExit;
  931. m_pRequest->m_pData->m_fLoadForm = FALSE;
  932. }
  933. *pcValues = m_dwCount;
  934. LExit:
  935. return hrReturn;
  936. }
  937. /*===================================================================
  938. CFormInputs::get_Key
  939. Function called from DispInvoke to get keys from the form inputs collection.
  940. Parameters:
  941. vKey VARIANT [in], which parameter to get the key of
  942. pvarReturn VARIANT *, [out] value of the requested parameter
  943. Returns:
  944. S_OK on success, E_FAIL on failure.
  945. ===================================================================*/
  946. HRESULT CFormInputs::get_Key(VARIANT varKey, VARIANT *pVar)
  947. {
  948. if (FAILED(m_pRequest->CheckForTombstone()))
  949. return E_FAIL;
  950. char *szKey; // ascii version of the key
  951. CWCharToMBCS convKey;
  952. CRequestHit *pRequestHit; // pointer to request bucket
  953. IDispatch *pSListReturn; // value of the key
  954. // Initialize things
  955. //
  956. VariantInit(pVar);
  957. VARIANT *pvarKey = &varKey;
  958. V_VT(pVar) = VT_BSTR;
  959. V_BSTR(pVar) = NULL;
  960. HRESULT hrReturn = S_OK;
  961. // Use VariantResolveDispatch which will:
  962. //
  963. // * Copy BYREF variants for us using VariantCopyInd
  964. // * handle E_OUTOFMEMORY for us
  965. // * get the default value from an IDispatch, which seems
  966. // like an appropriate conversion.
  967. //
  968. VARIANT varKeyCopy;
  969. VariantInit(&varKeyCopy);
  970. DWORD vt = V_VT(pvarKey);
  971. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  972. {
  973. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  974. goto LExit;
  975. pvarKey = &varKeyCopy;
  976. }
  977. vt = V_VT(pvarKey);
  978. switch (vt)
  979. {
  980. // Bug 95201 support all numberic sub-types
  981. case VT_I1: case VT_I2: case VT_I8:
  982. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  983. case VT_R4: case VT_R8:
  984. // Coerce all integral types to VT_I4
  985. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  986. goto LExit;
  987. // fallthru to VT_I4
  988. case VT_I4:
  989. case VT_BSTR:
  990. break;
  991. default:
  992. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  993. hrReturn = E_FAIL;
  994. goto LExit;
  995. }
  996. if (m_pRequest->m_pData->m_fLoadForm)
  997. {
  998. if (FAILED(hrReturn = m_pRequest->CopyClientData()))
  999. goto LExit;
  1000. if (FAILED(hrReturn = m_pRequest->LoadVariables(FORM, m_pRequest->m_pData->m_szFormData, m_pRequest->GetCodePage())))
  1001. {
  1002. goto LExit;
  1003. }
  1004. m_pRequest->m_pData->m_fLoadForm = FALSE;
  1005. }
  1006. if (vt == VT_BSTR)
  1007. {
  1008. // convert BSTR version to ANSI version of the key using current Session.CodePage
  1009. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey), m_pRequest->GetCodePage()))) {
  1010. if (hrReturn == E_OUTOFMEMORY) {
  1011. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  1012. goto LExit;
  1013. }
  1014. hrReturn = NO_ERROR;
  1015. szKey = "";
  1016. }
  1017. else {
  1018. szKey = convKey.GetString();
  1019. }
  1020. pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->FindElem(szKey, strlen(szKey)));
  1021. }
  1022. else
  1023. {
  1024. int iCount;
  1025. iCount = V_I4(pvarKey);
  1026. // BUG 86117 test passes when m_dwCount == 0
  1027. if ( ((iCount < 1) || (iCount > (int) m_dwCount)) || ((iCount > 0) && ((int) m_dwCount == 0)))
  1028. {
  1029. hrReturn = E_FAIL;
  1030. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  1031. goto LExit;
  1032. }
  1033. pRequestHit = m_rgRequestHit[iCount - 1];
  1034. }
  1035. if (pRequestHit)
  1036. {
  1037. // Create a BSTR containing the key for this variant
  1038. BSTR bstrT = NULL;
  1039. SysAllocStringFromSz((char *)pRequestHit->m_pKey,0,&bstrT,m_pRequest->GetCodePage());
  1040. if (!bstrT)
  1041. return E_OUTOFMEMORY;
  1042. V_BSTR(pVar) = bstrT;
  1043. }
  1044. LExit:
  1045. VariantClear(&varKeyCopy);
  1046. return hrReturn;
  1047. }
  1048. /*===================================================================
  1049. CFormInputs::get__NewEnum
  1050. Return a new enumerator
  1051. ===================================================================*/
  1052. HRESULT CFormInputs::get__NewEnum(IUnknown **ppEnumReturn)
  1053. {
  1054. if (FAILED(m_pRequest->CheckForTombstone()))
  1055. return E_FAIL;
  1056. return m_pRequest->GetRequestEnumerator(FORM, ppEnumReturn);
  1057. }
  1058. /*------------------------------------------------------------------
  1059. * C C o o k i e s
  1060. */
  1061. /*===================================================================
  1062. CCookies::CCookies
  1063. Constructor
  1064. Parameters:
  1065. pRequest Pointer to main Request object
  1066. pUnkOuter LPUNKNOWN of a controlling unknown.
  1067. Returns:
  1068. Nothing.
  1069. Note:
  1070. This object is NOT ref counted since it is created & destroyed
  1071. automatically by C++.
  1072. ===================================================================*/
  1073. CCookies::CCookies(CRequest *pRequest, IUnknown *pUnkOuter)
  1074. : m_ISupportErrImp(this, pUnkOuter, IID_IRequestDictionary)
  1075. {
  1076. m_punkOuter = pUnkOuter;
  1077. if (pRequest)
  1078. pRequest->AddRef();
  1079. m_pRequest = pRequest;
  1080. m_pEmptyCookie = NULL;
  1081. CDispatch::Init(IID_IRequestDictionary);
  1082. }
  1083. /*===================================================================
  1084. CCookies::CCookies
  1085. Destructor
  1086. Note:
  1087. This object is NOT ref counted since it is created & destroyed
  1088. automatically by C++.
  1089. ===================================================================*/
  1090. CCookies::~CCookies()
  1091. {
  1092. if (m_pRequest)
  1093. m_pRequest->Release();
  1094. if (m_pEmptyCookie)
  1095. m_pEmptyCookie->Release();
  1096. }
  1097. /*===================================================================
  1098. CCookies::Init
  1099. Initializer
  1100. Parameters:
  1101. None
  1102. Returns:
  1103. Nothing.
  1104. ===================================================================*/
  1105. HRESULT CCookies::Init()
  1106. {
  1107. return CRequestHitsArray::Init();
  1108. }
  1109. /*===================================================================
  1110. HRESULT CCookies::ReInit
  1111. Parameters:
  1112. None
  1113. Returns:
  1114. S_OK
  1115. ===================================================================*/
  1116. HRESULT CCookies::ReInit()
  1117. {
  1118. return CRequestHitsArray::ReInit();
  1119. }
  1120. /*===================================================================
  1121. CCookies::QueryInterface
  1122. CCookies::AddRef
  1123. CCookies::Release
  1124. IUnknown members for CQueryString object.
  1125. ===================================================================*/
  1126. STDMETHODIMP CCookies::QueryInterface(REFIID iid, void **ppvObj)
  1127. {
  1128. *ppvObj = NULL;
  1129. if (iid == IID_IUnknown || iid == IID_IRequestDictionary || iid == IID_IDispatch)
  1130. *ppvObj = this;
  1131. else if (iid == IID_ISupportErrorInfo)
  1132. *ppvObj = &m_ISupportErrImp;
  1133. if (*ppvObj != NULL)
  1134. {
  1135. static_cast<IUnknown *>(*ppvObj)->AddRef();
  1136. return S_OK;
  1137. }
  1138. return E_NOINTERFACE;
  1139. }
  1140. STDMETHODIMP_(ULONG) CCookies::AddRef(void)
  1141. {
  1142. return m_punkOuter->AddRef();
  1143. }
  1144. STDMETHODIMP_(ULONG) CCookies::Release(void)
  1145. {
  1146. return m_punkOuter->Release();
  1147. }
  1148. /*===================================================================
  1149. CCookies::get_Item
  1150. Function called from DispInvoke to get values from the Cookies collection.
  1151. Parameters:
  1152. vKey VARIANT [in], which parameter to get the value of - Empty means whole collection
  1153. pvarReturn VARIANT *, [out] value of the requested parameter
  1154. Returns:
  1155. S_OK on success, E_FAIL on failure.
  1156. ===================================================================*/
  1157. HRESULT CCookies::get_Item(VARIANT varKey, VARIANT *pvarReturn)
  1158. {
  1159. if (FAILED(m_pRequest->CheckForTombstone()))
  1160. return E_FAIL;
  1161. char *szKey; // ascii version of the key
  1162. CRequestHit *pRequestHit; // pointer to request bucket
  1163. CWCharToMBCS convKey;
  1164. STACK_BUFFER( tempCookie, 128 );
  1165. // Initialize things
  1166. //
  1167. VariantInit(pvarReturn);
  1168. VARIANT *pvarKey = &varKey;
  1169. HRESULT hrReturn = S_OK;
  1170. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
  1171. // produced by IEnumVariant
  1172. //
  1173. // Use VariantResolveDispatch which will:
  1174. //
  1175. // * Copy BYREF variants for us using VariantCopyInd
  1176. // * handle E_OUTOFMEMORY for us
  1177. // * get the default value from an IDispatch, which seems
  1178. // like an appropriate conversion.
  1179. //
  1180. VARIANT varKeyCopy;
  1181. VariantInit(&varKeyCopy);
  1182. DWORD vt = V_VT(pvarKey);
  1183. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  1184. {
  1185. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  1186. goto LExit;
  1187. pvarKey = &varKeyCopy;
  1188. }
  1189. vt = V_VT(pvarKey);
  1190. if (m_pRequest->m_pData->m_fLoadCookies)
  1191. {
  1192. char *szCookie = m_pRequest->GetIReq()->QueryPszCookie();
  1193. if (FAILED(hrReturn = m_pRequest->LoadVariables(COOKIE, szCookie, m_pRequest->GetCodePage())))
  1194. goto LExit;
  1195. m_pRequest->m_pData->m_fLoadCookies = FALSE;
  1196. }
  1197. switch (vt)
  1198. {
  1199. // Bug 95201 support all numberic sub-types
  1200. case VT_I1: case VT_I2: case VT_I8:
  1201. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  1202. case VT_R4: case VT_R8:
  1203. // Coerce all integral types to VT_I4
  1204. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  1205. goto LExit;
  1206. // fallthru to VT_I4
  1207. case VT_I4:
  1208. case VT_BSTR:
  1209. break;
  1210. case VT_ERROR:
  1211. if (V_ERROR(pvarKey) == DISP_E_PARAMNOTFOUND)
  1212. {
  1213. // Dynamically construct value of HTTP_COOKIE.
  1214. //
  1215. // Step 1: figure out how much space we need
  1216. //
  1217. int cbHTTPCookie = 1; // At the least we will need space for '\0'
  1218. for (pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->Head());
  1219. pRequestHit != NULL;
  1220. pRequestHit = static_cast<CRequestHit *>(pRequestHit->m_pNext))
  1221. {
  1222. CCookie *pCookie = pRequestHit->m_pCookieData;
  1223. if (pCookie)
  1224. cbHTTPCookie += pCookie->GetHTTPCookieSize() + pRequestHit->m_cbKey + 1;
  1225. }
  1226. // Allocate space for the HTTP_COOKIE value
  1227. //
  1228. if (cbHTTPCookie > REQUEST_ALLOC_MAX)
  1229. {
  1230. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_STACK_OVERFLOW);
  1231. hrReturn = E_FAIL;
  1232. goto LExit;
  1233. }
  1234. if (tempCookie.Resize(cbHTTPCookie) == FALSE) {
  1235. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  1236. hrReturn = E_OUTOFMEMORY;
  1237. goto LExit;
  1238. }
  1239. char *szHTTPCookie = static_cast<char *>(tempCookie.QueryPtr());
  1240. // Step 2: create the value of HTTP_COOKIE
  1241. //
  1242. char *szDest = szHTTPCookie;
  1243. for (pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->Head());
  1244. pRequestHit != NULL;
  1245. pRequestHit = static_cast<CRequestHit *>(pRequestHit->m_pNext))
  1246. {
  1247. CCookie *pCookie = pRequestHit->m_pCookieData;
  1248. if (pCookie)
  1249. {
  1250. strcpy(szDest, reinterpret_cast<char *>(pRequestHit->m_pKey));
  1251. szDest = strchr(szDest, '\0');
  1252. *szDest++ = '=';
  1253. szDest = pCookie->GetHTTPCookie(szDest);
  1254. if (pRequestHit->m_pNext)
  1255. *szDest++ = ';';
  1256. }
  1257. }
  1258. *szDest = '\0';
  1259. // Now we have the value, so return it.
  1260. //
  1261. BSTR bstrT;
  1262. if (FAILED(SysAllocStringFromSz(szHTTPCookie, 0, &bstrT, m_pRequest->GetCodePage())))
  1263. {
  1264. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  1265. hrReturn = E_OUTOFMEMORY;
  1266. goto LExit;
  1267. }
  1268. V_VT(pvarReturn) = VT_BSTR;
  1269. V_BSTR(pvarReturn) = bstrT;
  1270. goto LExit;
  1271. }
  1272. // Other error, FALL THROUGH to wrong type case
  1273. default:
  1274. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  1275. hrReturn = E_FAIL;
  1276. goto LExit;
  1277. }
  1278. V_VT(pvarReturn) = VT_DISPATCH;
  1279. V_DISPATCH(pvarReturn) = NULL;
  1280. if (vt == VT_BSTR)
  1281. {
  1282. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey),m_pRequest->GetCodePage()))) {
  1283. if (hrReturn == E_OUTOFMEMORY) {
  1284. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  1285. goto LExit;
  1286. }
  1287. hrReturn = NO_ERROR;
  1288. szKey = "";
  1289. }
  1290. else {
  1291. szKey = convKey.GetString();
  1292. }
  1293. pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->FindElem(szKey, strlen(szKey)));
  1294. }
  1295. else
  1296. {
  1297. // Look up item by index
  1298. int iCount;
  1299. iCount = V_I4(pvarKey);
  1300. // BUG 86117 test passes when m_dwCount == 0
  1301. if ( ((iCount < 1) || (iCount > (int) m_dwCount)) || ((iCount > 0) && ((int) m_dwCount == 0)))
  1302. {
  1303. hrReturn = E_FAIL;
  1304. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  1305. goto LExit;
  1306. }
  1307. pRequestHit = m_rgRequestHit[iCount - 1];
  1308. }
  1309. if (pRequestHit)
  1310. {
  1311. CCookie *pDictionary = pRequestHit->m_pCookieData;
  1312. if (pDictionary == NULL)
  1313. goto LNotFound;
  1314. if (FAILED(pDictionary->QueryInterface(IID_IReadCookie, reinterpret_cast<void **>(&V_DISPATCH(pvarReturn)))))
  1315. Assert (FALSE);
  1316. goto LExit;
  1317. }
  1318. LNotFound: // Return Empty Cookie
  1319. if (!m_pEmptyCookie)
  1320. {
  1321. // create on demand
  1322. if ((m_pEmptyCookie = new CCookie(m_pRequest->GetIReq(), m_pRequest->GetCodePage())) != NULL)
  1323. hrReturn = m_pEmptyCookie->Init();
  1324. else
  1325. hrReturn = E_OUTOFMEMORY;
  1326. }
  1327. if (m_pEmptyCookie)
  1328. hrReturn = m_pEmptyCookie->QueryInterface(IID_IReadCookie, reinterpret_cast<void **>(&V_DISPATCH(pvarReturn)));
  1329. LExit:
  1330. VariantClear(&varKeyCopy);
  1331. return hrReturn;
  1332. }
  1333. /*===================================================================
  1334. CCookies::get_Key
  1335. Function called from DispInvoke to get keys from the cookie collection.
  1336. Parameters:
  1337. vKey VARIANT [in], which parameter to get the key of
  1338. pvarReturn VARIANT *, [out] value of the requested parameter
  1339. Returns:
  1340. S_OK on success, E_FAIL on failure.
  1341. ===================================================================*/
  1342. HRESULT CCookies::get_Key(VARIANT varKey, VARIANT *pVar)
  1343. {
  1344. if (FAILED(m_pRequest->CheckForTombstone()))
  1345. return E_FAIL;
  1346. char *szKey; // ascii version of the key
  1347. CWCharToMBCS convKey;
  1348. CRequestHit *pRequestHit; // pointer to request bucket
  1349. IDispatch *pSListReturn; // value of the key
  1350. // Initialize things
  1351. //
  1352. VariantInit(pVar);
  1353. VARIANT *pvarKey = &varKey;
  1354. V_VT(pVar) = VT_BSTR;
  1355. V_BSTR(pVar) = NULL;
  1356. HRESULT hrReturn = S_OK;
  1357. // Use VariantResolveDispatch which will:
  1358. //
  1359. // * Copy BYREF variants for us using VariantCopyInd
  1360. // * handle E_OUTOFMEMORY for us
  1361. // * get the default value from an IDispatch, which seems
  1362. // like an appropriate conversion.
  1363. //
  1364. VARIANT varKeyCopy;
  1365. VariantInit(&varKeyCopy);
  1366. DWORD vt = V_VT(pvarKey);
  1367. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  1368. {
  1369. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  1370. goto LExit;
  1371. pvarKey = &varKeyCopy;
  1372. }
  1373. vt = V_VT(pvarKey);
  1374. switch (vt)
  1375. {
  1376. // Bug 95201 support all numberic sub-types
  1377. case VT_I1: case VT_I2: case VT_I8:
  1378. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  1379. case VT_R4: case VT_R8:
  1380. // Coerce all integral types to VT_I4
  1381. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  1382. goto LExit;
  1383. // fallthru to VT_I4
  1384. case VT_I4:
  1385. case VT_BSTR:
  1386. break;
  1387. default:
  1388. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  1389. hrReturn = E_FAIL;
  1390. goto LExit;
  1391. }
  1392. if (m_pRequest->m_pData->m_fLoadCookies)
  1393. {
  1394. char *szCookie = m_pRequest->GetIReq()->QueryPszCookie();
  1395. if (FAILED(hrReturn = m_pRequest->LoadVariables(COOKIE, szCookie, m_pRequest->GetCodePage())))
  1396. goto LExit;
  1397. m_pRequest->m_pData->m_fLoadCookies = FALSE;
  1398. }
  1399. if (vt == VT_BSTR)
  1400. {
  1401. // convert BSTR version to ANSI version of the key using current Session.CodePage
  1402. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey), m_pRequest->GetCodePage()))) {
  1403. if (hrReturn == E_OUTOFMEMORY) {
  1404. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  1405. goto LExit;
  1406. }
  1407. hrReturn = NO_ERROR;
  1408. szKey = "";
  1409. }
  1410. else {
  1411. szKey = convKey.GetString();
  1412. }
  1413. pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->FindElem(szKey, strlen(szKey)));
  1414. }
  1415. else
  1416. {
  1417. int iCount;
  1418. iCount = V_I4(pvarKey);
  1419. // BUG 86117 test passes when m_dwCount == 0
  1420. if ( ((iCount < 1) || (iCount > (int) m_dwCount)) || ((iCount > 0) && ((int) m_dwCount == 0)))
  1421. {
  1422. hrReturn = E_FAIL;
  1423. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  1424. goto LExit;
  1425. }
  1426. pRequestHit = m_rgRequestHit[iCount - 1];
  1427. }
  1428. if (pRequestHit)
  1429. {
  1430. // Create a BSTR containing the key for this variant
  1431. BSTR bstrT = NULL;
  1432. SysAllocStringFromSz((char *)pRequestHit->m_pKey,0,&bstrT,m_pRequest->GetCodePage());
  1433. if (!bstrT)
  1434. return E_OUTOFMEMORY;
  1435. V_BSTR(pVar) = bstrT;
  1436. }
  1437. LExit:
  1438. VariantClear(&varKeyCopy);
  1439. return hrReturn;
  1440. }
  1441. /*===================================================================
  1442. CCookies::get_Count
  1443. Parameters:
  1444. pcValues - count is stored in *pcValues
  1445. ===================================================================*/
  1446. STDMETHODIMP CCookies::get_Count(int *pcValues)
  1447. {
  1448. if (FAILED(m_pRequest->CheckForTombstone()))
  1449. return E_FAIL;
  1450. HRESULT hrReturn = S_OK;
  1451. if (m_pRequest->m_pData->m_fLoadCookies)
  1452. {
  1453. char *szCookie = m_pRequest->GetIReq()->QueryPszCookie();
  1454. if (FAILED(hrReturn = m_pRequest->LoadVariables(COOKIE, szCookie, m_pRequest->GetCodePage())))
  1455. goto LExit;
  1456. m_pRequest->m_pData->m_fLoadCookies = FALSE;
  1457. }
  1458. *pcValues = m_dwCount;
  1459. LExit:
  1460. return hrReturn;
  1461. }
  1462. /*===================================================================
  1463. CCookies::get__NewEnum
  1464. Return a new enumerator
  1465. ===================================================================*/
  1466. HRESULT CCookies::get__NewEnum(IUnknown **ppEnumReturn)
  1467. {
  1468. if (FAILED(m_pRequest->CheckForTombstone()))
  1469. return E_FAIL;
  1470. return m_pRequest->GetRequestEnumerator(COOKIE, ppEnumReturn);
  1471. }
  1472. /*------------------------------------------------------------------
  1473. * C C l C e r t s
  1474. */
  1475. /*===================================================================
  1476. CClCerts::CClCerts
  1477. Constructor
  1478. Parameters:
  1479. pRequest Pointer to main Request object
  1480. pUnkOuter LPUNKNOWN of a controlling unknown.
  1481. Returns:
  1482. Nothing.
  1483. Note:
  1484. This object is NOT ref counted since it is created & destroyed
  1485. automatically by C++.
  1486. ===================================================================*/
  1487. CClCerts::CClCerts(CRequest *pRequest, IUnknown *pUnkOuter)
  1488. : m_ISupportErrImp(this, pUnkOuter, IID_IRequestDictionary)
  1489. {
  1490. m_punkOuter = pUnkOuter;
  1491. if (pRequest)
  1492. pRequest->AddRef();
  1493. m_pRequest = pRequest;
  1494. m_pEmptyClCert = NULL;
  1495. CDispatch::Init(IID_IRequestDictionary);
  1496. }
  1497. /*===================================================================
  1498. CClCerts::ClCerts
  1499. Destructor
  1500. Note:
  1501. This object is NOT ref counted since it is created & destroyed
  1502. automatically by C++.
  1503. ===================================================================*/
  1504. CClCerts::~CClCerts()
  1505. {
  1506. if (m_pRequest)
  1507. m_pRequest->Release();
  1508. if (m_pEmptyClCert)
  1509. m_pEmptyClCert->Release();
  1510. }
  1511. /*===================================================================
  1512. CClCerts::Init
  1513. Initializer
  1514. Parameters:
  1515. None
  1516. Returns:
  1517. Nothing.
  1518. ===================================================================*/
  1519. HRESULT CClCerts::Init()
  1520. {
  1521. return CRequestHitsArray::Init();
  1522. }
  1523. /*===================================================================
  1524. CClCerts::ReInit
  1525. Parameters:
  1526. None
  1527. Returns:
  1528. S_OK
  1529. ===================================================================*/
  1530. HRESULT CClCerts::ReInit()
  1531. {
  1532. return CRequestHitsArray::ReInit();
  1533. }
  1534. /*===================================================================
  1535. CClCerts::QueryInterface
  1536. CClCerts::AddRef
  1537. CClCerts::Release
  1538. IUnknown members for CQueryString object.
  1539. ===================================================================*/
  1540. STDMETHODIMP CClCerts::QueryInterface(REFIID riid, void **ppv)
  1541. {
  1542. *ppv = NULL;
  1543. if (riid == IID_IUnknown || riid == IID_IRequestDictionary || riid == IID_IDispatch)
  1544. *ppv = this;
  1545. else if (riid == IID_ISupportErrorInfo)
  1546. *ppv = &m_ISupportErrImp;
  1547. if (*ppv != NULL)
  1548. {
  1549. static_cast<IUnknown *>(*ppv)->AddRef();
  1550. return S_OK;
  1551. }
  1552. return ResultFromScode(E_NOINTERFACE);
  1553. }
  1554. STDMETHODIMP_(ULONG) CClCerts::AddRef(void)
  1555. {
  1556. return m_punkOuter->AddRef();
  1557. }
  1558. STDMETHODIMP_(ULONG) CClCerts::Release(void)
  1559. {
  1560. return m_punkOuter->Release();
  1561. }
  1562. /*===================================================================
  1563. CClCerts::get_Item
  1564. Function called from DispInvoke to get values from the ClCerts collection.
  1565. Parameters:
  1566. vKey VARIANT [in], which parameter to get the value of - Empty means whole collection
  1567. pvarReturn VARIANT *, [out] value of the requested parameter
  1568. Returns:
  1569. S_OK on success, S_FALSE if key not found, E_FAIL on failure.
  1570. ===================================================================*/
  1571. HRESULT CClCerts::get_Item(VARIANT varKey, VARIANT *pvarReturn)
  1572. {
  1573. if (FAILED(m_pRequest->CheckForTombstone()))
  1574. return E_FAIL;
  1575. char *szKey; // ascii version of the key
  1576. CRequestHit *pRequestHit; // pointer to request bucket
  1577. CWCharToMBCS convKey;
  1578. // Initialize things
  1579. //
  1580. VariantInit(pvarReturn);
  1581. VARIANT *pvarKey = &varKey;
  1582. HRESULT hrReturn = S_OK;
  1583. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
  1584. // produced by IEnumVariant
  1585. //
  1586. // Use VariantResolveDispatch which will:
  1587. //
  1588. // * Copy BYREF variants for us using VariantCopyInd
  1589. // * handle E_OUTOFMEMORY for us
  1590. // * get the default value from an IDispatch, which seems
  1591. // like an appropriate conversion.
  1592. //
  1593. VARIANT varKeyCopy;
  1594. VariantInit(&varKeyCopy);
  1595. DWORD vt = V_VT(pvarKey);
  1596. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  1597. {
  1598. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  1599. goto LExit;
  1600. pvarKey = &varKeyCopy;
  1601. }
  1602. vt = V_VT(pvarKey);
  1603. if (m_pRequest->m_pData->m_fLoadClCerts)
  1604. {
  1605. if (FAILED(hrReturn = m_pRequest->LoadVariables(CLCERT, reinterpret_cast<char *>(m_pRequest->GetIReq()), m_pRequest->GetCodePage())))
  1606. goto LExit;
  1607. m_pRequest->m_pData->m_fLoadClCerts = FALSE;
  1608. }
  1609. switch (vt)
  1610. {
  1611. // Bug 95201 support all numberic sub-types
  1612. case VT_I1: case VT_I2: case VT_I8:
  1613. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  1614. case VT_R4: case VT_R8:
  1615. // Coerce all integral types to VT_I4
  1616. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  1617. goto LExit;
  1618. // fallthru to VT_I4
  1619. case VT_I4:
  1620. case VT_BSTR:
  1621. break;
  1622. case VT_ERROR:
  1623. if (V_ERROR(pvarKey) == DISP_E_PARAMNOTFOUND)
  1624. {
  1625. // Dynamically construct value of CLCERT
  1626. //
  1627. // Step 1: figure out how much space we need
  1628. //
  1629. int cbHTTPClCert = 0;
  1630. for (pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->Head());
  1631. pRequestHit != NULL;
  1632. pRequestHit = static_cast<CRequestHit *>(pRequestHit->m_pNext))
  1633. {
  1634. CClCert *pClCert = pRequestHit->m_pClCertData;
  1635. if (pClCert)
  1636. cbHTTPClCert += pClCert->GetHTTPClCertSize() + pRequestHit->m_cbKey + 1;
  1637. }
  1638. STACK_BUFFER( tempClCert, 256);
  1639. if (!tempClCert.Resize(cbHTTPClCert)) {
  1640. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  1641. hrReturn = E_OUTOFMEMORY;
  1642. goto LExit;
  1643. }
  1644. char *szHTTPClCert = static_cast<char *>(tempClCert.QueryPtr());
  1645. // Step 2: create the value of CLCERT
  1646. //
  1647. char *szDest = szHTTPClCert;
  1648. for (pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->Head());
  1649. pRequestHit != NULL;
  1650. pRequestHit = static_cast<CRequestHit *>(pRequestHit->m_pNext))
  1651. {
  1652. CClCert *pClCert = pRequestHit->m_pClCertData;
  1653. if (pClCert)
  1654. {
  1655. strcpy(szDest, reinterpret_cast<char *>(pRequestHit->m_pKey));
  1656. szDest = strchr(szDest, '\0');
  1657. *szDest++ = '=';
  1658. szDest = pClCert->GetHTTPClCert(szDest);
  1659. if (pRequestHit->m_pNext)
  1660. *szDest++ = ';';
  1661. }
  1662. }
  1663. *szDest = '\0';
  1664. // Now we have the value, so return it.
  1665. //
  1666. BSTR bstrT;
  1667. if (FAILED(SysAllocStringFromSz(szHTTPClCert, 0, &bstrT)))
  1668. {
  1669. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  1670. hrReturn = E_OUTOFMEMORY;
  1671. goto LExit;
  1672. }
  1673. V_VT(pvarReturn) = VT_BSTR;
  1674. V_BSTR(pvarReturn) = bstrT;
  1675. goto LExit;
  1676. }
  1677. // Other error, FALL THROUGH to wrong type case
  1678. default:
  1679. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  1680. hrReturn = E_FAIL;
  1681. goto LExit;
  1682. }
  1683. V_VT(pvarReturn) = VT_DISPATCH;
  1684. V_DISPATCH(pvarReturn) = NULL;
  1685. if (vt == VT_BSTR)
  1686. {
  1687. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey)))) {
  1688. if (hrReturn == E_OUTOFMEMORY) {
  1689. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  1690. goto LExit;
  1691. }
  1692. hrReturn = NO_ERROR;
  1693. szKey = "";
  1694. }
  1695. else {
  1696. szKey = convKey.GetString();
  1697. }
  1698. pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->FindElem(szKey, strlen(szKey)));
  1699. }
  1700. else
  1701. {
  1702. // Look up item by index
  1703. int iCount;
  1704. iCount = V_I4(pvarKey);
  1705. // BUG 86117 test passes when m_dwCount == 0
  1706. if ( ((iCount < 1) || (iCount > (int) m_dwCount)) || ((iCount > 0) && ((int) m_dwCount == 0)))
  1707. {
  1708. hrReturn = E_FAIL;
  1709. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  1710. goto LExit;
  1711. }
  1712. pRequestHit = m_rgRequestHit[iCount - 1];
  1713. }
  1714. if (pRequestHit)
  1715. {
  1716. CClCert *pDictionary = pRequestHit->m_pClCertData;
  1717. if (pDictionary == NULL)
  1718. goto LNotFound;
  1719. if (FAILED(pDictionary->QueryInterface(IID_IRequestDictionary, reinterpret_cast<void **>(&V_DISPATCH(pvarReturn)))))
  1720. Assert (FALSE);
  1721. goto LExit;
  1722. }
  1723. LNotFound: // Return "Empty"
  1724. if (!m_pEmptyClCert)
  1725. {
  1726. // create on demand
  1727. if ((m_pEmptyClCert = new CClCert) != NULL)
  1728. hrReturn = m_pEmptyClCert->Init();
  1729. else
  1730. hrReturn = E_OUTOFMEMORY;
  1731. }
  1732. if (m_pEmptyClCert)
  1733. hrReturn = m_pEmptyClCert->QueryInterface(IID_IRequestDictionary, reinterpret_cast<void **>(&V_DISPATCH(pvarReturn)));
  1734. LExit:
  1735. VariantClear(&varKeyCopy);
  1736. return hrReturn;
  1737. }
  1738. /*===================================================================
  1739. CClCerts::get_Key
  1740. Function called from DispInvoke to get keys from the certificate collection.
  1741. Parameters:
  1742. vKey VARIANT [in], which parameter to get the key of
  1743. pvarReturn VARIANT *, [out] value of the requested parameter
  1744. Returns:
  1745. S_OK on success, E_FAIL on failure.
  1746. ===================================================================*/
  1747. HRESULT CClCerts::get_Key(VARIANT varKey, VARIANT *pVar)
  1748. {
  1749. if (FAILED(m_pRequest->CheckForTombstone()))
  1750. return E_FAIL;
  1751. char *szKey; // ascii version of the key
  1752. CWCharToMBCS convKey;
  1753. CRequestHit *pRequestHit; // pointer to request bucket
  1754. // Initialize things
  1755. //
  1756. VariantInit(pVar);
  1757. VARIANT *pvarKey = &varKey;
  1758. V_VT(pVar) = VT_BSTR;
  1759. V_BSTR(pVar) = NULL;
  1760. HRESULT hrReturn = S_OK;
  1761. // Use VariantResolveDispatch which will:
  1762. //
  1763. // * Copy BYREF variants for us using VariantCopyInd
  1764. // * handle E_OUTOFMEMORY for us
  1765. // * get the default value from an IDispatch, which seems
  1766. // like an appropriate conversion.
  1767. //
  1768. VARIANT varKeyCopy;
  1769. VariantInit(&varKeyCopy);
  1770. DWORD vt = V_VT(pvarKey);
  1771. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  1772. {
  1773. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  1774. goto LExit;
  1775. pvarKey = &varKeyCopy;
  1776. }
  1777. vt = V_VT(pvarKey);
  1778. switch (vt)
  1779. {
  1780. // Bug 95201 support all numberic sub-types
  1781. case VT_I1: case VT_I2: case VT_I8:
  1782. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  1783. case VT_R4: case VT_R8:
  1784. // Coerce all integral types to VT_I4
  1785. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  1786. goto LExit;
  1787. // fallthru to VT_I4
  1788. case VT_I4:
  1789. case VT_BSTR:
  1790. break;
  1791. default:
  1792. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  1793. hrReturn = E_FAIL;
  1794. goto LExit;
  1795. }
  1796. if (m_pRequest->m_pData->m_fLoadClCerts)
  1797. {
  1798. if (FAILED(hrReturn = m_pRequest->LoadVariables(CLCERT, reinterpret_cast<char *>(m_pRequest->GetIReq()), m_pRequest->GetCodePage())))
  1799. {
  1800. goto LExit;
  1801. }
  1802. m_pRequest->m_pData->m_fLoadClCerts = FALSE;
  1803. }
  1804. if (vt == VT_BSTR)
  1805. {
  1806. // convert BSTR version to ANSI version of the key using current Session.CodePage
  1807. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey), m_pRequest->GetCodePage()))) {
  1808. if (hrReturn == E_OUTOFMEMORY) {
  1809. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  1810. goto LExit;
  1811. }
  1812. hrReturn = NO_ERROR;
  1813. szKey = "";
  1814. }
  1815. else {
  1816. szKey = convKey.GetString();
  1817. }
  1818. pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->FindElem(szKey, strlen(szKey)));
  1819. }
  1820. else
  1821. {
  1822. int iCount;
  1823. iCount = V_I4(pvarKey);
  1824. // BUG 86117 test passes when m_dwCount == 0
  1825. if ( ((iCount < 1) || (iCount > (int) m_dwCount)) || ((iCount > 0) && ((int) m_dwCount == 0)))
  1826. {
  1827. hrReturn = E_FAIL;
  1828. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  1829. goto LExit;
  1830. }
  1831. pRequestHit = m_rgRequestHit[iCount - 1];
  1832. }
  1833. if (pRequestHit)
  1834. {
  1835. // Create a BSTR containing the key for this variant
  1836. BSTR bstrT = NULL;
  1837. SysAllocStringFromSz((char *)pRequestHit->m_pKey,0,&bstrT,m_pRequest->GetCodePage());
  1838. if (!bstrT)
  1839. return E_OUTOFMEMORY;
  1840. V_BSTR(pVar) = bstrT;
  1841. }
  1842. LExit:
  1843. VariantClear(&varKeyCopy);
  1844. return hrReturn;
  1845. }
  1846. /*===================================================================
  1847. CClCerts::get_Count
  1848. Parameters:
  1849. pcValues - count is stored in *pcValues
  1850. ===================================================================*/
  1851. STDMETHODIMP CClCerts::get_Count(int *pcValues)
  1852. {
  1853. if (FAILED(m_pRequest->CheckForTombstone()))
  1854. return E_FAIL;
  1855. HRESULT hrReturn = S_OK;
  1856. if (m_pRequest->m_pData->m_fLoadClCerts)
  1857. {
  1858. if (FAILED(hrReturn = m_pRequest->LoadVariables(CLCERT, reinterpret_cast<char *>(m_pRequest->GetIReq()), m_pRequest->GetCodePage())))
  1859. {
  1860. goto LExit;
  1861. }
  1862. m_pRequest->m_pData->m_fLoadClCerts = FALSE;
  1863. }
  1864. *pcValues = m_dwCount;
  1865. LExit:
  1866. return hrReturn;
  1867. }
  1868. /*===================================================================
  1869. CClCerts::get__NewEnum
  1870. Return a new enumerator
  1871. ===================================================================*/
  1872. HRESULT CClCerts::get__NewEnum(IUnknown **ppEnumReturn)
  1873. {
  1874. if (FAILED(m_pRequest->CheckForTombstone()))
  1875. return E_FAIL;
  1876. return m_pRequest->GetRequestEnumerator(CLCERT, ppEnumReturn);
  1877. }
  1878. /*------------------------------------------------------------------
  1879. * C S e r v e r V a r i a b l e s
  1880. */
  1881. /*===================================================================
  1882. CServerVariables::CServerVariables
  1883. Constructor
  1884. Parameters:
  1885. pRequest Pointer to main Request object
  1886. pUnkOuter LPUNKNOWN of a controlling unknown.
  1887. Returns:
  1888. Nothing.
  1889. Note:
  1890. This object is NOT ref counted since it is created & destroyed
  1891. automatically by C++.
  1892. ===================================================================*/
  1893. CServerVariables::CServerVariables(CRequest *pRequest, IUnknown *pUnkOuter)
  1894. : m_ISupportErrImp(this, pUnkOuter, IID_IRequestDictionary),
  1895. m_pIterator(NULL)
  1896. {
  1897. m_punkOuter = pUnkOuter;
  1898. if (pRequest)
  1899. pRequest->AddRef();
  1900. m_pRequest = pRequest;
  1901. CDispatch::Init(IID_IRequestDictionary);
  1902. }
  1903. /*===================================================================
  1904. CServerVariables::~CServerVariables
  1905. Destructor
  1906. Parameters:
  1907. None
  1908. Returns:
  1909. Nothing.
  1910. Note:
  1911. This object is NOT ref counted since it is created & destroyed
  1912. automatically by C++.
  1913. ===================================================================*/
  1914. CServerVariables::~CServerVariables( )
  1915. {
  1916. if (m_pRequest)
  1917. m_pRequest->Release();
  1918. if (m_pIterator)
  1919. m_pIterator->Release();
  1920. }
  1921. /*===================================================================
  1922. CServerVariables::QueryInterface
  1923. CServerVariables::AddRef
  1924. CServerVariables::Release
  1925. IUnknown members for CFormInputs object.
  1926. ===================================================================*/
  1927. STDMETHODIMP CServerVariables::QueryInterface(REFIID iid, void **ppvObj)
  1928. {
  1929. *ppvObj = NULL;
  1930. if (iid == IID_IUnknown || iid == IID_IRequestDictionary || iid == IID_IDispatch)
  1931. *ppvObj = this;
  1932. else if (iid == IID_ISupportErrorInfo)
  1933. *ppvObj = &m_ISupportErrImp;
  1934. if (*ppvObj != NULL)
  1935. {
  1936. static_cast<IUnknown *>(*ppvObj)->AddRef();
  1937. return S_OK;
  1938. }
  1939. return E_NOINTERFACE;
  1940. }
  1941. STDMETHODIMP_(ULONG) CServerVariables::AddRef(void)
  1942. {
  1943. return m_punkOuter->AddRef();
  1944. }
  1945. STDMETHODIMP_(ULONG) CServerVariables::Release(void)
  1946. {
  1947. return m_punkOuter->Release();
  1948. }
  1949. /*===================================================================
  1950. CServerVariables::get_Item
  1951. Function called from DispInvoke to get values from the ServerVariables
  1952. collection.
  1953. Parameters:
  1954. vKey VARIANT [in], which parameter to get the value of
  1955. pvarReturn VARIANT *, [out] value of the requested parameter
  1956. Returns:
  1957. S_OK on success, E_FAIL on failure.
  1958. NOTE:
  1959. This code is basically an enacpsulation from the SERVER_GET macro,
  1960. only more efficient, since it only looks up the key once on average
  1961. unfortunately, the only way to get good memory utilization with
  1962. ISAPI is to use _alloca() with lookups, which means we can't
  1963. encapsulate the lookup logic very well.
  1964. ===================================================================*/
  1965. HRESULT CServerVariables::get_Item(VARIANT varKey, VARIANT *pvarReturn)
  1966. {
  1967. if (FAILED(m_pRequest->CheckForTombstone()))
  1968. return E_FAIL;
  1969. DWORD dwValSize; // buffer size
  1970. char *szKey; // pointer to ASCII value of varKey
  1971. char *szValue;
  1972. WCHAR *wszValue;
  1973. BOOL fSuccess; // TRUE when call to GetServerVariable succeeds
  1974. UINT uCodePage = CP_ACP;
  1975. CWCharToMBCS convKey;
  1976. BOOL fUnicodeVar = FALSE;
  1977. STACK_BUFFER( tempVal, 128 );
  1978. dwValSize = tempVal.QuerySize();
  1979. szValue = (char *)tempVal.QueryPtr();
  1980. wszValue = (WCHAR *)tempVal.QueryPtr();
  1981. // Initialize things
  1982. //
  1983. VariantInit(pvarReturn);
  1984. VARIANT *pvarKey = &varKey;
  1985. HRESULT hrReturn = S_OK;
  1986. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
  1987. // produced by IEnumVariant
  1988. //
  1989. // Use VariantResolveDispatch which will:
  1990. //
  1991. // * Copy BYREF variants for us using VariantCopyInd
  1992. // * handle E_OUTOFMEMORY for us
  1993. // * get the default value from an IDispatch, which seems
  1994. // like an appropriate conversion.
  1995. //
  1996. VARIANT varKeyCopy;
  1997. VariantInit(&varKeyCopy);
  1998. DWORD vt = V_VT(pvarKey);
  1999. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4)) {
  2000. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  2001. goto LExit;
  2002. pvarKey = &varKeyCopy;
  2003. }
  2004. vt = V_VT(pvarKey);
  2005. V_VT(pvarReturn) = VT_DISPATCH;
  2006. V_DISPATCH(pvarReturn) = NULL; // initial value of Nothing
  2007. switch (vt) {
  2008. // Bug 95201 support all numberic sub-types
  2009. case VT_I1: case VT_I2: case VT_I8:
  2010. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  2011. case VT_R4: case VT_R8:
  2012. // Coerce all integral types to VT_I4
  2013. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  2014. goto LExit;
  2015. // fallthru to VT_I4
  2016. case VT_I4:
  2017. case VT_BSTR:
  2018. break;
  2019. case VT_ERROR:
  2020. if (V_ERROR(pvarKey) == DISP_E_PARAMNOTFOUND) {
  2021. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_NOT_ALLOWED);
  2022. hrReturn = E_FAIL;
  2023. goto LExit;
  2024. }
  2025. // Other error, FALL THROUGH to wrong type case
  2026. default:
  2027. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  2028. hrReturn = E_FAIL;
  2029. goto LExit;
  2030. }
  2031. uCodePage = m_pRequest->GetCodePage();
  2032. if (vt == VT_BSTR) {
  2033. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey), uCodePage))) {
  2034. if (hrReturn == E_OUTOFMEMORY) {
  2035. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  2036. goto LExit;
  2037. }
  2038. hrReturn = NO_ERROR;
  2039. szKey = "";
  2040. }
  2041. else {
  2042. szKey = CharUpperA(convKey.GetString());
  2043. }
  2044. }
  2045. else {
  2046. // Look up item by index
  2047. int iCount;
  2048. iCount = V_I4(pvarKey);
  2049. // We use the CServVarsIterator to manange
  2050. // the count of sv and integer index
  2051. if (!m_pIterator) {
  2052. m_pIterator = new CServVarsIterator;
  2053. if (!m_pIterator) {
  2054. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  2055. hrReturn = E_OUTOFMEMORY;
  2056. goto LExit;
  2057. }
  2058. if (FAILED(hrReturn=m_pIterator->Init(m_pRequest->m_pData->m_pIReq)))
  2059. goto LExit;
  2060. }
  2061. // BUG 86117 test passes when m_dwCount == 0
  2062. if ( ((iCount < 1) || (iCount > (int) m_pIterator->m_cKeys)) || ((iCount > 0) && ((int) m_pIterator->m_cKeys == 0))) {
  2063. hrReturn = E_FAIL;
  2064. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  2065. goto LExit;
  2066. }
  2067. if (FAILED(hrReturn = convKey.Init(m_pIterator->m_rgwszKeys[iCount - 1], uCodePage))) {
  2068. if (hrReturn == E_OUTOFMEMORY) {
  2069. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  2070. goto LExit;
  2071. }
  2072. hrReturn = NO_ERROR;
  2073. szKey = "";
  2074. }
  2075. else {
  2076. szKey = CharUpperA(convKey.GetString());
  2077. }
  2078. }
  2079. if (strncmp(convKey.GetString(), "UNICODE_", 7) == 0) {
  2080. fSuccess = false;
  2081. goto SkipLookup;
  2082. }
  2083. #if _IIS_6_0
  2084. // in IIS6, there are a number of variables that are UNICODE. To
  2085. // access them, you simply place UNICODE_ infront of the name.
  2086. // Two approaches could be taken here. One would be to always
  2087. // try for a UNICODE_ var and fallback to the non-UNICODE var
  2088. // if the lookup fails. This can be costly. The second, and
  2089. // chosen method here, would be to maintain a list of vars
  2090. // that have UNICODE_ versions.
  2091. // this char array is declared on the stack and is currently only
  2092. // 32 chars. It only needs to be as big as the largest UNICODE
  2093. // var name. Which is UNICODE_UNMAPPED_REMOTE_USER.
  2094. char szUNICODEName[32];
  2095. // search the list to see if this is one of the UNICODE_ vars.
  2096. // the list is sorted by length of string. The current list is
  2097. // not all that long, so a sequential search is not that expensive
  2098. // in the scheme of things.
  2099. for (int i=0;
  2100. (g_sUNICODEVars[i].varLen != -1)
  2101. && (convKey.GetStringLen() >= g_sUNICODEVars[i].varLen);
  2102. i++) {
  2103. // the 'for' loop allows in anything which is at least as long
  2104. // as the current entry. The following 'if' will check for
  2105. // for an exact length match and then a string compare.
  2106. if ((convKey.GetStringLen() == g_sUNICODEVars[i].varLen)
  2107. && (strcmp(convKey.GetString(), g_sUNICODEVars[i].szVarName) == 0)) {
  2108. // if a hit is made, set the fUnicodeVar = TRUE so that the
  2109. // right ISAPI lookup routine is called and the right StringList
  2110. // AddValue is called.
  2111. fUnicodeVar = TRUE;
  2112. // build up the UNICODE_ version into the stack temp array
  2113. strcpyExA(strcpyExA(szUNICODEName,"UNICODE_"),convKey.GetString());
  2114. // reassign the key name to this value
  2115. szKey = szUNICODEName;
  2116. break;
  2117. }
  2118. }
  2119. #endif
  2120. fSuccess = fUnicodeVar
  2121. ? m_pRequest->GetIReq()->GetServerVariableW(szKey, wszValue, &dwValSize)
  2122. : m_pRequest->GetIReq()->GetServerVariableA(szKey, szValue, &dwValSize);
  2123. if (!fSuccess && (dwValSize > tempVal.QuerySize())) {
  2124. if (dwValSize > REQUEST_ALLOC_MAX) {
  2125. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_STACK_OVERFLOW);
  2126. hrReturn = E_FAIL;
  2127. goto LExit;
  2128. }
  2129. if (tempVal.Resize(dwValSize) == FALSE) {
  2130. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  2131. hrReturn = E_OUTOFMEMORY;
  2132. goto LExit;
  2133. }
  2134. szValue = static_cast<char *>(tempVal.QueryPtr());
  2135. wszValue = static_cast<WCHAR *>(tempVal.QueryPtr());
  2136. fSuccess = fUnicodeVar
  2137. ? m_pRequest->GetIReq()->GetServerVariableW(szKey, wszValue, &dwValSize)
  2138. : m_pRequest->GetIReq()->GetServerVariableA(szKey, szValue, &dwValSize);
  2139. }
  2140. SkipLookup:
  2141. if (fSuccess) {
  2142. // Create return value
  2143. CStringList *pValue = new CStringList;
  2144. if (pValue == NULL) {
  2145. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  2146. hrReturn = E_OUTOFMEMORY;
  2147. goto LExit;
  2148. }
  2149. // add the value and QueryInterface for IDispatch interface - strdup the input string
  2150. if (FAILED(hrReturn = (fUnicodeVar
  2151. ? pValue->AddValue(wszValue, TRUE)
  2152. : pValue->AddValue(szValue, TRUE, uCodePage))))
  2153. goto LExit;
  2154. if (FAILED(pValue->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&V_DISPATCH(pvarReturn)))))
  2155. Assert (FALSE);
  2156. // Release temporary (QueryInterface AddRef'd)
  2157. pValue->Release();
  2158. goto LExit;
  2159. }
  2160. else {
  2161. if (FAILED(m_pRequest->m_pData->GetEmptyStringList(&V_DISPATCH(pvarReturn))))
  2162. hrReturn = E_FAIL;
  2163. }
  2164. LExit:
  2165. VariantClear(&varKeyCopy);
  2166. return hrReturn;
  2167. }
  2168. /*===================================================================
  2169. CServerVariables::get_Key
  2170. Function called from DispInvoke to get keys from the server variables collection.
  2171. Parameters:
  2172. vKey VARIANT [in], which parameter to get the key of
  2173. pvarReturn VARIANT *, [out] value of the requested parameter
  2174. Returns:
  2175. S_OK on success, E_FAIL on failure.
  2176. ===================================================================*/
  2177. HRESULT CServerVariables::get_Key(VARIANT varKey, VARIANT *pVar)
  2178. {
  2179. HRESULT hrReturn = S_OK;
  2180. int iCount = 0;
  2181. BSTR bstrT = NULL;
  2182. if (FAILED(m_pRequest->CheckForTombstone()))
  2183. return E_FAIL;
  2184. char *szKey; // ascii version of the key
  2185. CRequestHit *pRequestHit; // pointer to request bucket
  2186. IDispatch *pSListReturn; // value of the key
  2187. CWCharToMBCS convKey;
  2188. // Initialize things
  2189. //
  2190. VariantInit(pVar);
  2191. VARIANT *pvarKey = &varKey;
  2192. V_VT(pVar) = VT_BSTR;
  2193. V_BSTR(pVar) = NULL;
  2194. // Use VariantResolveDispatch which will:
  2195. //
  2196. // * Copy BYREF variants for us using VariantCopyInd
  2197. // * handle E_OUTOFMEMORY for us
  2198. // * get the default value from an IDispatch, which seems
  2199. // like an appropriate conversion.
  2200. //
  2201. VARIANT varKeyCopy;
  2202. VariantInit(&varKeyCopy);
  2203. DWORD vt = V_VT(pvarKey);
  2204. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  2205. {
  2206. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  2207. goto LExit;
  2208. pvarKey = &varKeyCopy;
  2209. }
  2210. vt = V_VT(pvarKey);
  2211. switch (vt)
  2212. {
  2213. // Bug 95201 support all numberic sub-types
  2214. case VT_I1: case VT_I2: case VT_I8:
  2215. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  2216. case VT_R4: case VT_R8:
  2217. // Coerce all integral types to VT_I4
  2218. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  2219. goto LExit;
  2220. vt = V_VT(pvarKey);
  2221. // fallthru to VT_I4
  2222. case VT_I4:
  2223. case VT_BSTR:
  2224. break;
  2225. default:
  2226. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  2227. hrReturn = E_FAIL;
  2228. goto LExit;
  2229. }
  2230. // At this point the VT of pvarKey should be VT_I4 or VT_BSTR
  2231. Assert((vt == VT_I4) || (vt == VT_BSTR));
  2232. if (vt == VT_I4)
  2233. {
  2234. // We were passed in a number.
  2235. // Look up the key by integer index
  2236. iCount = V_I4(pvarKey);
  2237. // We use the CServVarsIterator to manange
  2238. // the count of sv and integer index
  2239. if (!m_pIterator)
  2240. {
  2241. m_pIterator = new CServVarsIterator;
  2242. if (!m_pIterator)
  2243. {
  2244. hrReturn = E_OUTOFMEMORY;
  2245. goto LExit;
  2246. }
  2247. if (FAILED(hrReturn=m_pIterator->Init(m_pRequest->m_pData->m_pIReq)))
  2248. goto LExit;
  2249. }
  2250. // BUG 86117 test passes when m_dwCount == 0
  2251. if ( ((iCount < 1) || (iCount > (int) m_pIterator->m_cKeys)) || ((iCount > 0) && ((int) m_pIterator->m_cKeys == 0)))
  2252. {
  2253. hrReturn = E_FAIL;
  2254. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  2255. goto LExit;
  2256. }
  2257. // Create a BSTR containing the key for this variant
  2258. bstrT = SysAllocString(m_pIterator->m_rgwszKeys[iCount - 1]);
  2259. if (!bstrT)
  2260. {
  2261. hrReturn = E_OUTOFMEMORY;
  2262. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  2263. goto LExit;
  2264. }
  2265. }
  2266. else
  2267. {
  2268. // We were passed in a BSTR. Check to see if there
  2269. // is a server variable for this key
  2270. char szBuffer;
  2271. DWORD dwValSize = sizeof(szBuffer);
  2272. UINT uCodePage = m_pRequest->GetCodePage();
  2273. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey), uCodePage))) {
  2274. if (hrReturn == E_OUTOFMEMORY) {
  2275. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  2276. goto LExit;
  2277. }
  2278. hrReturn = NO_ERROR;
  2279. szKey = "";
  2280. }
  2281. else {
  2282. szKey = CharUpperA(convKey.GetString());
  2283. }
  2284. BOOL fSuccess = m_pRequest->GetIReq()->GetServerVariableA(szKey, &szBuffer, &dwValSize);
  2285. DWORD dwError = 0;
  2286. if (!fSuccess)
  2287. {
  2288. dwError = GetLastError();
  2289. }
  2290. // If the error was that we had insufficient buffer then
  2291. // there is a server variable for that key
  2292. if (fSuccess || dwError == ERROR_INSUFFICIENT_BUFFER)
  2293. {
  2294. bstrT = SysAllocString(V_BSTR(pvarKey));
  2295. if (!bstrT)
  2296. {
  2297. hrReturn = E_OUTOFMEMORY;
  2298. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  2299. goto LExit;
  2300. }
  2301. }
  2302. else if (dwError != ERROR_INVALID_INDEX)
  2303. {
  2304. // Any other error indicates an unexpected failure
  2305. hrReturn = HRESULT_FROM_WIN32(dwError);
  2306. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_UNEXPECTED);
  2307. goto LExit;
  2308. }
  2309. }
  2310. // If we found a key, copy it into the out parmater
  2311. if (bstrT)
  2312. {
  2313. V_BSTR(pVar) = bstrT;
  2314. }
  2315. LExit:
  2316. VariantClear(&varKeyCopy);
  2317. return hrReturn;
  2318. }
  2319. /*===================================================================
  2320. CServerVariables::get_Count
  2321. Parameters:
  2322. pcValues - count is stored in *pcValues
  2323. ===================================================================*/
  2324. STDMETHODIMP CServerVariables::get_Count(int *pcValues)
  2325. {
  2326. if (FAILED(m_pRequest->CheckForTombstone()))
  2327. return E_FAIL;
  2328. HRESULT hrReturn = S_OK;
  2329. // We use the CServVarsIterator to manange
  2330. // the count of sv and integer index
  2331. if (!m_pIterator)
  2332. {
  2333. m_pIterator = new CServVarsIterator;
  2334. if (!m_pIterator)
  2335. {
  2336. *pcValues = 0;
  2337. return E_OUTOFMEMORY;
  2338. }
  2339. if (FAILED(hrReturn=m_pIterator->Init(m_pRequest->m_pData->m_pIReq)))
  2340. return hrReturn;
  2341. }
  2342. *pcValues = m_pIterator->m_cKeys;
  2343. return hrReturn;
  2344. }
  2345. /*===================================================================
  2346. CServerVariables::get__NewEnum
  2347. Return a new enumerator
  2348. ===================================================================*/
  2349. HRESULT CServerVariables::get__NewEnum(IUnknown **ppEnumReturn)
  2350. {
  2351. HRESULT hrReturn;
  2352. if (FAILED(m_pRequest->CheckForTombstone()))
  2353. return E_FAIL;
  2354. *ppEnumReturn = NULL;
  2355. CServVarsIterator *pIterator = new CServVarsIterator;
  2356. if (pIterator == NULL)
  2357. {
  2358. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  2359. return E_OUTOFMEMORY;
  2360. }
  2361. if (FAILED(hrReturn=pIterator->Init(m_pRequest->GetIReq())))
  2362. {
  2363. delete pIterator;
  2364. ExceptionId(IID_IRequestDictionary, IDE_REQUEST,
  2365. ((hrReturn==E_OUTOFMEMORY)? IDE_OOM: IDE_UNEXPECTED) );
  2366. return hrReturn;
  2367. }
  2368. *ppEnumReturn = pIterator;
  2369. return S_OK;
  2370. }
  2371. /*------------------------------------------------------------------
  2372. * C R e q u e s t D a t a
  2373. */
  2374. /*===================================================================
  2375. CRequestData::CRequestData
  2376. Constructor
  2377. Parameters:
  2378. CRequest *pRequest
  2379. Returns:
  2380. Nothing.
  2381. ===================================================================*/
  2382. CRequestData::CRequestData
  2383. (
  2384. CRequest *pRequest
  2385. )
  2386. : m_ISupportErrImp(static_cast<IRequest *>(pRequest), this, IID_IRequest),
  2387. m_QueryString(pRequest, this),
  2388. m_ServerVariables(pRequest, this),
  2389. m_FormInputs(pRequest, this),
  2390. m_Cookies(pRequest, this),
  2391. m_ClCerts(pRequest, this),
  2392. m_cRefs(1)
  2393. {
  2394. m_pIReq = NULL;
  2395. m_pHitObj = NULL;
  2396. m_FormDataStatus = AVAILABLE;
  2397. m_pbAvailableData = NULL;
  2398. m_cbAvailable = 0;
  2399. m_cbTotal = 0;
  2400. m_szFormData = NULL;
  2401. m_cbFormData = 0;
  2402. m_szFormClone = NULL;
  2403. m_szCookie = NULL;
  2404. m_cbCookie = 0;
  2405. m_szClCert = NULL;
  2406. m_cbClCert = 0;
  2407. m_fLoadForm = TRUE;
  2408. m_fLoadQuery = TRUE;
  2409. m_fLoadCookies = TRUE;
  2410. m_fLoadClCerts = TRUE;
  2411. m_pEmptyString = NULL;
  2412. }
  2413. /*===================================================================
  2414. CRequestData::~CRequestData
  2415. Destructor
  2416. Parameters:
  2417. Returns:
  2418. Nothing.
  2419. ===================================================================*/
  2420. CRequestData::~CRequestData()
  2421. {
  2422. CRequestHit *pNukeElem = static_cast<CRequestHit *>
  2423. (
  2424. m_mpszStrings.Head()
  2425. );
  2426. while (pNukeElem != NULL) {
  2427. CRequestHit *pNext = static_cast<CRequestHit *>(pNukeElem->m_pNext);
  2428. delete pNukeElem;
  2429. pNukeElem = pNext;
  2430. }
  2431. m_mpszStrings.UnInit();
  2432. if (m_pEmptyString)
  2433. m_pEmptyString->Release();
  2434. if (m_szFormData)
  2435. free(m_szFormData);
  2436. if (m_szFormClone)
  2437. free(m_szFormClone);
  2438. if (m_szCookie)
  2439. free(m_szCookie);
  2440. if (m_szClCert)
  2441. free(m_szClCert);
  2442. }
  2443. /*===================================================================
  2444. CRequestData::Init
  2445. Init
  2446. Parameters:
  2447. Returns:
  2448. Nothing.
  2449. ===================================================================*/
  2450. HRESULT CRequestData::Init()
  2451. {
  2452. HRESULT hr = S_OK;
  2453. if (SUCCEEDED(hr))
  2454. hr = m_mpszStrings.Init();
  2455. if (SUCCEEDED(hr))
  2456. hr = m_QueryString.Init();
  2457. if (SUCCEEDED(hr))
  2458. hr = m_FormInputs.Init();
  2459. if (SUCCEEDED(hr))
  2460. hr = m_Cookies.Init();
  2461. if (SUCCEEDED(hr))
  2462. hr = m_ClCerts.Init();
  2463. if (SUCCEEDED(hr))
  2464. hr = m_ServerVariables.Init();
  2465. return hr;
  2466. }
  2467. /*===================================================================
  2468. CRequestData::ReInit
  2469. ReInit -- associate with new CIsapiReqInfo and HitObj
  2470. Parameters:
  2471. Returns:
  2472. Nothing.
  2473. ===================================================================*/
  2474. HRESULT CRequestData::ReInit
  2475. (
  2476. CIsapiReqInfo *pIReq,
  2477. CHitObj *pHitObj
  2478. )
  2479. {
  2480. CRequestHit *pNukeElem = static_cast<CRequestHit *>
  2481. (
  2482. m_mpszStrings.Head()
  2483. );
  2484. while (pNukeElem != NULL)
  2485. {
  2486. CRequestHit *pNext = static_cast<CRequestHit *>
  2487. (
  2488. pNukeElem->m_pNext
  2489. );
  2490. delete pNukeElem;
  2491. pNukeElem = pNext;
  2492. }
  2493. m_mpszStrings.ReInit();
  2494. m_QueryString.ReInit();
  2495. m_FormInputs.ReInit();
  2496. m_Cookies.ReInit();
  2497. m_ClCerts.ReInit();
  2498. m_pIReq = pIReq;
  2499. m_pHitObj = pHitObj;
  2500. m_fLoadForm = TRUE;
  2501. m_fLoadQuery = TRUE;
  2502. m_fLoadCookies = TRUE;
  2503. m_fLoadClCerts = TRUE;
  2504. m_FormDataStatus = AVAILABLE;
  2505. if (pIReq)
  2506. {
  2507. m_pbAvailableData = pIReq->QueryPbData();
  2508. m_cbAvailable = pIReq->QueryCbAvailable();
  2509. m_cbTotal = pIReq->QueryCbTotalBytes();
  2510. }
  2511. else
  2512. {
  2513. m_pbAvailableData = NULL;
  2514. m_cbAvailable = 0;
  2515. m_cbTotal = 0;
  2516. }
  2517. if (m_szFormData)
  2518. {
  2519. m_szFormData[0] = '\0';
  2520. m_szFormClone[0] = '\0';
  2521. }
  2522. if (m_szCookie)
  2523. m_szCookie[0] = '\0';
  2524. if (m_szClCert)
  2525. m_szClCert[0] = '\0';
  2526. return S_OK;
  2527. }
  2528. /*===================================================================
  2529. CRequestData::GetEmptyStringList
  2530. Get empty string list's IDispatch *
  2531. Create empty string list on demand
  2532. ===================================================================*/
  2533. HRESULT CRequestData::GetEmptyStringList
  2534. (
  2535. IDispatch **ppdisp
  2536. )
  2537. {
  2538. if (!m_pEmptyString)
  2539. {
  2540. m_pEmptyString = new CStringList;
  2541. if (!m_pEmptyString)
  2542. {
  2543. *ppdisp = NULL;
  2544. return E_FAIL;
  2545. }
  2546. }
  2547. return m_pEmptyString->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(ppdisp));
  2548. }
  2549. /*===================================================================
  2550. CRequestData::QueryInterface
  2551. CRequestData::AddRef
  2552. CRequestData::Release
  2553. IUnknown members for CRequestData object.
  2554. ===================================================================*/
  2555. STDMETHODIMP CRequestData::QueryInterface
  2556. (
  2557. REFIID iid,
  2558. void **ppvObj
  2559. )
  2560. {
  2561. if (iid == IID_IUnknown)
  2562. {
  2563. *ppvObj = this;
  2564. AddRef();
  2565. return S_OK;
  2566. }
  2567. else
  2568. {
  2569. *ppvObj = NULL;
  2570. return E_NOINTERFACE;
  2571. }
  2572. }
  2573. STDMETHODIMP_(ULONG) CRequestData::AddRef()
  2574. {
  2575. return ++m_cRefs;
  2576. }
  2577. STDMETHODIMP_(ULONG) CRequestData::Release(void)
  2578. {
  2579. if (--m_cRefs)
  2580. return m_cRefs;
  2581. delete this;
  2582. return 0;
  2583. }
  2584. /*------------------------------------------------------------------
  2585. * C R e q u e s t
  2586. */
  2587. /*===================================================================
  2588. CRequest::CRequest
  2589. Constructor
  2590. Parameters:
  2591. punkOuter object to ref count (can be NULL)
  2592. ===================================================================*/
  2593. CRequest::CRequest(IUnknown *punkOuter)
  2594. :
  2595. m_fInited(FALSE),
  2596. m_fDiagnostics(FALSE),
  2597. m_pData(NULL)
  2598. {
  2599. CDispatch::Init(IID_IRequest);
  2600. if (punkOuter)
  2601. {
  2602. m_punkOuter = punkOuter;
  2603. m_fOuterUnknown = TRUE;
  2604. }
  2605. else
  2606. {
  2607. m_cRefs = 1;
  2608. m_fOuterUnknown = FALSE;
  2609. }
  2610. #ifdef DBG
  2611. m_fDiagnostics = TRUE;
  2612. #endif // DBG
  2613. }
  2614. /*===================================================================
  2615. CRequest::~CRequest
  2616. Destructor
  2617. Parameters:
  2618. None
  2619. Returns:
  2620. Nothing.
  2621. ===================================================================*/
  2622. CRequest::~CRequest()
  2623. {
  2624. Assert(!m_fInited);
  2625. Assert(m_fOuterUnknown || m_cRefs == 0); // must have 0 ref count
  2626. }
  2627. /*===================================================================
  2628. CRequest::CleanUp
  2629. Deallocates members and removes m_pData
  2630. Parameters:
  2631. None
  2632. Returns:
  2633. HRESULT (S_OK)
  2634. ===================================================================*/
  2635. HRESULT CRequest::CleanUp()
  2636. {
  2637. if (m_pData)
  2638. {
  2639. m_pData->Release();
  2640. m_pData = NULL;
  2641. }
  2642. return S_OK;
  2643. }
  2644. /*===================================================================
  2645. CRequest::Init
  2646. Allocates m_pData.
  2647. Performs any intiailization of a CRequest that's prone to failure
  2648. that we also use internally before exposing the object outside.
  2649. Parameters:
  2650. None
  2651. Returns:
  2652. S_OK on success.
  2653. ===================================================================*/
  2654. HRESULT CRequest::Init()
  2655. {
  2656. if (m_fInited)
  2657. return S_OK; // already inited
  2658. Assert(!m_pData);
  2659. m_pData = new CRequestData(this);
  2660. if (!m_pData)
  2661. return E_OUTOFMEMORY;
  2662. HRESULT hr = m_pData->Init();
  2663. if (SUCCEEDED(hr))
  2664. m_fInited = TRUE;
  2665. else
  2666. CleanUp();
  2667. return hr;
  2668. }
  2669. /*===================================================================
  2670. CRequest::UnInit
  2671. Remove m_pData. Back to UnInited state
  2672. Parameters:
  2673. None
  2674. Returns:
  2675. HRESULT
  2676. ===================================================================*/
  2677. HRESULT CRequest::UnInit()
  2678. {
  2679. if (!m_fInited)
  2680. return S_OK; // already uninited
  2681. Assert(m_pData);
  2682. CleanUp();
  2683. Assert(!m_pData);
  2684. m_fInited = FALSE;
  2685. return S_OK;
  2686. }
  2687. /*===================================================================
  2688. Request::ReInit
  2689. Each Request we service will have a new CIsapiReqInfo.
  2690. This function is used to set the value of the CIsapiReqInfo.
  2691. Parameters:
  2692. CIsapiReqInfo *pIReq CIsapiReqInfo
  2693. CHitObj *pHitObj HitObj
  2694. Returns:
  2695. HRESULT
  2696. ===================================================================*/
  2697. HRESULT CRequest::ReInit
  2698. (
  2699. CIsapiReqInfo *pIReq,
  2700. CHitObj *pHitObj
  2701. )
  2702. {
  2703. Assert(m_fInited);
  2704. Assert(m_pData);
  2705. return m_pData->ReInit(pIReq, pHitObj);
  2706. }
  2707. /*===================================================================
  2708. CRequest::GetCodePage
  2709. GetCodePage from current HitObj
  2710. Parameters:
  2711. Returns:
  2712. CodePage
  2713. ===================================================================*/
  2714. UINT CRequest::GetCodePage()
  2715. {
  2716. Assert(m_fInited);
  2717. Assert(m_pData);
  2718. Assert(m_pData->m_pHitObj);
  2719. return m_pData->m_pHitObj->GetCodePage();
  2720. }
  2721. /*===================================================================
  2722. CRequest::LoadCookies
  2723. Load the Request map with values from the HTTP_COOKIE variable.
  2724. Parameters:
  2725. bstrVar BSTR, which parameter to get the value of
  2726. pbstrRet BSTR FAR *, return value of the requested parameter
  2727. Returns:
  2728. S_OK on success. E_FAIL on failure.
  2729. Bugs:
  2730. This code assumes that dictionary cookies are well-formed.
  2731. If they are not, then the results will be unpredictable.
  2732. The dictionary cookies are gauranteed to be well-formed if
  2733. Response.Cookies is used. If other means, such as a direct
  2734. use of the <META> tag, or if Response.SetCookie is used, we
  2735. are at the mercy of the script writer.
  2736. ===================================================================*/
  2737. HRESULT CRequest::LoadCookies(char *szData)
  2738. {
  2739. if (FAILED(CheckForTombstone()))
  2740. return E_FAIL;
  2741. HRESULT hResult;
  2742. if (szData == NULL)
  2743. return S_OK;
  2744. // Each cookie definition is moved to a buffer so that we don't
  2745. // overwrite the value of HTTP_COOKIE. We can save a strcpy()
  2746. // call since 'DecodeFromURL' can copy for us.
  2747. //
  2748. size_t cbCookie = strlen(szData) + 1;
  2749. if (m_pData->m_cbCookie == 0)
  2750. m_pData->m_szCookie = static_cast<char *>(malloc(m_pData->m_cbCookie = cbCookie));
  2751. else if (cbCookie > m_pData->m_cbCookie)
  2752. m_pData->m_szCookie = static_cast<char *>(realloc(m_pData->m_szCookie, m_pData->m_cbCookie = cbCookie));
  2753. if (m_pData->m_szCookie == NULL)
  2754. return E_OUTOFMEMORY;
  2755. char *szDest = m_pData->m_szCookie;
  2756. char chDelimiter; // delimiter that we found to stop the scan
  2757. while (*szData != '\0')
  2758. {
  2759. char *szName, *szPartialValue;
  2760. // Get the cookie name
  2761. chDelimiter = DecodeFromURL(&szData, ";=", szName = szDest, GetCodePage(), FALSE);
  2762. szDest = strchr(szDest, '\0') + 1;
  2763. if (chDelimiter == '=')
  2764. {
  2765. // if DecodeFromURL stop scanning because of an equal sign, then the browser sent
  2766. // a value for this cookie
  2767. // Get the cookie's value
  2768. chDelimiter = DecodeFromURL(&szData, ";=", szPartialValue = szDest, GetCodePage(), FALSE);
  2769. szDest = strchr(szDest, '\0') + 1;
  2770. // discard the denali session ID
  2771. if (strncmp(szName, SZ_SESSION_ID_COOKIE_PREFIX, CCH_SESSION_ID_COOKIE_PREFIX) == 0)
  2772. {
  2773. // DENALISESSIONID better not have non-alphabetics in it! expecting
  2774. // termination with ';' or NUL.
  2775. //
  2776. continue;
  2777. }
  2778. }
  2779. else if (*szName == '\0')
  2780. {
  2781. continue;
  2782. }
  2783. else
  2784. {
  2785. // either we hit a ';' char or end of string. In either case, this indicates that
  2786. // the cookie has no value. Set the szPartialValue to an empty string and set the
  2787. // delimiter to ';' to trick the remainder of this function into thinking that the
  2788. // cookie does have a value and that is a simple value (i.e. no sub-cookies).
  2789. chDelimiter = ';';
  2790. szPartialValue = "";
  2791. }
  2792. // Add this cookie to the Request
  2793. CRequestHit *pRequestHit = static_cast<CRequestHit *>(GetStrings()->FindElem(szName, strlen(szName)));
  2794. if (pRequestHit == NULL)
  2795. {
  2796. pRequestHit = new CRequestHit;
  2797. if (pRequestHit == NULL)
  2798. return E_OUTOFMEMORY;
  2799. if (FAILED(pRequestHit->Init(szName))) {
  2800. delete pRequestHit;
  2801. return E_FAIL;
  2802. }
  2803. GetStrings()->AddElem(pRequestHit);
  2804. // This is a new request hit, add it to the array of request hits
  2805. if (!m_pData->m_Cookies.AddRequestHit(pRequestHit))
  2806. {
  2807. return E_OUTOFMEMORY;
  2808. }
  2809. }
  2810. else if (pRequestHit->m_pCookieData) // a cookie by this name already exists
  2811. {
  2812. if (chDelimiter == '=') // eat the rest of this cookie
  2813. DecodeFromURL(&szData, ";", szDest, GetCodePage()); // no need to advance szDest
  2814. continue; // discard later cookies
  2815. }
  2816. // The cookie value may be in the form <key1=value1&key2=value2...>
  2817. // or not. If there is an '=' sign present, that lets us know if it
  2818. // is a cookie dictionary or a simple value.
  2819. //
  2820. // We assume that '=' signs that are part of the cookie are escaped in hex.
  2821. //
  2822. if (chDelimiter != '=')
  2823. {
  2824. if (FAILED(hResult = pRequestHit->AddValue(COOKIE, szPartialValue, m_pData->m_pIReq, GetCodePage())))
  2825. return hResult;
  2826. }
  2827. else
  2828. {
  2829. char *szKey = szPartialValue; // already got the key
  2830. for (;;)
  2831. {
  2832. char *szValue;
  2833. chDelimiter = DecodeFromURL(&szData, ";&", szValue = szDest, GetCodePage(), FALSE);
  2834. szDest = strchr(szDest, '\0') + 1;
  2835. if (FAILED(hResult = pRequestHit->AddKeyAndValue(COOKIE, szKey, szValue, m_pData->m_pIReq, GetCodePage())))
  2836. return hResult;
  2837. if (chDelimiter == ';' || chDelimiter == '\0')
  2838. break;
  2839. // get the key, exit when NUL terminator found
  2840. chDelimiter = DecodeFromURL(&szData, "=;", szKey = szDest, GetCodePage(), FALSE);
  2841. if (chDelimiter == ';' || chDelimiter == '\0')
  2842. break;
  2843. szDest = strchr(szDest, '\0') + 1;
  2844. }
  2845. }
  2846. }
  2847. return S_OK;
  2848. }
  2849. #define CB_CERT_DEFAULT 4096
  2850. /*===================================================================
  2851. CRequest::LoadClCerts
  2852. Load the Request map with values from the CIsapiReqInfo
  2853. Parameters:
  2854. szData - ptr to CIsapiReqInfo
  2855. Returns:
  2856. S_OK on success. E_FAIL on failure.
  2857. ===================================================================*/
  2858. HRESULT CRequest::LoadClCerts(char *szData, UINT lCodePage)
  2859. {
  2860. HRESULT hres = S_OK;
  2861. CERT_CONTEXT_EX CertContextEx;
  2862. CCertRequest CertReq( this );
  2863. STACK_BUFFER( tempCert, CB_CERT_DEFAULT );
  2864. ZeroMemory( &CertContextEx, sizeof(CERT_CONTEXT_EX) );
  2865. if (FAILED(CheckForTombstone()))
  2866. return E_FAIL;
  2867. CIsapiReqInfo *pIReq = reinterpret_cast<CIsapiReqInfo *>(szData);
  2868. // allocate certificate buffer
  2869. CertContextEx.cbAllocated = tempCert.QuerySize();
  2870. CertContextEx.CertContext.pbCertEncoded = static_cast<BYTE *>(tempCert.QueryPtr());
  2871. // get certificate info from web server
  2872. if ( !pIReq->ServerSupportFunction( HSE_REQ_GET_CERT_INFO_EX,
  2873. &CertContextEx,
  2874. NULL,
  2875. NULL ) )
  2876. {
  2877. DWORD dwErr = GetLastError();
  2878. if ( dwErr == ERROR_INSUFFICIENT_BUFFER )
  2879. {
  2880. // buffer was too small - realloc and call again
  2881. Assert( CertContextEx.cbAllocated < CertContextEx.CertContext.cbCertEncoded );
  2882. CertContextEx.cbAllocated = CertContextEx.CertContext.cbCertEncoded;
  2883. // If CB_CERT_DEFAULT wasn't enough, we want to allocate from the heap, rather then the stack
  2884. if (tempCert.Resize(CertContextEx.cbAllocated) == FALSE) {
  2885. hres = E_OUTOFMEMORY;
  2886. goto LExit;
  2887. }
  2888. CertContextEx.CertContext.pbCertEncoded = static_cast<BYTE *>(tempCert.QueryPtr());
  2889. if ( !pIReq->ServerSupportFunction(
  2890. HSE_REQ_GET_CERT_INFO_EX,
  2891. &CertContextEx,
  2892. NULL,
  2893. NULL ) )
  2894. {
  2895. // if we fail a second time, just bail
  2896. // NOTE this should never happen?
  2897. dwErr = GetLastError();
  2898. Assert(dwErr != ERROR_INSUFFICIENT_BUFFER);
  2899. hres = HRESULT_FROM_WIN32(dwErr);
  2900. goto LExit;
  2901. }
  2902. }
  2903. else if ( dwErr == ERROR_INVALID_PARAMETER )
  2904. {
  2905. // not supported (old IIS)
  2906. hres = S_OK;
  2907. goto LExit;
  2908. }
  2909. else
  2910. {
  2911. hres = HRESULT_FROM_WIN32(dwErr);
  2912. goto LExit;
  2913. }
  2914. }
  2915. if(CertContextEx.CertContext.cbCertEncoded == 0)
  2916. {
  2917. hres = CertReq.NoCertificate();
  2918. }
  2919. else
  2920. {
  2921. hres = CertReq.ParseCertificate( CertContextEx.CertContext.pbCertEncoded,
  2922. CertContextEx.CertContext.cbCertEncoded,
  2923. CertContextEx.CertContext.dwCertEncodingType,
  2924. CertContextEx.dwCertificateFlags,
  2925. lCodePage );
  2926. }
  2927. LExit:
  2928. return hres;
  2929. }
  2930. /*===================================================================
  2931. CRequest::LoadVariables
  2932. Load the Request map with values from a URL encoded string
  2933. WARNING: This function modifies the passed szData!!
  2934. Note: this is part of bug 682, but we are not going to fix it for
  2935. performance reasons. Just be aware that this function
  2936. screws up the passed in string.
  2937. Parameters:
  2938. bstrVar BSTR, which parameter to get the value of
  2939. pbstrRet BSTR FAR *, return value of the requested parameter
  2940. lCodePage UINT, the codepage used in retrieving the data
  2941. Returns:
  2942. S_OK on success. E_FAIL on failure.
  2943. ===================================================================*/
  2944. HRESULT CRequest::LoadVariables(CollectionType Source, char *szData, UINT lCodePage)
  2945. {
  2946. if (FAILED(CheckForTombstone()))
  2947. return E_FAIL;
  2948. HRESULT hResult;
  2949. if (Source == COOKIE) // cookies are a special case
  2950. return LoadCookies(szData); // handle them specially
  2951. if (Source == CLCERT) // clcerts are a special case
  2952. return LoadClCerts(szData, lCodePage); // handle them specially
  2953. if (szData == NULL) // treat NULL as "no data available"
  2954. return S_OK;
  2955. while (*szData != '\0')
  2956. {
  2957. char *szName, *szValue;
  2958. DecodeFromURL(&szData, "=", szName = szData, lCodePage, FALSE);
  2959. DecodeFromURL(&szData, "&", szValue = szData, lCodePage, FALSE);
  2960. // this is to handle the case where an un-named pair was passed.
  2961. // skip it and process the next named pair
  2962. //
  2963. if(*szName == '\0')
  2964. continue;
  2965. CRequestHit *pRequestHit = static_cast<CRequestHit *>
  2966. (
  2967. GetStrings()->FindElem(szName, strlen(szName))
  2968. );
  2969. if (pRequestHit == NULL)
  2970. {
  2971. pRequestHit = new CRequestHit;
  2972. if (pRequestHit == NULL)
  2973. return E_OUTOFMEMORY;
  2974. if (FAILED(pRequestHit->Init(szName))) {
  2975. delete pRequestHit;
  2976. return E_FAIL;
  2977. }
  2978. GetStrings()->AddElem(pRequestHit);
  2979. // This is a new request hit, so we should add it
  2980. // to the array of request
  2981. if (Source == QUERYSTRING)
  2982. {
  2983. if (!m_pData->m_QueryString.AddRequestHit(pRequestHit))
  2984. {
  2985. return E_FAIL;
  2986. }
  2987. }
  2988. else if (Source == FORM)
  2989. {
  2990. if (!m_pData->m_FormInputs.AddRequestHit(pRequestHit))
  2991. {
  2992. return E_FAIL;
  2993. }
  2994. }
  2995. }
  2996. if (FAILED(hResult = pRequestHit->AddValue(Source, szValue, m_pData->m_pIReq, lCodePage)))
  2997. return hResult;
  2998. }
  2999. return S_OK;
  3000. }
  3001. /*===================================================================
  3002. CRequest::QueryInterface
  3003. CRequest::AddRef
  3004. CRequest::Release
  3005. IUnknown members for CRequest object.
  3006. ===================================================================*/
  3007. STDMETHODIMP CRequest::QueryInterface(REFIID iid, void **ppvObj)
  3008. {
  3009. *ppvObj = NULL;
  3010. // BUG FIX 683 added IID_IDenaliIntrinsic to prevent the user from
  3011. // storing intrinsic objects in the application and session object
  3012. if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_IRequest || iid == IID_IDenaliIntrinsic)
  3013. *ppvObj = static_cast<IRequest *>(this);
  3014. else if (iid == IID_ISupportErrorInfo)
  3015. {
  3016. if (m_pData)
  3017. *ppvObj = &(m_pData->m_ISupportErrImp);
  3018. }
  3019. // Support IStream for ADO/XML
  3020. else if (iid == IID_IStream )
  3021. {
  3022. *ppvObj = static_cast<IStream *>(this);
  3023. }
  3024. else if (IID_IMarshal == iid)
  3025. {
  3026. *ppvObj = static_cast<IMarshal *>(this);
  3027. }
  3028. if (*ppvObj != NULL)
  3029. {
  3030. static_cast<IUnknown *>(*ppvObj)->AddRef();
  3031. return S_OK;
  3032. }
  3033. return E_NOINTERFACE;
  3034. }
  3035. STDMETHODIMP_(ULONG) CRequest::AddRef(void)
  3036. {
  3037. if (m_fOuterUnknown)
  3038. return m_punkOuter->AddRef();
  3039. return InterlockedIncrement((LPLONG)&m_cRefs);
  3040. }
  3041. STDMETHODIMP_(ULONG) CRequest::Release(void)
  3042. {
  3043. if (m_fOuterUnknown)
  3044. return m_punkOuter->Release();
  3045. DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs);
  3046. if (cRefs)
  3047. return cRefs;
  3048. delete this;
  3049. return 0;
  3050. }
  3051. /*===================================================================
  3052. CRequest::CheckForTombstone
  3053. Tombstone stub for IRequest methods. If the object is
  3054. tombstone, does ExceptionId and fails.
  3055. Parameters:
  3056. Returns:
  3057. HRESULT E_FAIL if Tombstone
  3058. S_OK if not
  3059. ===================================================================*/
  3060. HRESULT CRequest::CheckForTombstone()
  3061. {
  3062. if (m_fInited)
  3063. {
  3064. // inited - good object
  3065. Assert(m_pData); // must be present for inited objects
  3066. return S_OK;
  3067. }
  3068. ExceptionId
  3069. (
  3070. IID_IRequest,
  3071. IDE_REQUEST,
  3072. IDE_INTRINSIC_OUT_OF_SCOPE
  3073. );
  3074. return E_FAIL;
  3075. }
  3076. /*===================================================================
  3077. CRequest::get_QueryString
  3078. Return the QueryString dictionary
  3079. ===================================================================*/
  3080. HRESULT CRequest::get_QueryString(IRequestDictionary **ppDictReturn)
  3081. {
  3082. if (FAILED(CheckForTombstone()))
  3083. return E_FAIL;
  3084. return m_pData->m_QueryString.QueryInterface(IID_IRequestDictionary, reinterpret_cast<void **>(ppDictReturn));
  3085. }
  3086. /*===================================================================
  3087. CRequest::get_Form
  3088. Return the Form dictionary
  3089. ===================================================================*/
  3090. HRESULT CRequest::get_Form(IRequestDictionary **ppDictReturn)
  3091. {
  3092. if (FAILED(CheckForTombstone()))
  3093. return E_FAIL;
  3094. return m_pData->m_FormInputs.QueryInterface(IID_IRequestDictionary, reinterpret_cast<void **>(ppDictReturn));
  3095. }
  3096. /*===================================================================
  3097. CRequest::get_Body
  3098. Return the Body dictionary (alias for Form dictionary)
  3099. ===================================================================*/
  3100. HRESULT CRequest::get_Body(IRequestDictionary **ppDictReturn)
  3101. {
  3102. if (FAILED(CheckForTombstone()))
  3103. return E_FAIL;
  3104. return m_pData->m_FormInputs.QueryInterface(IID_IRequestDictionary, reinterpret_cast<void **>(ppDictReturn));
  3105. }
  3106. /*===================================================================
  3107. CRequest::get_Cookies
  3108. Return the Cookies dictionary
  3109. ===================================================================*/
  3110. HRESULT CRequest::get_Cookies(IRequestDictionary **ppDictReturn)
  3111. {
  3112. if (FAILED(CheckForTombstone()))
  3113. return E_FAIL;
  3114. return m_pData->m_Cookies.QueryInterface(IID_IRequestDictionary, reinterpret_cast<void **>(ppDictReturn));
  3115. }
  3116. /*===================================================================
  3117. CRequest::get_ClientCertificate
  3118. Return the ClCerts dictionary
  3119. ===================================================================*/
  3120. HRESULT CRequest::get_ClientCertificate(IRequestDictionary **ppDictReturn)
  3121. {
  3122. if (FAILED(CheckForTombstone()))
  3123. return E_FAIL;
  3124. return m_pData->m_ClCerts.QueryInterface(IID_IRequestDictionary, reinterpret_cast<void **>(ppDictReturn));
  3125. }
  3126. /*===================================================================
  3127. CRequest::get_ServerVariables
  3128. Return the Form dictionary
  3129. ===================================================================*/
  3130. HRESULT CRequest::get_ServerVariables(IRequestDictionary **ppDictReturn)
  3131. {
  3132. if (FAILED(CheckForTombstone()))
  3133. return E_FAIL;
  3134. return m_pData->m_ServerVariables.QueryInterface(IID_IRequestDictionary, reinterpret_cast<void **>(ppDictReturn));
  3135. }
  3136. /*===================================================================
  3137. CRequest::get_Item
  3138. Function called from DispInvoke to get values from any one of four
  3139. collections. Search order is "ServerVariables", "QueryString",
  3140. "Form", "Cookies", "ClientCertificate"
  3141. Parameters:
  3142. bstrVar BSTR, which parameter to get the value of
  3143. pVarReturn VARIANT *, return value of the requested parameter
  3144. Returns:
  3145. S_OK on success. E_FAIL on failure.
  3146. ===================================================================*/
  3147. HRESULT CRequest::get_Item(BSTR bstrName, IDispatch **ppDispReturn)
  3148. {
  3149. if (FAILED(CheckForTombstone()))
  3150. return E_FAIL;
  3151. if (bstrName == NULL)
  3152. {
  3153. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
  3154. return E_FAIL;
  3155. }
  3156. UINT lCodePage = CP_ACP;
  3157. CWCharToMBCS convName;
  3158. char *szName;
  3159. // If BinaryRead has been called, the Form collection is no longer available
  3160. // so we insist that the script writer specify which collection to use
  3161. if (m_pData->m_FormDataStatus != AVAILABLE &&
  3162. m_pData->m_FormDataStatus != FORMCOLLECTIONONLY)
  3163. {
  3164. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_REQUEST_GENERICCOLLECTION_NA);
  3165. return E_FAIL;
  3166. }
  3167. // At this point, we are forced to load the QueryString, Form, Cookies
  3168. // and ClientCertificate
  3169. // collections even though it will only come from one of these.
  3170. //
  3171. if (m_pData->m_fLoadQuery)
  3172. {
  3173. // QueryString can contains DBCS string
  3174. lCodePage = GetCodePage();
  3175. if (FAILED(LoadVariables(QUERYSTRING, GetIReq()->QueryPszQueryString(), lCodePage)))
  3176. return E_FAIL;
  3177. m_pData->m_fLoadQuery = FALSE;
  3178. }
  3179. if (m_pData->m_fLoadCookies)
  3180. {
  3181. char *szCookie = GetIReq()->QueryPszCookie();
  3182. if (FAILED(LoadVariables(COOKIE, szCookie, lCodePage)))
  3183. return E_FAIL;
  3184. m_pData->m_fLoadCookies = FALSE;
  3185. }
  3186. if (m_pData->m_fLoadClCerts)
  3187. {
  3188. lCodePage = GetCodePage();
  3189. if (FAILED(LoadVariables(CLCERT, (char*)GetIReq(), lCodePage)))
  3190. return E_FAIL;
  3191. m_pData->m_fLoadClCerts = FALSE;
  3192. }
  3193. if (m_pData->m_fLoadForm)
  3194. {
  3195. HRESULT hrGetData = CopyClientData();
  3196. if (FAILED(hrGetData))
  3197. return hrGetData;
  3198. // Form can contain DBCS string
  3199. lCodePage = GetCodePage();
  3200. if (FAILED(LoadVariables(FORM, m_pData->m_szFormData, lCodePage)))
  3201. return E_FAIL;
  3202. m_pData->m_fLoadForm = FALSE;
  3203. }
  3204. // Convert name to ANSI
  3205. //
  3206. HRESULT hr;
  3207. if (FAILED(hr = convName.Init(bstrName, lCodePage))) {
  3208. if (hr == E_OUTOFMEMORY) {
  3209. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  3210. return hr;
  3211. }
  3212. hr = NO_ERROR;
  3213. szName = "";
  3214. }
  3215. else {
  3216. szName = convName.GetString();
  3217. }
  3218. // Look up the name in the collections
  3219. //
  3220. CRequestHit *pRequestHit = static_cast<CRequestHit *>(GetStrings()->FindElem(szName, strlen(szName)));
  3221. if (pRequestHit)
  3222. {
  3223. IUnknown *pValues = NULL;
  3224. if (pRequestHit->m_pQueryData)
  3225. pValues = pRequestHit->m_pQueryData;
  3226. else if (pRequestHit->m_pFormData)
  3227. pValues = pRequestHit->m_pFormData;
  3228. else if (pRequestHit->m_pCookieData)
  3229. pValues = pRequestHit->m_pCookieData;
  3230. else if (pRequestHit->m_pClCertData)
  3231. pValues = pRequestHit->m_pClCertData;
  3232. if (pValues == NULL)
  3233. goto NotFound;
  3234. if (FAILED(pValues->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(ppDispReturn))))
  3235. return E_FAIL;
  3236. return S_OK;
  3237. }
  3238. NotFound:
  3239. // Look in server variables
  3240. VARIANT varKey, varValue;
  3241. V_VT(&varKey) = VT_BSTR;
  3242. V_BSTR(&varKey) = bstrName;
  3243. if (m_pData->m_ServerVariables.get_Item(varKey, &varValue) == S_OK)
  3244. {
  3245. Assert (V_VT(&varValue) == VT_DISPATCH);
  3246. *ppDispReturn = V_DISPATCH(&varValue);
  3247. return S_OK;
  3248. }
  3249. if (FAILED(m_pData->GetEmptyStringList(ppDispReturn)))
  3250. return E_FAIL;
  3251. return S_OK;
  3252. }
  3253. /*===================================================================
  3254. CRequest::CopyClientData
  3255. Load the form data (stdin) by using either ReadClient or the
  3256. ISAPI buffer
  3257. ===================================================================*/
  3258. HRESULT CRequest::CopyClientData()
  3259. {
  3260. HRESULT hr = S_OK;
  3261. if (FAILED(CheckForTombstone()))
  3262. return E_FAIL;
  3263. STACK_BUFFER(tempContent, 1024 );
  3264. CIsapiReqInfo *pIReq = m_pData->m_pIReq;
  3265. // assert that the data is in the format we want
  3266. //
  3267. // we need to scan the content type for the supported header,
  3268. // the client my send multiple headers so use strstr to search
  3269. // the header string this is a HOT_FIX for NT BUG:208530
  3270. //
  3271. if (pIReq->QueryPszContentType())
  3272. {
  3273. size_t cbQueryPszContentType = (strlen(pIReq->QueryPszContentType()) + 1);
  3274. if (cbQueryPszContentType > REQUEST_ALLOC_MAX)
  3275. {
  3276. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_STACK_OVERFLOW);
  3277. return E_FAIL;
  3278. }
  3279. if (tempContent.Resize(cbQueryPszContentType) == FALSE)
  3280. {
  3281. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  3282. return E_FAIL;
  3283. }
  3284. CHAR *szQueryPszContentType = _strlwr(
  3285. strcpy(
  3286. static_cast<char *>(tempContent.QueryPtr()),
  3287. pIReq->QueryPszContentType()
  3288. ));
  3289. if (strstr(szQueryPszContentType, "application/x-www-form-urlencoded") == NULL)
  3290. return S_OK;
  3291. }
  3292. else
  3293. return S_OK;
  3294. //
  3295. // Determine if it is chunked or not.
  3296. //
  3297. DWORD dwVarSize = 0;
  3298. STACK_BUFFER( varBuff, 128 );
  3299. if (SERVER_GET(pIReq, "HTTP_TRANSFER_ENCODING", &varBuff, &dwVarSize) &&
  3300. (!stricmp(static_cast<char *>(varBuff.QueryPtr()),"chunked")))
  3301. hr = CopyChunkedClientData();
  3302. else
  3303. hr = CopyNonChunkedClientData();
  3304. // Clone the data (LoadVariables will destroy the data)
  3305. // Allocate memory for clone. It should theoritically be equal to the size of FormData.
  3306. if (SUCCEEDED (hr))
  3307. {
  3308. m_pData->m_szFormClone = static_cast<char *>(malloc(m_pData->m_cbFormData));
  3309. if (m_pData->m_szFormClone == NULL)
  3310. return E_OUTOFMEMORY;
  3311. // Actually perform the copy of data.
  3312. strcpy(m_pData->m_szFormClone, m_pData->m_szFormData);
  3313. }
  3314. return hr;
  3315. }
  3316. /*===================================================================
  3317. CRequest::CopyChunkedClientData
  3318. Load the form data (stdin) by using either ReadClient or the
  3319. ISAPI buffer. This case is called when Data is being sent in a chunks.
  3320. ===================================================================*/
  3321. HRESULT CRequest::CopyChunkedClientData ()
  3322. {
  3323. CIsapiReqInfo *pIReq = m_pData->m_pIReq;
  3324. // Try to initially allocate units 4K,16K,32K....
  3325. // For the current implementation we shall stop at 32K
  3326. // Which will bring us to an allocation of (48) +4+8+16+32 +32 +32 + .....
  3327. //
  3328. DWORD allocUnit = 4096; // 0001 0000 0000 0000 B
  3329. DWORD cbFormData = (pIReq->QueryCbAvailable() + 1);
  3330. // WinSE 26645: check for interger overflow after every add
  3331. //
  3332. if (cbFormData < 1)
  3333. {
  3334. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_NOT_ALLOWED);
  3335. return E_FAIL;
  3336. }
  3337. // Alloc the 4K extra memory.
  3338. cbFormData += allocUnit;
  3339. if (cbFormData < allocUnit)
  3340. {
  3341. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_NOT_ALLOWED);
  3342. return E_FAIL;
  3343. }
  3344. if (m_pData->m_cbFormData == 0)
  3345. m_pData->m_szFormData = static_cast<char *>(malloc(m_pData->m_cbFormData = cbFormData)); // space for data & its clone
  3346. else if (cbFormData > m_pData->m_cbFormData)
  3347. m_pData->m_szFormData = static_cast<char *>(realloc(m_pData->m_szFormData, m_pData->m_cbFormData = cbFormData));
  3348. if (m_pData->m_szFormData == NULL)
  3349. return E_OUTOFMEMORY;
  3350. char * pszOffset;
  3351. // Once we start to read the form data only the form collection can use it
  3352. m_pData->m_FormDataStatus = FORMCOLLECTIONONLY;
  3353. memcpy( m_pData->m_szFormData,
  3354. pIReq->QueryPbData(),
  3355. pIReq->QueryCbAvailable() );
  3356. pszOffset = m_pData->m_szFormData + pIReq->QueryCbAvailable();
  3357. DWORD cBytesToRead = allocUnit;
  3358. DWORD cBytesRead = cBytesToRead;
  3359. //
  3360. // Call ReadClient until we have read all the data
  3361. //
  3362. while (cBytesRead > 0)
  3363. {
  3364. if ((!pIReq->SyncReadClient(pszOffset, &cBytesRead)) || (cBytesRead == 0))
  3365. break;
  3366. cBytesToRead -= cBytesRead;
  3367. if (cBytesToRead == 0)
  3368. {
  3369. // Dont allocatate anything larger than 32K unit else double the size of the allocation Unit.
  3370. if (allocUnit < 0x8000)
  3371. allocUnit = allocUnit << 1;
  3372. // Adjust buffer size
  3373. cbFormData += allocUnit;
  3374. if (cbFormData < allocUnit)
  3375. {
  3376. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_NOT_ALLOWED);
  3377. return E_FAIL;
  3378. }
  3379. // Allocate new memory.
  3380. m_pData->m_szFormData = static_cast<char *>(realloc(m_pData->m_szFormData,
  3381. m_pData->m_cbFormData = cbFormData));
  3382. // Check for out of memory.
  3383. if (m_pData->m_szFormData == NULL)
  3384. return E_OUTOFMEMORY;
  3385. // Adjust offset.
  3386. pszOffset = m_pData->m_szFormData + cbFormData - allocUnit -1;
  3387. cBytesToRead = allocUnit;
  3388. }
  3389. else
  3390. {
  3391. pszOffset += cBytesRead;
  3392. }
  3393. cBytesRead = cBytesToRead;
  3394. }
  3395. // Adjust cbFormData to read the currect count of data.
  3396. m_pData->m_cbFormData -= cBytesToRead;
  3397. // Add the NULL terminator.
  3398. m_pData->m_szFormData[m_pData->m_cbFormData-1] = '\0';
  3399. return S_OK;
  3400. }
  3401. /*===================================================================
  3402. CRequest::CopyNonChunkedClientData
  3403. Load the form data (stdin) by using either ReadClient or the
  3404. ISAPI buffer. This case is called when the Content Length is known and
  3405. ===================================================================*/
  3406. HRESULT CRequest::CopyNonChunkedClientData ()
  3407. {
  3408. CIsapiReqInfo *pIReq = m_pData->m_pIReq;
  3409. //
  3410. // Allocate enough space for the form data and a copy
  3411. //
  3412. size_t cbFormData = (pIReq->QueryCbTotalBytes() + 1);
  3413. if (cbFormData < 1)
  3414. {
  3415. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_NOT_ALLOWED);
  3416. return E_FAIL;
  3417. }
  3418. if (m_pData->m_cbFormData == 0)
  3419. m_pData->m_szFormData = static_cast<char *>(malloc(m_pData->m_cbFormData = cbFormData)); // space for data & its clone
  3420. else if (cbFormData > m_pData->m_cbFormData)
  3421. m_pData->m_szFormData = static_cast<char *>(realloc(m_pData->m_szFormData, m_pData->m_cbFormData = cbFormData));
  3422. if (m_pData->m_szFormData == NULL)
  3423. return E_OUTOFMEMORY;
  3424. char * pszOffset;
  3425. // Once we start to read the form data only the form collection can use it
  3426. m_pData->m_FormDataStatus = FORMCOLLECTIONONLY;
  3427. // Load the data
  3428. //
  3429. if (pIReq->QueryCbTotalBytes() <= pIReq->QueryCbAvailable())
  3430. {
  3431. memcpy( m_pData->m_szFormData,
  3432. pIReq->QueryPbData(),
  3433. pIReq->QueryCbTotalBytes() ); // bytes are available now
  3434. }
  3435. else
  3436. {
  3437. // Some bytes are in the CIsapiReqInfo buffer, we must call ReadClient for others
  3438. // First copy the data in the CIsapiReqInfo buffer
  3439. //
  3440. memcpy( m_pData->m_szFormData,
  3441. pIReq->QueryPbData(),
  3442. pIReq->QueryCbAvailable() );
  3443. DWORD cBytesToRead = pIReq->QueryCbTotalBytes() - pIReq->QueryCbAvailable();
  3444. DWORD cBytesRead = cBytesToRead;
  3445. pszOffset = m_pData->m_szFormData + pIReq->QueryCbAvailable();
  3446. // Call ReadClient until we have read all the data
  3447. //
  3448. while (cBytesToRead > 0)
  3449. {
  3450. if ((!pIReq->SyncReadClient(pszOffset, &cBytesRead)) || (cBytesRead == 0))
  3451. return E_FAIL;
  3452. cBytesToRead -= cBytesRead;
  3453. pszOffset += cBytesRead;
  3454. cBytesRead = cBytesToRead;
  3455. }
  3456. }
  3457. m_pData->m_szFormData[pIReq->QueryCbTotalBytes()] = '\0';
  3458. return S_OK;
  3459. }
  3460. /*===================================================================
  3461. CResponse::GetRequestIterator
  3462. Provide a default implementation of get__NewEnum for the Request
  3463. collections because most of the collections can use this
  3464. implementation.
  3465. Parameters:
  3466. Collection - the type of iterator to create
  3467. ppEnumReturn - on return, this points to the new enumeration
  3468. Returns:
  3469. Can return E_FAIL or E_OUTOFMEMORY
  3470. Side effects:
  3471. None.
  3472. ===================================================================*/
  3473. HRESULT CRequest::GetRequestEnumerator(CollectionType WhichCollection, IUnknown **ppEnumReturn)
  3474. {
  3475. if (FAILED(CheckForTombstone()))
  3476. return E_FAIL;
  3477. *ppEnumReturn = NULL;
  3478. CRequestIterator *pIterator = new CRequestIterator(this, WhichCollection);
  3479. if (pIterator == NULL)
  3480. {
  3481. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  3482. return E_OUTOFMEMORY;
  3483. }
  3484. HRESULT hrInit = pIterator->Init();
  3485. if (FAILED(hrInit))
  3486. {
  3487. delete pIterator;
  3488. ExceptionId(IID_IRequestDictionary,
  3489. IDE_REQUEST,
  3490. (hrInit == E_OUTOFMEMORY)? IDE_OOM : IDE_UNEXPECTED);
  3491. return hrInit;
  3492. }
  3493. *ppEnumReturn = pIterator;
  3494. return S_OK;
  3495. }
  3496. /*===================================================================
  3497. CResponse::get_TotalBytes
  3498. Presents the number of bytes to expect in the request body
  3499. Parameters:
  3500. pcBytes - pointer to long where we will place the number
  3501. of bytes to expect in the request body
  3502. Returns:
  3503. Can return E_FAIL
  3504. Side effects:
  3505. None.
  3506. ===================================================================*/
  3507. HRESULT CRequest::get_TotalBytes(long *pcbTotal)
  3508. {
  3509. if (FAILED(CheckForTombstone()))
  3510. return E_FAIL;
  3511. if (pcbTotal == NULL)
  3512. return E_FAIL;
  3513. Assert(m_pData->m_pIReq);
  3514. *pcbTotal = (long) m_pData->m_pIReq->QueryCbTotalBytes();
  3515. return S_OK;
  3516. }
  3517. /*===================================================================
  3518. CResponse::BinaryRead
  3519. Read bytes from the Request Body to a SafeArray of VT_U1.
  3520. Parameters:
  3521. pcBytes - pointer to long where we will find the number
  3522. of bytes to read in the request body, and where
  3523. we will store the number of bytes we read.
  3524. pvarOutput - pointer to variant that will contain the SafeArray we create
  3525. Returns:
  3526. Can return E_FAIL or E_OUTOFMEMORY
  3527. Side effects:
  3528. Allocates memory.
  3529. ===================================================================*/
  3530. HRESULT CRequest::BinaryRead(VARIANT *pvarCount, VARIANT *pvarReturn)
  3531. {
  3532. if (FAILED(CheckForTombstone()))
  3533. return E_FAIL;
  3534. HRESULT hr = S_OK;
  3535. SAFEARRAYBOUND rgsabound[1];
  3536. size_t cbToRead = 0;
  3537. size_t cbRead = 0;
  3538. BYTE *pbData = NULL;
  3539. Assert(m_pData->m_pIReq);
  3540. Assert(pvarCount);
  3541. Assert(pvarReturn);
  3542. // Set the variant type of the output parameter
  3543. V_VT(pvarReturn) = VT_ARRAY|VT_UI1;
  3544. V_ARRAY(pvarReturn) = NULL;
  3545. if (m_pData->m_FormDataStatus == FORMCOLLECTIONONLY)
  3546. {
  3547. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_REQUEST_BINARYREAD_NA);
  3548. hr = E_FAIL;
  3549. goto error;
  3550. }
  3551. // Convert the byte count variant to a long
  3552. if (FAILED(hr = VariantChangeTypeEx(pvarCount, pvarCount, m_pData->m_pHitObj->GetLCID(), 0, VT_I4)))
  3553. {
  3554. switch (hr)
  3555. {
  3556. case E_OUTOFMEMORY:
  3557. ExceptionId(IID_IResponse, IDE_REQUEST, IDE_OOM);
  3558. break;
  3559. case DISP_E_OVERFLOW:
  3560. hr = E_FAIL;
  3561. ExceptionId(IID_IResponse, IDE_REQUEST, IDE_RESPONSE_UNABLE_TO_CONVERT);
  3562. break;
  3563. case DISP_E_TYPEMISMATCH:
  3564. ExceptionId(IID_IResponse, IDE_REQUEST, IDE_TYPE_MISMATCH);
  3565. break;
  3566. default:
  3567. ExceptionId(IID_IResponse, IDE_REQUEST, IDE_UNEXPECTED);
  3568. }
  3569. goto error;
  3570. }
  3571. cbToRead = V_I4(pvarCount);
  3572. V_I4(pvarCount) = 0;
  3573. if ((signed long) cbToRead < 0)
  3574. {
  3575. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_REQUEST_BINREAD_BAD_ARG);
  3576. hr = E_FAIL;
  3577. goto error;
  3578. }
  3579. // If 0 bytes are requested, or available we're done
  3580. if (cbToRead == 0 || m_pData->m_cbTotal == 0)
  3581. return S_OK;
  3582. // Allocate a SafeArray for the data
  3583. // If they've asked for more bytes then the request
  3584. // contains, give them all the bytes in the request.
  3585. rgsabound[0].lLbound = 0;
  3586. if (cbToRead > m_pData->m_cbTotal)
  3587. cbToRead = m_pData->m_cbTotal;
  3588. rgsabound[0].cElements = cbToRead;
  3589. V_ARRAY(pvarReturn) = SafeArrayCreate(VT_UI1, 1, rgsabound);
  3590. if (V_ARRAY(pvarReturn) == NULL)
  3591. {
  3592. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
  3593. hr = E_OUTOFMEMORY;
  3594. goto error;
  3595. }
  3596. if (FAILED(SafeArrayAccessData(V_ARRAY(pvarReturn), (void **) &pbData)))
  3597. {
  3598. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_UNEXPECTED);
  3599. hr = E_UNEXPECTED;
  3600. goto error;
  3601. }
  3602. // There is no turning back now. The Request.Form collection will
  3603. // no longer be available.
  3604. if (m_pData->m_FormDataStatus == AVAILABLE)
  3605. {
  3606. m_pData->m_FormDataStatus = BINARYREADONLY;
  3607. m_pData->m_fLoadForm = FALSE;
  3608. }
  3609. // If the number of bytes requested is less then the number of
  3610. // bytes available (as maintained by the request object),
  3611. // then copy the requested bytes from the request object copy
  3612. // of the pointer to the CIsapiReqInfo buffer, decrement the number of bytes
  3613. // available, and increment the pointer to the CIsapiReqInfo buffer.
  3614. // Otherwise, copy all available bytes from the CIsapiReqInfo buffer, and
  3615. // then issue a call to ReadClient to get the remaining needed bytes.
  3616. if (cbToRead <= m_pData->m_cbAvailable)
  3617. {
  3618. memcpy(pbData, m_pData->m_pbAvailableData, cbToRead);
  3619. m_pData->m_pbAvailableData += cbToRead;
  3620. m_pData->m_cbAvailable -= cbToRead;
  3621. m_pData->m_cbTotal -= cbToRead;
  3622. V_I4(pvarCount) = cbToRead;
  3623. }
  3624. else
  3625. {
  3626. if (m_pData->m_cbAvailable > 0)
  3627. {
  3628. memcpy(pbData, m_pData->m_pbAvailableData, m_pData->m_cbAvailable);
  3629. V_I4(pvarCount) = m_pData->m_cbAvailable;
  3630. cbToRead -= m_pData->m_cbAvailable;
  3631. m_pData->m_cbTotal -= m_pData->m_cbAvailable;
  3632. pbData += m_pData->m_cbAvailable;
  3633. }
  3634. m_pData->m_pbAvailableData = NULL;
  3635. m_pData->m_cbAvailable = 0;
  3636. while (cbToRead)
  3637. {
  3638. cbRead = cbToRead;
  3639. if (!GetIReq()->SyncReadClient(pbData, (DWORD *)&cbRead) || (cbRead == 0))
  3640. {
  3641. SafeArrayUnaccessData(V_ARRAY(pvarReturn));
  3642. ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_UNEXPECTED);
  3643. hr = E_FAIL;
  3644. goto error;
  3645. }
  3646. pbData += cbRead;
  3647. V_I4(pvarCount) += cbRead;
  3648. m_pData->m_cbTotal -= cbRead;
  3649. cbToRead -= cbRead;
  3650. }
  3651. }
  3652. SafeArrayUnaccessData(V_ARRAY(pvarReturn));
  3653. return S_OK;
  3654. error:
  3655. VariantClear(pvarReturn);
  3656. return(hr);
  3657. }
  3658. /*===================================================================
  3659. IStream implementation for ADO/XML
  3660. ===================================================================*/
  3661. STDMETHODIMP CRequest::Read(
  3662. void *pv,
  3663. ULONG cb,
  3664. ULONG *pcbRead)
  3665. {
  3666. if (pv == NULL)
  3667. return E_POINTER;
  3668. ULONG cbReadDummy;
  3669. if (pcbRead == NULL)
  3670. pcbRead = &cbReadDummy;
  3671. if (m_pData->m_FormDataStatus != AVAILABLE &&
  3672. m_pData->m_FormDataStatus != ISTREAMONLY)
  3673. {
  3674. ExceptionId(IID_IRequestDictionary, IDE_REQUEST,
  3675. IDE_REQUEST_STREAMONLY);
  3676. return E_FAIL;
  3677. }
  3678. // If they've asked for more bytes then the request
  3679. // contains, give them all the bytes in the request.
  3680. if (cb > m_pData->m_cbTotal)
  3681. cb = m_pData->m_cbTotal;
  3682. // There is no turning back now. The Request.Form collection and
  3683. // Request.BinaryRead will no longer be available.
  3684. if (m_pData->m_FormDataStatus == AVAILABLE)
  3685. {
  3686. m_pData->m_FormDataStatus = ISTREAMONLY;
  3687. m_pData->m_fLoadForm = FALSE;
  3688. }
  3689. // If the number of bytes requested is less then the number of
  3690. // bytes available (as maintained by the request object),
  3691. // then copy the requested bytes from the request object copy of
  3692. // the pointer to the CIsapiReqInfo buffer, decrement the number of bytes
  3693. // available, and increment the pointer to the CIsapiReqInfo buffer.
  3694. // Otherwise, copy all available bytes from the CIsapiReqInfo buffer, and
  3695. // then issue a call to ReadClient to get the remaining needed bytes.
  3696. BYTE* pbData = static_cast<BYTE*>(pv);
  3697. if (cb <= m_pData->m_cbAvailable)
  3698. {
  3699. memcpy(pbData, m_pData->m_pbAvailableData, cb);
  3700. m_pData->m_pbAvailableData += cb;
  3701. m_pData->m_cbAvailable -= cb;
  3702. m_pData->m_cbTotal -= cb;
  3703. *pcbRead = cb;
  3704. }
  3705. else
  3706. {
  3707. *pcbRead = 0;
  3708. if (m_pData->m_cbAvailable > 0)
  3709. {
  3710. memcpy(pbData, m_pData->m_pbAvailableData, m_pData->m_cbAvailable);
  3711. *pcbRead = m_pData->m_cbAvailable;
  3712. cb -= m_pData->m_cbAvailable;
  3713. m_pData->m_cbTotal -= m_pData->m_cbAvailable;
  3714. pbData += m_pData->m_cbAvailable;
  3715. }
  3716. m_pData->m_pbAvailableData = NULL;
  3717. m_pData->m_cbAvailable = 0;
  3718. while (cb > 0)
  3719. {
  3720. DWORD cbRead = cb;
  3721. if ((!GetIReq()->SyncReadClient(pbData, &cbRead)) || (cbRead == 0))
  3722. {
  3723. ExceptionId(IID_IRequestDictionary, IDE_REQUEST,
  3724. IDE_UNEXPECTED);
  3725. return E_FAIL;
  3726. }
  3727. pbData += cbRead;
  3728. *pcbRead += cbRead;
  3729. m_pData->m_cbTotal -= cbRead;
  3730. cb -= cbRead;
  3731. }
  3732. }
  3733. return S_OK;
  3734. }
  3735. STDMETHODIMP CRequest::Write(
  3736. const void *pv,
  3737. ULONG cb,
  3738. ULONG *pcbWritten)
  3739. {
  3740. return E_NOTIMPL;
  3741. }
  3742. STDMETHODIMP CRequest::Seek(
  3743. LARGE_INTEGER dlibMove,
  3744. DWORD dwOrigin,
  3745. ULARGE_INTEGER *plibNewPosition)
  3746. {
  3747. // We can only do a seek if we're in the first, pre-read portion of the
  3748. // form data
  3749. if (m_pData->m_pbAvailableData == NULL)
  3750. return E_FAIL;
  3751. BYTE* pbAvailableData;
  3752. switch (dwOrigin)
  3753. {
  3754. case STREAM_SEEK_SET:
  3755. // relative to beginning of stream
  3756. pbAvailableData = m_pData->m_pIReq->QueryPbData() + dlibMove.LowPart;
  3757. break;
  3758. case STREAM_SEEK_CUR:
  3759. // relative to current position in stream
  3760. pbAvailableData = m_pData->m_pbAvailableData + dlibMove.LowPart;
  3761. break;
  3762. case STREAM_SEEK_END:
  3763. // relative to end of stream; not supported
  3764. return E_FAIL;
  3765. };
  3766. // Does the new offset fall within the initial header?
  3767. if (m_pData->m_pIReq->QueryPbData() <= pbAvailableData
  3768. && pbAvailableData < m_pData->m_pIReq->QueryPbData()
  3769. + m_pData->m_pIReq->QueryCbAvailable())
  3770. {
  3771. DWORD dwDiff = DIFF(pbAvailableData - m_pData->m_pIReq->QueryPbData());
  3772. m_pData->m_pbAvailableData = pbAvailableData;
  3773. m_pData->m_cbAvailable = m_pData->m_pIReq->QueryCbAvailable() - dwDiff;
  3774. m_pData->m_cbTotal = m_pData->m_pIReq->QueryCbTotalBytes() - dwDiff;
  3775. // Return the new position, if wanted
  3776. if (plibNewPosition != NULL)
  3777. plibNewPosition->LowPart = dwDiff;
  3778. return S_OK;
  3779. }
  3780. return E_FAIL;
  3781. }
  3782. STDMETHODIMP CRequest::SetSize(
  3783. ULARGE_INTEGER libNewSize)
  3784. {
  3785. return E_NOTIMPL;
  3786. }
  3787. STDMETHODIMP CRequest::CopyTo(
  3788. IStream *pstm,
  3789. ULARGE_INTEGER cb,
  3790. ULARGE_INTEGER *pcbRead,
  3791. ULARGE_INTEGER *pcbWritten)
  3792. {
  3793. return E_NOTIMPL;
  3794. }
  3795. STDMETHODIMP CRequest::Commit(
  3796. DWORD grfCommitFlags)
  3797. {
  3798. return E_NOTIMPL;
  3799. }
  3800. STDMETHODIMP CRequest::Revert()
  3801. {
  3802. return E_NOTIMPL;
  3803. }
  3804. STDMETHODIMP CRequest::LockRegion(
  3805. ULARGE_INTEGER libOffset,
  3806. ULARGE_INTEGER cb,
  3807. DWORD dwLockType)
  3808. {
  3809. return E_NOTIMPL;
  3810. }
  3811. STDMETHODIMP CRequest::UnlockRegion(
  3812. ULARGE_INTEGER libOffset,
  3813. ULARGE_INTEGER cb,
  3814. DWORD dwLockType)
  3815. {
  3816. return E_NOTIMPL;
  3817. }
  3818. STDMETHODIMP CRequest::Stat(
  3819. STATSTG *pstatstg,
  3820. DWORD grfStatFlag)
  3821. {
  3822. return E_NOTIMPL;
  3823. }
  3824. STDMETHODIMP CRequest::Clone(
  3825. IStream **ppstm)
  3826. {
  3827. return E_NOTIMPL;
  3828. }
  3829. #ifdef DBG
  3830. /*===================================================================
  3831. CRequest::AssertValid
  3832. Test to make sure that the CRequest object is currently correctly formed
  3833. and assert if it is not.
  3834. Returns:
  3835. Side effects:
  3836. None.
  3837. ===================================================================*/
  3838. VOID CRequest::AssertValid() const
  3839. {
  3840. }
  3841. #endif // DBG
  3842. /*===================================================================
  3843. HexToChar
  3844. Convert two digit hex string to a hex byte
  3845. Parameters:
  3846. szHex - pointer to two digit hex string
  3847. Return Value:
  3848. the character value of the hex string
  3849. ===================================================================*/
  3850. char HexToChar(LPSTR szHex)
  3851. {
  3852. char chResult, chDigit;
  3853. chDigit = (char)CharUpperA((LPSTR)szHex[0]);
  3854. chResult = (chDigit >= 'A'? (chDigit - 'A' + 0xA) : (chDigit - '0')) << 4;
  3855. chDigit = (char)CharUpperA((LPSTR)szHex[1]);
  3856. chResult |= chDigit >= 'A'? (chDigit - 'A' + 0xA) : (chDigit - '0');
  3857. return chResult;
  3858. }
  3859. /*===================================================================
  3860. DecodeFromURL
  3861. Convert two digit hex string to a hex byte
  3862. WARNING: This function modifies the passed pszSource!!
  3863. Note: this is part of bug 682, but we are not going to fix it for
  3864. performance reasons. Just be aware that this function
  3865. screws up the passed in string.
  3866. Parameters:
  3867. pszSource - in/out parameter points to a substring in the URL which
  3868. contains a Name=Value pair
  3869. szDelimiters - a set of delimiters for this field
  3870. szDest - pointer to buffer to hold the substring
  3871. Return Value:
  3872. Returns the actual delimiter that caused parsing to halt.
  3873. ===================================================================*/
  3874. char DecodeFromURL(char **pszSource, char *szDelimiters, char *szDest, UINT uCodePage, BOOL fIgnoreCase)
  3875. {
  3876. char ch;
  3877. char *szSource = *pszSource;
  3878. char *pszDestStart = szDest;
  3879. CPINFO CpInfo;
  3880. BOOL fIschLeadingByte = TRUE;
  3881. BOOL InvalidPercent = FALSE;
  3882. GetCPInfo(uCodePage, (LPCPINFO)&CpInfo);
  3883. while ((ch = *szSource++) != '\0' &&
  3884. ((!strchr(szDelimiters, ch) && fIschLeadingByte) || (!fIschLeadingByte))) {
  3885. InvalidPercent = FALSE;
  3886. switch (ch) {
  3887. case ' ': // skip whitespace - assume that all whitespace
  3888. case '\t': // that we need is escaped
  3889. case '\r': // all these chars are out of trailing byte range
  3890. case '\n':
  3891. case '\f':
  3892. case '\v':
  3893. Assert(fIschLeadingByte);
  3894. continue;
  3895. case '+': // '+' is out of trailing byte range, can never be a trailing byte
  3896. *szDest++ = ' ';
  3897. Assert(fIschLeadingByte);
  3898. break;
  3899. case '%': // '%' is out of trailing byte range, can never be a trailing byte
  3900. if (*szSource == 'u') {
  3901. if (isxdigit((UCHAR)*(szSource+1)) &&
  3902. isxdigit((UCHAR)*(szSource+2)) &&
  3903. isxdigit((UCHAR)*(szSource+3)) &&
  3904. isxdigit((UCHAR)*(szSource+4))) {
  3905. WCHAR wch[2];
  3906. int cch = 1;
  3907. wch[0] = (UCHAR)HexToChar(&szSource[1]) << 8;
  3908. wch[0] |= (UCHAR)HexToChar(&szSource[3]);
  3909. szSource += 5;
  3910. // if the current UNICODE value falls into the
  3911. // range of valid high-Surrogate, check to see if
  3912. // the next character is in the low-Surrogate
  3913. // range.
  3914. if ((wch[0] >= 0xd800)
  3915. && (wch[0] <= 0xdbff)
  3916. && (szSource[0] == '%')
  3917. && (szSource[1] == 'u')
  3918. && isxdigit((UCHAR)szSource[2])
  3919. && isxdigit((UCHAR)szSource[3])
  3920. && isxdigit((UCHAR)szSource[4])
  3921. && isxdigit((UCHAR)szSource[5])) {
  3922. // Well, the current UNICODE value is in the high
  3923. // range and the next portion of the string is
  3924. // a UNICODE encoding. Decode it.
  3925. wch[1] = (UCHAR)HexToChar(&szSource[2]) << 8;
  3926. wch[1] |= (UCHAR)HexToChar(&szSource[4]);
  3927. // Now see if it falls in the range of low-Surrogates
  3928. if ((wch[1] >= 0xdc00)
  3929. && (wch[1] <= 0xdfff)) {
  3930. // it does!!! Up the number of characters in the
  3931. // string that WideCharToMultiByte is going to
  3932. // convert. And advance the source string past this
  3933. // location.
  3934. cch = 2;
  3935. szSource += 6;
  3936. }
  3937. }
  3938. szDest += WideCharToMultiByte( uCodePage, 0, wch, cch, szDest, 6, NULL, NULL );
  3939. } else {
  3940. // What to do here ?
  3941. // since we have at least the u char after the %,
  3942. // keep the u and let the show go on
  3943. }
  3944. break;
  3945. }
  3946. else {
  3947. if (isxdigit((UCHAR)*szSource) && isxdigit((UCHAR)*(szSource+1))) {
  3948. ch = HexToChar(szSource);
  3949. szSource += 2;
  3950. }
  3951. else
  3952. {
  3953. // the spurious encoding MUST be removed
  3954. InvalidPercent = TRUE;
  3955. }
  3956. }
  3957. // FALL THROUGH to "Normal" case
  3958. default:
  3959. if (fIschLeadingByte == TRUE) {
  3960. if (CpInfo.MaxCharSize > 1) {
  3961. // if this is a Leading byte, then, the next one is a trailing byte, we need
  3962. // not process the next char even the next char is in szDelimiter, next char
  3963. // is just the second byte of a DBCS char.
  3964. if (IsDBCSLeadByteEx(uCodePage, ch))
  3965. fIschLeadingByte = FALSE;
  3966. }
  3967. }
  3968. else { // A trailing byte
  3969. // If we skip a DBCS trailing byte, then, the next char we check is a leading byte
  3970. Assert(CpInfo.MaxCharSize == 2);
  3971. fIschLeadingByte = TRUE;
  3972. }
  3973. if (!InvalidPercent) {
  3974. *szDest++ = ch;
  3975. }
  3976. }
  3977. }
  3978. if (ch == '\0') // End of String - undo increment of szSource
  3979. --szSource;
  3980. *szDest = '\0';
  3981. if (fIgnoreCase)
  3982. CharUpperA(pszDestStart);
  3983. *pszSource = szSource;
  3984. return ch;
  3985. }
  3986. /*------------------------------------------------------------------
  3987. * C S e r v V a r s I t e r a t o r
  3988. */
  3989. /*===================================================================
  3990. CServVarsIterator::CServVarsIterator
  3991. Constructor
  3992. ===================================================================*/
  3993. CServVarsIterator::CServVarsIterator()
  3994. {
  3995. m_rgwszKeys = NULL;
  3996. m_pwszKey = NULL;
  3997. m_pwchAllHttp = NULL;
  3998. m_cRefs = 1;
  3999. m_cKeys = 0;
  4000. }
  4001. /*===================================================================
  4002. CServVarsIterator::~CServVarsIterator
  4003. Destructor
  4004. ===================================================================*/
  4005. CServVarsIterator::~CServVarsIterator()
  4006. {
  4007. delete m_rgwszKeys;
  4008. delete m_pwchAllHttp;
  4009. }
  4010. /*===================================================================
  4011. CServVarsIterator::Init
  4012. Initialize the iterator by:
  4013. * Getting the value of ALL_HTTP, and parsing it to get the
  4014. extra keys
  4015. * creating a dynamic memory area to hold the ALL_HTTP keys
  4016. * setting m_rgwszKeys by copying pointers from rgwszStandardKeys
  4017. and from ALL_HTTP keys
  4018. Parameters:
  4019. pIReq - pointer to CIsapiReqInfo used to query for extra headers
  4020. Return Value:
  4021. Returns E_OUTOFMEMORY or S_OK
  4022. ===================================================================*/
  4023. HRESULT CServVarsIterator::Init
  4024. (
  4025. CIsapiReqInfo *pIReq
  4026. )
  4027. {
  4028. static wchar_t *rgwszStandardKeys[] = {
  4029. L"ALL_HTTP",
  4030. L"ALL_RAW",
  4031. L"APPL_MD_PATH",
  4032. L"APPL_PHYSICAL_PATH",
  4033. L"AUTH_PASSWORD",
  4034. L"AUTH_TYPE",
  4035. L"AUTH_USER",
  4036. L"CERT_COOKIE",
  4037. L"CERT_FLAGS",
  4038. L"CERT_ISSUER",
  4039. L"CERT_KEYSIZE",
  4040. L"CERT_SECRETKEYSIZE",
  4041. L"CERT_SERIALNUMBER",
  4042. L"CERT_SERVER_ISSUER",
  4043. L"CERT_SERVER_SUBJECT",
  4044. L"CERT_SUBJECT",
  4045. L"CONTENT_LENGTH",
  4046. L"CONTENT_TYPE",
  4047. L"GATEWAY_INTERFACE",
  4048. // Purposely left out of IIS 4.0 L"HTTP_CFG_ENC_CAPS",
  4049. // Purposely left out of IIS 4.0 L"HTTP_REQ_PWD_EXPIRE",
  4050. // Purposely left out of IIS 4.0 L"HTTP_REQ_REALM",
  4051. L"HTTPS",
  4052. L"HTTPS_KEYSIZE",
  4053. L"HTTPS_SECRETKEYSIZE",
  4054. L"HTTPS_SERVER_ISSUER",
  4055. L"HTTPS_SERVER_SUBJECT",
  4056. L"INSTANCE_ID",
  4057. L"INSTANCE_META_PATH",
  4058. L"LOCAL_ADDR",
  4059. L"LOGON_USER",
  4060. L"PATH_INFO",
  4061. L"PATH_TRANSLATED",
  4062. L"QUERY_STRING",
  4063. L"REMOTE_ADDR",
  4064. L"REMOTE_HOST",
  4065. L"REMOTE_USER",
  4066. L"REQUEST_METHOD",
  4067. // Deleted bogus variable in IIS 4.0 L"SCRIPT_MAP",
  4068. L"SCRIPT_NAME",
  4069. L"SERVER_NAME",
  4070. L"SERVER_PORT",
  4071. L"SERVER_PORT_SECURE",
  4072. L"SERVER_PROTOCOL",
  4073. L"SERVER_SOFTWARE",
  4074. // Purposely left out of IIS 4.0 L"UNMAPPED_REMOTE_USER",
  4075. L"URL"
  4076. };
  4077. const int cStandardKeys = sizeof(rgwszStandardKeys) / sizeof(rgwszStandardKeys[0]);
  4078. // Style note:
  4079. //
  4080. // pwchExtraKeys points not to just one NUL terminated wide string
  4081. // but a whole sequence of NUL terminated wide string followed by
  4082. // a double NUL terminator. I therefore chose not to use the
  4083. // standard "wsz" hungarian prefix, instead using "pwch" as
  4084. // "pointer to wide characters"
  4085. //
  4086. int cwchAlloc = 0, cRequestHeaders = 0;
  4087. DWORD dwHeaderSize = 0;
  4088. STACK_BUFFER( extraKeysBuff, 2048 );
  4089. if (!SERVER_GET(pIReq, "ALL_HTTP", &extraKeysBuff, &dwHeaderSize)) {
  4090. if (GetLastError() == E_OUTOFMEMORY) {
  4091. return E_OUTOFMEMORY;
  4092. }
  4093. else {
  4094. return E_FAIL;
  4095. }
  4096. }
  4097. char *szExtraKeys = (char *)extraKeysBuff.QueryPtr();
  4098. CMBCSToWChar convStr;
  4099. HRESULT hrConvResult;
  4100. if (FAILED(hrConvResult = convStr.Init(szExtraKeys))) {
  4101. return hrConvResult;
  4102. }
  4103. wchar_t *pwchExtraKeys = convStr.GetString();
  4104. if (! CreateKeys(pwchExtraKeys, &cwchAlloc, &cRequestHeaders))
  4105. {
  4106. return E_FAIL;
  4107. }
  4108. // At this point, pwchExtraKeys has the strings. Copy them
  4109. // into more permanent storage.
  4110. //
  4111. if (cwchAlloc)
  4112. {
  4113. Assert(pwchExtraKeys != NULL);
  4114. if ((m_pwchAllHttp = new wchar_t [cwchAlloc]) == NULL)
  4115. return E_OUTOFMEMORY;
  4116. memcpy(m_pwchAllHttp, pwchExtraKeys, cwchAlloc * sizeof(wchar_t));
  4117. }
  4118. else
  4119. m_pwchAllHttp = NULL;
  4120. // Allocate the array of keys, m_rgwszKeys, and copy the standard
  4121. // ISAPI keys, the extra keys from the request headers, and a
  4122. // terminating NULL to easily mark the end of an iteration.
  4123. //
  4124. if ((m_rgwszKeys = new wchar_t *[cStandardKeys + cRequestHeaders + 1]) == NULL)
  4125. return E_OUTOFMEMORY;
  4126. m_cKeys = cStandardKeys + cRequestHeaders;
  4127. wchar_t **pwszKey = m_rgwszKeys;
  4128. int i;
  4129. for (i = 0; i < cStandardKeys; ++i)
  4130. *pwszKey++ = rgwszStandardKeys[i];
  4131. wchar_t *pwch = m_pwchAllHttp;
  4132. for (i = 0; i < cRequestHeaders; ++i)
  4133. {
  4134. *pwszKey++ = pwch;
  4135. pwch = wcschr(pwch, L'\0') + 1;
  4136. }
  4137. // make sure that cRequestHeaders was equal to the actual number of strings
  4138. // in the pwchAllHttp string table. (Do this by making sure that we stored
  4139. // the exact amount of bytes and are now at the NULL terminator)
  4140. //
  4141. Assert (*pwch == L'\0' && (pwch - m_pwchAllHttp + 1) == cwchAlloc);
  4142. *pwszKey = NULL; // terminate the array
  4143. return Reset(); // reset the iterator
  4144. }
  4145. /*===================================================================
  4146. CServVarsIterator::CreateKeys
  4147. Parse the string from Request.ServerVariables["ALL_HTTP"], then
  4148. transform the string into a list of NUL terminated wide strings
  4149. in place, terminated with a double NUL.
  4150. Parameters:
  4151. pwchKeys -
  4152. Input: Contains the value of Request.ServerVariables["ALL_HTTP"]
  4153. as a wide string
  4154. Output: Contains the keys from Request.ServerVariables["ALL_HTTP"],
  4155. each key is separated by a NUL terminator, and the entire
  4156. list of keys is terminated by a double NUL.
  4157. pwchAlloc -
  4158. Output: Contains the number of wide characters that should be
  4159. allocated to contain the entire list of strings pointed
  4160. to by pwchKeys
  4161. pcRequestHeaders -
  4162. Output: Contains the number of keys that were found in
  4163. Request.ServerVariables["ALL_HTTP"].
  4164. Return Value:
  4165. true if successful
  4166. ===================================================================*/
  4167. BOOL CServVarsIterator::CreateKeys(wchar_t *pwchKeys, int *pcwchAlloc, int *pcRequestHeaders)
  4168. {
  4169. wchar_t *pwchSrc = pwchKeys; // source
  4170. wchar_t *pwchDest = pwchKeys; // destination
  4171. if (pwchKeys == NULL)
  4172. {
  4173. *pcwchAlloc = 0;
  4174. *pcRequestHeaders = 0;
  4175. return TRUE;
  4176. }
  4177. // Loop over pwchKeys until we hit the NUL terminator
  4178. //
  4179. *pcRequestHeaders = 0;
  4180. while (*pwchSrc)
  4181. {
  4182. // Copy characters up to the ':' and store in pwchDest
  4183. //
  4184. while (*pwchSrc != L':')
  4185. {
  4186. if (*pwchSrc == L'\0') // WinSE 27000
  4187. {
  4188. return FALSE;
  4189. }
  4190. *pwchDest++ = *pwchSrc++;
  4191. }
  4192. // now NUL terminate pwchDest, advance pwchSrc, increment cRequestHeaders
  4193. //
  4194. *pwchDest++ = L'\0';
  4195. ++pwchSrc;
  4196. ++*pcRequestHeaders;
  4197. // Skip characters until we find a \r OR \n
  4198. //
  4199. // If wcspbrk returns NULL here, it means there was no terminating
  4200. // \r or \n. In this case we can exit the loop because there
  4201. // are no more keys (the value must have ran to the end of the
  4202. // string without termination)
  4203. //
  4204. pwchSrc = wcspbrk(pwchSrc, L"\r\n");
  4205. if (! pwchSrc)
  4206. break;
  4207. // we found either \r OR \n. Skip the remaining whitspace char.
  4208. //
  4209. while (*pwchSrc == L'\r' || *pwchSrc == L'\n')
  4210. ++pwchSrc;
  4211. // pwchSrc now points to the next key.
  4212. }
  4213. // terminate with the final NUL.
  4214. *pwchDest++ = L'\0';
  4215. *pcwchAlloc = DIFF(pwchDest - pwchKeys);
  4216. return TRUE;
  4217. }
  4218. /*===================================================================
  4219. CServVarsIterator::QueryInterface
  4220. CServVarsIterator::AddRef
  4221. CServVarsIterator::Release
  4222. IUnknown members for CServVarsIterator object.
  4223. ===================================================================*/
  4224. STDMETHODIMP CServVarsIterator::QueryInterface(REFIID iid, void **ppvObj)
  4225. {
  4226. if (iid == IID_IUnknown || iid == IID_IEnumVARIANT)
  4227. {
  4228. AddRef();
  4229. *ppvObj = this;
  4230. return S_OK;
  4231. }
  4232. *ppvObj = NULL;
  4233. return E_NOINTERFACE;
  4234. }
  4235. STDMETHODIMP_(ULONG) CServVarsIterator::AddRef()
  4236. {
  4237. return ++m_cRefs;
  4238. }
  4239. STDMETHODIMP_(ULONG) CServVarsIterator::Release()
  4240. {
  4241. if (--m_cRefs > 0)
  4242. return m_cRefs;
  4243. delete this;
  4244. return 0;
  4245. }
  4246. /*===================================================================
  4247. CServVarsIterator::Clone
  4248. Clone this iterator (standard method)
  4249. NOTE:
  4250. Cloning this iterator is quite involved. (It essentially
  4251. involves copying the allocated memory, then adjusting
  4252. ONLY the dynamic pointers in the rgwszKeys array.)
  4253. Right now, this is NYI, as our client (VBScript)
  4254. does not clone this iterator.
  4255. ===================================================================*/
  4256. STDMETHODIMP CServVarsIterator::Clone(IEnumVARIANT **ppEnumReturn)
  4257. {
  4258. return E_NOTIMPL;
  4259. }
  4260. /*===================================================================
  4261. CServVarsIterator::Next
  4262. Get next value (standard method)
  4263. To rehash standard OLE semantics:
  4264. We get the next "cElements" from the collection and store them
  4265. in "rgVariant" which holds at least "cElements" items. On
  4266. return "*pcElementsFetched" contains the actual number of elements
  4267. stored. Returns S_FALSE if less than "cElements" were stored, S_OK
  4268. otherwise.
  4269. ===================================================================*/
  4270. STDMETHODIMP CServVarsIterator::Next(unsigned long cElementsRequested, VARIANT *rgVariant, unsigned long *pcElementsFetched)
  4271. {
  4272. // give a valid pointer value to 'pcElementsFetched'
  4273. //
  4274. unsigned long cElementsFetched;
  4275. if (pcElementsFetched == NULL)
  4276. pcElementsFetched = &cElementsFetched;
  4277. // Loop through the collection until either we reach the end or
  4278. // cElements becomes zero
  4279. //
  4280. unsigned long cElements = cElementsRequested;
  4281. *pcElementsFetched = 0;
  4282. while (cElements > 0 && *m_pwszKey != NULL)
  4283. {
  4284. BSTR bstrT = SysAllocString(*m_pwszKey);
  4285. if (bstrT == NULL)
  4286. return E_OUTOFMEMORY;
  4287. V_VT(rgVariant) = VT_BSTR;
  4288. V_BSTR(rgVariant) = bstrT;
  4289. ++m_pwszKey;
  4290. ++rgVariant;
  4291. --cElements;
  4292. ++*pcElementsFetched;
  4293. }
  4294. // initialize the remaining variants
  4295. //
  4296. while (cElements-- > 0)
  4297. VariantInit(rgVariant++);
  4298. return (*pcElementsFetched == cElementsRequested)? S_OK : S_FALSE;
  4299. }
  4300. /*===================================================================
  4301. CServVarsIterator::Skip
  4302. Skip items (standard method)
  4303. To rehash standard OLE semantics:
  4304. We skip over the next "cElements" from the collection.
  4305. Returns S_FALSE if less than "cElements" were skipped, S_OK
  4306. otherwise.
  4307. ===================================================================*/
  4308. STDMETHODIMP CServVarsIterator::Skip(unsigned long cElements)
  4309. {
  4310. /* Loop through the collection until either we reach the end or
  4311. * cElements becomes zero
  4312. */
  4313. while (cElements > 0 && *m_pwszKey != NULL)
  4314. {
  4315. --cElements;
  4316. ++m_pwszKey;
  4317. }
  4318. return (cElements == 0)? S_OK : S_FALSE;
  4319. }
  4320. /*===================================================================
  4321. CServVarsIterator::Reset
  4322. Reset the iterator (standard method)
  4323. ===================================================================*/
  4324. STDMETHODIMP CServVarsIterator::Reset()
  4325. {
  4326. m_pwszKey = &m_rgwszKeys[0];
  4327. return S_OK;
  4328. }
  4329. /*------------------------------------------------------------------
  4330. * C R e q u e s t I t e r a t o r
  4331. */
  4332. /*===================================================================
  4333. CRequestIterator::CRequestIterator
  4334. Constructor
  4335. NOTE: CRequest is (currently) not refcounted. AddRef/Release
  4336. added to protect against future changes.
  4337. ===================================================================*/
  4338. CRequestIterator::CRequestIterator(CRequest *pRequest, CollectionType Collection)
  4339. {
  4340. m_Collection = Collection;
  4341. m_pRequest = pRequest;
  4342. m_cRefs = 1;
  4343. m_pRequestHit = NULL; // Init() will change this pointer anyway...
  4344. m_pRequest->AddRef();
  4345. }
  4346. /*===================================================================
  4347. CRequestIterator::CRequestIterator
  4348. Destructor
  4349. ===================================================================*/
  4350. CRequestIterator::~CRequestIterator()
  4351. {
  4352. m_pRequest->Release();
  4353. }
  4354. /*===================================================================
  4355. CRequestIterator::Init
  4356. Initialize the iterator by loading the collection that we are
  4357. about to iterate over.
  4358. Return Value:
  4359. Returns E_FAIL if there were problems loading the collection,
  4360. and possibly E_OUTOFMEMORY.
  4361. ===================================================================*/
  4362. HRESULT CRequestIterator::Init()
  4363. {
  4364. if (FAILED(m_pRequest->CheckForTombstone()))
  4365. return E_FAIL;
  4366. switch (m_Collection)
  4367. {
  4368. case QUERYSTRING:
  4369. if (m_pRequest->m_pData->m_fLoadQuery)
  4370. {
  4371. if (FAILED(m_pRequest->LoadVariables(QUERYSTRING, m_pRequest->GetIReq()->QueryPszQueryString(), m_pRequest->GetCodePage())))
  4372. return E_FAIL;
  4373. m_pRequest->m_pData->m_fLoadQuery = FALSE;
  4374. }
  4375. break;
  4376. case FORM:
  4377. if (m_pRequest->m_pData->m_fLoadForm)
  4378. {
  4379. HRESULT hrGetData = m_pRequest->CopyClientData();
  4380. if (FAILED(hrGetData))
  4381. return hrGetData;
  4382. if (FAILED(m_pRequest->LoadVariables(FORM, m_pRequest->m_pData->m_szFormData, m_pRequest->GetCodePage())))
  4383. return E_FAIL;
  4384. m_pRequest->m_pData->m_fLoadForm = FALSE;
  4385. }
  4386. break;
  4387. case COOKIE:
  4388. if (m_pRequest->m_pData->m_fLoadCookies)
  4389. {
  4390. char *szCookie = m_pRequest->GetIReq()->QueryPszCookie();
  4391. if (FAILED(m_pRequest->LoadVariables(COOKIE, szCookie, m_pRequest->GetCodePage())))
  4392. return E_FAIL;
  4393. m_pRequest->m_pData->m_fLoadCookies = FALSE;
  4394. }
  4395. break;
  4396. case CLCERT:
  4397. if (m_pRequest->m_pData->m_fLoadClCerts)
  4398. {
  4399. if (FAILED(m_pRequest->LoadVariables(CLCERT, (char*)m_pRequest->GetIReq(), m_pRequest->GetCodePage())))
  4400. return E_FAIL;
  4401. m_pRequest->m_pData->m_fLoadClCerts = FALSE;
  4402. }
  4403. break;
  4404. }
  4405. return Reset();
  4406. }
  4407. /*===================================================================
  4408. CRequestIterator::QueryInterface
  4409. CRequestIterator::AddRef
  4410. CRequestIterator::Release
  4411. IUnknown members for CRequestIterator object.
  4412. ===================================================================*/
  4413. STDMETHODIMP CRequestIterator::QueryInterface(REFIID iid, void **ppvObj)
  4414. {
  4415. if (iid == IID_IUnknown || iid == IID_IEnumVARIANT)
  4416. {
  4417. AddRef();
  4418. *ppvObj = this;
  4419. return S_OK;
  4420. }
  4421. *ppvObj = NULL;
  4422. return E_NOINTERFACE;
  4423. }
  4424. STDMETHODIMP_(ULONG) CRequestIterator::AddRef()
  4425. {
  4426. return ++m_cRefs;
  4427. }
  4428. STDMETHODIMP_(ULONG) CRequestIterator::Release()
  4429. {
  4430. if (--m_cRefs > 0)
  4431. return m_cRefs;
  4432. delete this;
  4433. return 0;
  4434. }
  4435. /*===================================================================
  4436. CRequestIterator::Clone
  4437. Clone this iterator (standard method)
  4438. ===================================================================*/
  4439. STDMETHODIMP CRequestIterator::Clone(IEnumVARIANT **ppEnumReturn)
  4440. {
  4441. if (FAILED(m_pRequest->CheckForTombstone()))
  4442. return E_FAIL;
  4443. CRequestIterator *pNewIterator = new CRequestIterator(m_pRequest, m_Collection);
  4444. if (pNewIterator == NULL)
  4445. return E_OUTOFMEMORY;
  4446. // new iterator should point to same location as this.
  4447. pNewIterator->m_pRequestHit = m_pRequestHit;
  4448. *ppEnumReturn = pNewIterator;
  4449. return S_OK;
  4450. }
  4451. /*===================================================================
  4452. CRequestIterator::Next
  4453. Get next value (standard method)
  4454. To rehash standard OLE semantics:
  4455. We get the next "cElements" from the collection and store them
  4456. in "rgVariant" which holds at least "cElements" items. On
  4457. return "*pcElementsFetched" contains the actual number of elements
  4458. stored. Returns S_FALSE if less than "cElements" were stored, S_OK
  4459. otherwise.
  4460. ===================================================================*/
  4461. STDMETHODIMP CRequestIterator::Next(unsigned long cElementsRequested, VARIANT *rgVariant, unsigned long *pcElementsFetched)
  4462. {
  4463. if (FAILED(m_pRequest->CheckForTombstone()))
  4464. return E_FAIL;
  4465. // give a valid pointer value to 'pcElementsFetched'
  4466. //
  4467. unsigned long cElementsFetched;
  4468. if (pcElementsFetched == NULL)
  4469. pcElementsFetched = &cElementsFetched;
  4470. // Loop through the collection until either we reach the end or
  4471. // cElements becomes zero
  4472. //
  4473. unsigned long cElements = cElementsRequested;
  4474. *pcElementsFetched = 0;
  4475. while (cElements > 0 && m_pRequestHit != NULL)
  4476. {
  4477. BOOL fHaveData = FALSE;
  4478. switch (m_Collection)
  4479. {
  4480. case QUERYSTRING:
  4481. fHaveData = m_pRequestHit->m_pQueryData != NULL;
  4482. break;
  4483. case FORM:
  4484. fHaveData = m_pRequestHit->m_pFormData != NULL;
  4485. break;
  4486. case COOKIE:
  4487. fHaveData = m_pRequestHit->m_pCookieData != NULL;
  4488. break;
  4489. case CLCERT:
  4490. fHaveData = m_pRequestHit->m_pClCertData != NULL;
  4491. }
  4492. if (fHaveData)
  4493. {
  4494. BSTR bstrT;
  4495. if (FAILED(SysAllocStringFromSz(reinterpret_cast<char *>(m_pRequestHit->m_pKey), 0, &bstrT,m_pRequest->GetCodePage())))
  4496. return E_OUTOFMEMORY;
  4497. V_VT(rgVariant) = VT_BSTR;
  4498. V_BSTR(rgVariant) = bstrT;
  4499. ++rgVariant;
  4500. --cElements;
  4501. ++*pcElementsFetched;
  4502. }
  4503. m_pRequestHit = static_cast<CRequestHit *>(m_pRequestHit->m_pPrev);
  4504. }
  4505. // initialize the remaining variants
  4506. //
  4507. while (cElements-- > 0)
  4508. VariantInit(rgVariant++);
  4509. return (*pcElementsFetched == cElementsRequested)? S_OK : S_FALSE;
  4510. }
  4511. /*===================================================================
  4512. CRequestIterator::Skip
  4513. Skip items (standard method)
  4514. To rehash standard OLE semantics:
  4515. We skip over the next "cElements" from the collection.
  4516. Returns S_FALSE if less than "cElements" were skipped, S_OK
  4517. otherwise.
  4518. ===================================================================*/
  4519. STDMETHODIMP CRequestIterator::Skip(unsigned long cElements)
  4520. {
  4521. if (FAILED(m_pRequest->CheckForTombstone()))
  4522. return E_FAIL;
  4523. /* Loop through the collection until either we reach the end or
  4524. * cElements becomes zero
  4525. */
  4526. while (cElements > 0 && m_pRequestHit != NULL)
  4527. {
  4528. BOOL fHaveData = FALSE;
  4529. switch (m_Collection)
  4530. {
  4531. case QUERYSTRING:
  4532. fHaveData = m_pRequestHit->m_pQueryData != NULL;
  4533. break;
  4534. case FORM:
  4535. fHaveData = m_pRequestHit->m_pFormData != NULL;
  4536. break;
  4537. case COOKIE:
  4538. fHaveData = m_pRequestHit->m_pCookieData != NULL;
  4539. break;
  4540. case CLCERT:
  4541. fHaveData = m_pRequestHit->m_pClCertData != NULL;
  4542. }
  4543. if (fHaveData)
  4544. --cElements;
  4545. m_pRequestHit = static_cast<CRequestHit *>(m_pRequestHit->m_pPrev);
  4546. }
  4547. return (cElements == 0)? S_OK : S_FALSE;
  4548. }
  4549. /*===================================================================
  4550. CRequestIterator::Reset
  4551. Reset the iterator (standard method)
  4552. ===================================================================*/
  4553. STDMETHODIMP CRequestIterator::Reset()
  4554. {
  4555. if (FAILED(m_pRequest->CheckForTombstone()))
  4556. return E_FAIL;
  4557. m_pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->Tail());
  4558. return S_OK;
  4559. }