Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5777 lines
161 KiB

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