Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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