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.

1519 lines
37 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Request, Response objects
  6. File: cookies.cpp
  7. Owner: DGottner
  8. This file contains the code for the implementation of the
  9. Request.Cookies and Response.Cookies collections.
  10. ===================================================================*/
  11. #include "denpre.h"
  12. #pragma hdrstop
  13. #include "objbase.h"
  14. #include "cookies.h"
  15. #include "memchk.h"
  16. #pragma warning (disable: 4355) // ignore: "'this' used in base member init
  17. /*------------------------------------------------------------------
  18. * C C o o k i e S u p p o r t E r r
  19. */
  20. /*===================================================================
  21. CCookieSupportErr::CCookieSupportErr
  22. constructor
  23. ===================================================================*/
  24. CCookieSupportErr::CCookieSupportErr(CCookie *pCookie)
  25. {
  26. m_pCookie = pCookie;
  27. }
  28. /*===================================================================
  29. CCookieSupportErr::QueryInterface
  30. CCookieSupportErr::AddRef
  31. CCookieSupportErr::Release
  32. Delegating IUnknown members for CCookieSupportErr object.
  33. ===================================================================*/
  34. STDMETHODIMP CCookieSupportErr::QueryInterface(const IID &idInterface, void **ppvObj)
  35. {
  36. return m_pCookie->QueryInterface(idInterface, ppvObj);
  37. }
  38. STDMETHODIMP_(ULONG) CCookieSupportErr::AddRef()
  39. {
  40. return m_pCookie->AddRef();
  41. }
  42. STDMETHODIMP_(ULONG) CCookieSupportErr::Release()
  43. {
  44. return m_pCookie->Release();
  45. }
  46. /*===================================================================
  47. CCookieSupportErr::InterfaceSupportsErrorInfo
  48. Report back to OA about which interfaces we support that return
  49. error information
  50. ===================================================================*/
  51. STDMETHODIMP CCookieSupportErr::InterfaceSupportsErrorInfo(const GUID &idInterface)
  52. {
  53. if (idInterface == IID_IDispatch || idInterface == IID_IWriteCookie || idInterface == IID_IReadCookie)
  54. return S_OK;
  55. return S_FALSE;
  56. }
  57. /*------------------------------------------------------------------
  58. * C W r i t e C o o k i e
  59. */
  60. /*===================================================================
  61. CWriteCookie::CWriteCookie
  62. constructor
  63. ===================================================================*/
  64. CWriteCookie::CWriteCookie(CCookie *pCookie)
  65. {
  66. m_pCookie = pCookie;
  67. CDispatch::Init(IID_IWriteCookie);
  68. }
  69. /*===================================================================
  70. CWriteCookie::QueryInterface
  71. CWriteCookie::AddRef
  72. CWriteCookie::Release
  73. Delegating IUnknown members for CWriteCookie object.
  74. ===================================================================*/
  75. STDMETHODIMP CWriteCookie::QueryInterface(const IID &idInterface, void **ppvObj)
  76. {
  77. // Bug 85953 Trap IDispatch before it gets to the core object
  78. if (idInterface == IID_IUnknown ||
  79. idInterface == IID_IWriteCookie ||
  80. idInterface == IID_IDispatch)
  81. {
  82. *ppvObj = this;
  83. static_cast<IUnknown *>(*ppvObj)->AddRef();
  84. return S_OK;
  85. }
  86. else
  87. return m_pCookie->QueryInterface(idInterface, ppvObj);
  88. }
  89. STDMETHODIMP_(ULONG) CWriteCookie::AddRef()
  90. {
  91. return m_pCookie->AddRef();
  92. }
  93. STDMETHODIMP_(ULONG) CWriteCookie::Release()
  94. {
  95. return m_pCookie->Release();
  96. }
  97. /*===================================================================
  98. CWriteCookie::put_Item
  99. Set the primary value for a cookie.
  100. ===================================================================*/
  101. STDMETHODIMP CWriteCookie::put_Item(VARIANT varKey, BSTR bstrValue)
  102. {
  103. char *szKey; // ascii value of the key
  104. CWCharToMBCS convValue;
  105. CWCharToMBCS convKey;
  106. // Bug 122589: Don't crash when "bstrValue" is NULL
  107. if (bstrValue == NULL)
  108. return E_FAIL;
  109. // Initialize things
  110. //
  111. VARIANT *pvarKey = &varKey;
  112. HRESULT hrReturn = S_OK;
  113. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
  114. // produced by IEnumVariant
  115. //
  116. // Use VariantResolveDispatch which will:
  117. //
  118. // * Copy BYREF variants for us using VariantCopyInd
  119. // * handle E_OUTOFMEMORY for us
  120. // * get the default value from an IDispatch, which seems
  121. // like an appropriate conversion.
  122. //
  123. VARIANT varKeyCopy;
  124. VariantInit(&varKeyCopy);
  125. if (V_VT(pvarKey) != VT_BSTR)
  126. {
  127. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  128. goto LExit;
  129. pvarKey = &varKeyCopy;
  130. }
  131. switch (V_VT(pvarKey))
  132. {
  133. case VT_BSTR:
  134. break;
  135. case VT_ERROR:
  136. if (V_ERROR(pvarKey) == DISP_E_PARAMNOTFOUND)
  137. {
  138. if (m_pCookie->m_szValue == NULL) // current value is a dictionary
  139. {
  140. CCookiePair *pNukePair = static_cast<CCookiePair *>(m_pCookie->m_mpszValues.Head());
  141. while (pNukePair != NULL)
  142. {
  143. CCookiePair *pNext = static_cast<CCookiePair *>(pNukePair->m_pNext);
  144. delete pNukePair;
  145. pNukePair = pNext;
  146. }
  147. m_pCookie->m_mpszValues.ReInit();
  148. }
  149. else // no dictionary value
  150. if (m_pCookie->m_fDuplicate)
  151. free(m_pCookie->m_szValue);
  152. if (FAILED(hrReturn = convValue.Init(bstrValue,m_pCookie->m_lCodePage))) {
  153. goto LExit;
  154. }
  155. m_pCookie->m_szValue = NULL;
  156. m_pCookie->AddValue(convValue.GetString(), TRUE);
  157. m_pCookie->m_fDirty = TRUE;
  158. goto LExit;
  159. }
  160. // Other error, FALL THROUGH to wrong type case
  161. default:
  162. ExceptionId(IID_IWriteCookie, IDE_COOKIE, IDE_EXPECTING_STR);
  163. hrReturn = E_FAIL;
  164. goto LExit;
  165. }
  166. // don't allow empty keys in the cookie
  167. //
  168. if (V_BSTR(pvarKey)) {
  169. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey),m_pCookie->m_lCodePage))) {
  170. goto LExit;
  171. }
  172. else {
  173. szKey = convKey.GetString();
  174. }
  175. }
  176. else {
  177. szKey = "";
  178. }
  179. if (*szKey == '\0')
  180. {
  181. ExceptionId(IID_IWriteCookie, IDE_COOKIE, IDE_COOKIE_EMPTY_DICT);
  182. hrReturn = E_FAIL;
  183. goto LExit;
  184. }
  185. // we're changing a dictionary value, so first trash the primary value
  186. //
  187. if (m_pCookie->m_fDuplicate)
  188. free(m_pCookie->m_szValue);
  189. if (FAILED(hrReturn = convValue.Init(bstrValue,m_pCookie->m_lCodePage))) {
  190. goto LExit;
  191. }
  192. m_pCookie->m_szValue = NULL;
  193. m_pCookie->AddKeyAndValue(szKey, convValue.GetString(), TRUE);
  194. m_pCookie->m_fDirty = TRUE;
  195. LExit:
  196. VariantClear(&varKeyCopy);
  197. return hrReturn;
  198. }
  199. /*===================================================================
  200. CWriteCookie::put_Expires
  201. Set the expires attribute for a cookie.
  202. ===================================================================*/
  203. STDMETHODIMP CWriteCookie::put_Expires(DATE dtExpires)
  204. {
  205. if (FAILED(VariantDateToCTime(dtExpires, &m_pCookie->m_tExpires)))
  206. {
  207. ExceptionId(IID_IWriteCookie, IDE_COOKIE, IDE_COOKIE_BAD_EXPIRATION);
  208. return E_FAIL;
  209. }
  210. m_pCookie->m_fDirty = TRUE;
  211. return S_OK;
  212. }
  213. /*===================================================================
  214. CWriteCookie::put_Domain
  215. Set the domain attribute for a cookie.
  216. ===================================================================*/
  217. STDMETHODIMP CWriteCookie::put_Domain(BSTR bstrDomain)
  218. {
  219. CWCharToMBCS convDomain;
  220. HRESULT hr = S_OK;
  221. if (FAILED(hr = convDomain.Init(bstrDomain,m_pCookie->m_lCodePage)));
  222. else {
  223. if (m_pCookie->m_szDomain)
  224. free(m_pCookie->m_szDomain);
  225. m_pCookie->m_szDomain = convDomain.GetString(TRUE);
  226. m_pCookie->m_fDirty = TRUE;
  227. }
  228. return hr;
  229. }
  230. /*===================================================================
  231. CWriteCookie::put_Path
  232. Set the path attribute for a cookie.
  233. ===================================================================*/
  234. STDMETHODIMP CWriteCookie::put_Path(BSTR bstrPath)
  235. {
  236. HRESULT hr = S_OK;
  237. CWCharToMBCS convPath;
  238. if (FAILED(hr = convPath.Init(bstrPath,m_pCookie->m_lCodePage)));
  239. else {
  240. if (m_pCookie->m_szPath)
  241. free(m_pCookie->m_szPath);
  242. m_pCookie->m_szPath = convPath.GetString(TRUE);
  243. if (m_pCookie->m_szPath == NULL)
  244. hr = E_OUTOFMEMORY;
  245. }
  246. if (SUCCEEDED(hr))
  247. m_pCookie->m_fDirty = TRUE;
  248. return hr;
  249. }
  250. /*===================================================================
  251. CWriteCookie::put_Secure
  252. Set the secure attribute for a cookie.
  253. ===================================================================*/
  254. STDMETHODIMP CWriteCookie::put_Secure(VARIANT_BOOL fSecure)
  255. {
  256. m_pCookie->m_fSecure = fSecure;
  257. m_pCookie->m_fDirty = TRUE;
  258. return S_OK;
  259. }
  260. /*===================================================================
  261. CWriteCookie::get_HasKeys
  262. Return True if the cookie contains keys, False if it is a simple
  263. value
  264. ===================================================================*/
  265. STDMETHODIMP CWriteCookie::get_HasKeys(VARIANT_BOOL *pfHasKeys)
  266. {
  267. *pfHasKeys = ( m_pCookie->m_mpszValues.Count() > 0 ? VARIANT_TRUE : VARIANT_FALSE);
  268. return S_OK;
  269. }
  270. /*===================================================================
  271. CWriteCookie::get__NewEnum
  272. Return an enumerator object.
  273. ReadCookie and WriteCookie use the same iterator object.
  274. To reduce useless redundancy, deletage to IReadCookie.
  275. The IReadCookie enumerator will likely be used much more
  276. frequently than the IWriteCookie iterator, so we pay the
  277. overhead of delegation in this function.
  278. ===================================================================*/
  279. STDMETHODIMP CWriteCookie::get__NewEnum(IUnknown **ppEnumReturn)
  280. {
  281. IReadCookie *pReadCookie;
  282. if (FAILED(QueryInterface(IID_IReadCookie, reinterpret_cast<void **>(&pReadCookie))))
  283. {
  284. Assert (FALSE); // expect success!
  285. return E_FAIL;
  286. }
  287. HRESULT hrNewEnum = pReadCookie->get__NewEnum(ppEnumReturn);
  288. pReadCookie->Release();
  289. return hrNewEnum;
  290. }
  291. /*------------------------------------------------------------------
  292. * C R e a d C o o k i e
  293. */
  294. /*===================================================================
  295. CReadCookie::CReadCookie
  296. constructor
  297. ===================================================================*/
  298. CReadCookie::CReadCookie(CCookie *pCookie)
  299. {
  300. m_pCookie = pCookie;
  301. CDispatch::Init(IID_IReadCookie);
  302. }
  303. /*===================================================================
  304. CReadCookie::QueryInterface
  305. CReadCookie::AddRef
  306. CReadCookie::Release
  307. Delegating IUnknown members for CReadCookie object.
  308. ===================================================================*/
  309. STDMETHODIMP CReadCookie::QueryInterface(const IID &idInterface, void **ppvObj)
  310. {
  311. // Bug 85953 Trap IDispatch before it gets to the core object
  312. if (idInterface == IID_IUnknown ||
  313. idInterface == IID_IReadCookie ||
  314. idInterface == IID_IDispatch)
  315. {
  316. *ppvObj = this;
  317. static_cast<IUnknown *>(*ppvObj)->AddRef();
  318. return S_OK;
  319. }
  320. else
  321. return m_pCookie->QueryInterface(idInterface, ppvObj);
  322. }
  323. STDMETHODIMP_(ULONG) CReadCookie::AddRef()
  324. {
  325. return m_pCookie->AddRef();
  326. }
  327. STDMETHODIMP_(ULONG) CReadCookie::Release()
  328. {
  329. return m_pCookie->Release();
  330. }
  331. /*===================================================================
  332. CReadCookie::get_Item
  333. Retrieve a value in the cookie dictionary.
  334. ===================================================================*/
  335. STDMETHODIMP CReadCookie::get_Item(VARIANT varKey, VARIANT *pvarReturn)
  336. {
  337. char *szKey; // ascii version of the key
  338. CCookiePair *pPair = NULL; // name and value of cookie in the dictionary
  339. CWCharToMBCS convKey;
  340. STACK_BUFFER( tempCookie, 128 );
  341. // Initialize things
  342. //
  343. VariantInit(pvarReturn);
  344. VARIANT *pvarKey = &varKey;
  345. HRESULT hrReturn = S_OK;
  346. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
  347. // produced by IEnumVariant
  348. //
  349. // Use VariantResolveDispatch which will:
  350. //
  351. // * Copy BYREF variants for us using VariantCopyInd
  352. // * handle E_OUTOFMEMORY for us
  353. // * get the default value from an IDispatch, which seems
  354. // like an appropriate conversion.
  355. //
  356. VARIANT varKeyCopy;
  357. VariantInit(&varKeyCopy);
  358. DWORD vt = V_VT(pvarKey);
  359. if ((V_VT(pvarKey) != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  360. {
  361. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  362. goto LExit;
  363. pvarKey = &varKeyCopy;
  364. }
  365. vt = V_VT(pvarKey);
  366. switch (vt)
  367. {
  368. // Bug 95201 support all numberic sub-types
  369. case VT_I1: case VT_I2: case VT_I8:
  370. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  371. case VT_R4: case VT_R8:
  372. // Coerce all integral types to VT_I4
  373. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  374. goto LExit;
  375. // fallthru to VT_I4
  376. case VT_I4:
  377. case VT_BSTR:
  378. break;
  379. case VT_ERROR:
  380. if (V_ERROR(pvarKey) == DISP_E_PARAMNOTFOUND)
  381. {
  382. V_VT(pvarReturn) = VT_BSTR;
  383. // simple value, URLEncoding NOT a good idea in this case
  384. if (m_pCookie->m_szValue)
  385. {
  386. BSTR bstrT;
  387. if (FAILED(SysAllocStringFromSz(m_pCookie->m_szValue, 0, &bstrT,m_pCookie->m_lCodePage)))
  388. {
  389. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_OOM);
  390. hrReturn = E_FAIL;
  391. goto LExit;
  392. }
  393. V_BSTR(pvarReturn) = bstrT;
  394. }
  395. // dictionary value, must URLEncode to prevent '&', '=' from being misinterpreted
  396. else
  397. {
  398. int cbHTTPCookie = m_pCookie->GetHTTPCookieSize();
  399. if (cbHTTPCookie > REQUEST_ALLOC_MAX)
  400. {
  401. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_STACK_OVERFLOW);
  402. hrReturn = E_FAIL;
  403. goto LExit;
  404. }
  405. if (tempCookie.Resize(cbHTTPCookie) == FALSE) {
  406. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_OOM);
  407. hrReturn = E_OUTOFMEMORY;
  408. goto LExit;
  409. }
  410. char *szHTTPCookie = static_cast<char *>(tempCookie.QueryPtr());
  411. m_pCookie->GetHTTPCookie(szHTTPCookie);
  412. BSTR bstrT;
  413. if (FAILED(SysAllocStringFromSz(szHTTPCookie, 0, &bstrT,m_pCookie->m_lCodePage)))
  414. {
  415. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_OOM);
  416. hrReturn = E_FAIL;
  417. goto LExit;
  418. }
  419. V_BSTR(pvarReturn) = bstrT;
  420. }
  421. goto LExit;
  422. }
  423. default:
  424. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_EXPECTING_STR);
  425. hrReturn = E_FAIL;
  426. goto LExit;
  427. }
  428. if (vt == VT_BSTR)
  429. {
  430. // convert the key to ANSI
  431. if (V_BSTR(pvarKey)) {
  432. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey),m_pCookie->m_lCodePage))) {
  433. goto LExit;
  434. }
  435. else {
  436. szKey = convKey.GetString();
  437. }
  438. }
  439. else {
  440. szKey = "";
  441. }
  442. // Look up the key in the Cookie.
  443. pPair = static_cast<CCookiePair *>(m_pCookie->m_mpszValues.FindElem(szKey, strlen(szKey)));
  444. }
  445. else
  446. {
  447. // Look up item by index
  448. int iCount;
  449. iCount = V_I4(pvarKey);
  450. if ((iCount < 1) ||
  451. (m_pCookie->m_mpszValues.Count() == 0) ||
  452. (iCount > (int) m_pCookie->m_mpszValues.Count() ))
  453. {
  454. hrReturn = E_FAIL;
  455. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_BAD_ARRAY_INDEX);
  456. goto LExit;
  457. }
  458. pPair = static_cast<CCookiePair *>(m_pCookie->m_mpszValues.Head());
  459. while((iCount > 1) && (pPair != NULL))
  460. {
  461. pPair = static_cast<CCookiePair *>(pPair->m_pNext);
  462. iCount--;
  463. }
  464. }
  465. if (pPair)
  466. {
  467. BSTR bstrT;
  468. if (FAILED(SysAllocStringFromSz(pPair->m_szValue, 0, &bstrT,m_pCookie->m_lCodePage)))
  469. {
  470. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_OOM);
  471. hrReturn = E_FAIL;
  472. goto LExit;
  473. }
  474. V_VT(pvarReturn) = VT_BSTR;
  475. V_BSTR(pvarReturn) = bstrT;
  476. }
  477. LExit:
  478. VariantClear(&varKeyCopy);
  479. return hrReturn;
  480. }
  481. /*===================================================================
  482. CReadCookie::get_HasKeys
  483. Return True if the cookie contains keys, False if it is a simple
  484. value
  485. ===================================================================*/
  486. STDMETHODIMP CReadCookie::get_HasKeys(VARIANT_BOOL *pfHasKeys)
  487. {
  488. *pfHasKeys = (m_pCookie->m_mpszValues.Count() > 0 ? VARIANT_TRUE : VARIANT_FALSE);
  489. return S_OK;
  490. }
  491. /*===================================================================
  492. CReadCookie::get__NewEnum
  493. Return an enumerator object.
  494. ===================================================================*/
  495. STDMETHODIMP CReadCookie::get__NewEnum(IUnknown **ppEnumReturn)
  496. {
  497. *ppEnumReturn = NULL;
  498. CCookieIterator *pIterator = new CCookieIterator(m_pCookie);
  499. if (pIterator == NULL)
  500. {
  501. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_OOM);
  502. return E_OUTOFMEMORY;
  503. }
  504. *ppEnumReturn = pIterator;
  505. return S_OK;
  506. }
  507. /*===================================================================
  508. CReadCookie::get_Count
  509. Parameters:
  510. pcValues - count is stored in *pcValues. Set to 0 if this
  511. cookie is not multi-valued.
  512. ===================================================================*/
  513. STDMETHODIMP CReadCookie::get_Count(int *pcValues)
  514. {
  515. *pcValues = m_pCookie->m_mpszValues.Count();
  516. return S_OK;
  517. }
  518. /*===================================================================
  519. CReadCookie::get_Key
  520. Function called from DispInvoke to get keys from a multi-valued
  521. Cookie collection.
  522. Parameters:
  523. vKey VARIANT [in], which parameter to get the key of
  524. pvarReturn VARIANT *, [out] value of the requested parameter
  525. Returns:
  526. S_OK on success, E_FAIL on failure.
  527. ===================================================================*/
  528. STDMETHODIMP CReadCookie::get_Key(VARIANT varKey, VARIANT *pvarReturn)
  529. {
  530. char *szKey; // ascii version of the key
  531. CCookiePair *pPair = NULL; // name and value of cookie in the dictionary
  532. CWCharToMBCS convKey;
  533. STACK_BUFFER( tempCookie, 128);
  534. // Initialize things
  535. //
  536. VariantInit(pvarReturn);
  537. VARIANT *pvarKey = &varKey;
  538. HRESULT hrReturn = S_OK;
  539. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
  540. // produced by IEnumVariant
  541. //
  542. // Use VariantResolveDispatch which will:
  543. //
  544. // * Copy BYREF variants for us using VariantCopyInd
  545. // * handle E_OUTOFMEMORY for us
  546. // * get the default value from an IDispatch, which seems
  547. // like an appropriate conversion.
  548. //
  549. VARIANT varKeyCopy;
  550. VariantInit(&varKeyCopy);
  551. DWORD vt = V_VT(pvarKey);
  552. if ((V_VT(pvarKey) != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  553. {
  554. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  555. goto LExit;
  556. pvarKey = &varKeyCopy;
  557. }
  558. vt = V_VT(pvarKey);
  559. switch (vt)
  560. {
  561. // Bug 95201 support all numberic sub-types
  562. case VT_I1: case VT_I2: case VT_I8:
  563. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  564. case VT_R4: case VT_R8:
  565. // Coerce all integral types to VT_I4
  566. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  567. goto LExit;
  568. // fallthru to VT_I4
  569. case VT_I4:
  570. case VT_BSTR:
  571. break;
  572. case VT_ERROR:
  573. if (V_ERROR(pvarKey) == DISP_E_PARAMNOTFOUND)
  574. {
  575. V_VT(pvarReturn) = VT_BSTR;
  576. // simple value, URLEncoding NOT a good idea in this case
  577. if (m_pCookie->m_szValue)
  578. {
  579. BSTR bstrT;
  580. if (FAILED(SysAllocStringFromSz(m_pCookie->m_szValue, 0, &bstrT,m_pCookie->m_lCodePage)))
  581. {
  582. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_OOM);
  583. hrReturn = E_FAIL;
  584. goto LExit;
  585. }
  586. V_BSTR(pvarReturn) = bstrT;
  587. }
  588. // dictionary value, must URLEncode to prevent '&', '=' from being misinterpreted
  589. else
  590. {
  591. int cbHTTPCookie = m_pCookie->GetHTTPCookieSize();
  592. if (cbHTTPCookie > REQUEST_ALLOC_MAX)
  593. {
  594. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_STACK_OVERFLOW);
  595. hrReturn = E_FAIL;
  596. goto LExit;
  597. }
  598. if (tempCookie.Resize(cbHTTPCookie) == FALSE) {
  599. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_OOM);
  600. hrReturn = E_OUTOFMEMORY;
  601. goto LExit;
  602. }
  603. char *szHTTPCookie = static_cast<char *>(tempCookie.QueryPtr());
  604. m_pCookie->GetHTTPCookie(szHTTPCookie);
  605. BSTR bstrT;
  606. if (FAILED(SysAllocStringFromSz(szHTTPCookie, 0, &bstrT, m_pCookie->m_lCodePage)))
  607. {
  608. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_OOM);
  609. hrReturn = E_FAIL;
  610. goto LExit;
  611. }
  612. V_BSTR(pvarReturn) = bstrT;
  613. }
  614. goto LExit;
  615. }
  616. default:
  617. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_EXPECTING_STR);
  618. hrReturn = E_FAIL;
  619. goto LExit;
  620. }
  621. if (vt == VT_BSTR)
  622. {
  623. // convert the key to ANSI
  624. if (V_BSTR(pvarKey)) {
  625. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey),m_pCookie->m_lCodePage))) {
  626. goto LExit;
  627. }
  628. else {
  629. szKey = convKey.GetString();
  630. }
  631. }
  632. else {
  633. szKey = "";
  634. }
  635. // Look up the key in the Cookie.
  636. pPair = static_cast<CCookiePair *>(m_pCookie->m_mpszValues.FindElem(szKey, strlen(szKey)));
  637. }
  638. else
  639. {
  640. // Look up item by index
  641. int iCount;
  642. iCount = V_I4(pvarKey);
  643. if ((iCount < 1) ||
  644. (m_pCookie->m_mpszValues.Count() == 0) ||
  645. (iCount > (int) m_pCookie->m_mpszValues.Count() ))
  646. {
  647. hrReturn = E_FAIL;
  648. ExceptionId(IID_IReadCookie, IDE_COOKIE, IDE_BAD_ARRAY_INDEX);
  649. goto LExit;
  650. }
  651. pPair = static_cast<CCookiePair *>(m_pCookie->m_mpszValues.Head());
  652. while((iCount > 1) && (pPair != NULL))
  653. {
  654. pPair = static_cast<CCookiePair *>(pPair->m_pNext);
  655. iCount--;
  656. }
  657. }
  658. if (pPair)
  659. {
  660. // Create a BSTR containing the key for this variant
  661. BSTR bstrT;
  662. SysAllocStringFromSz((CHAR *)pPair->m_pKey, 0, &bstrT, m_pCookie->m_lCodePage);
  663. if (!bstrT)
  664. return E_OUTOFMEMORY;
  665. V_VT(pvarReturn) = VT_BSTR;
  666. V_BSTR(pvarReturn) = bstrT;
  667. }
  668. LExit:
  669. VariantClear(&varKeyCopy);
  670. return hrReturn;
  671. }
  672. /*------------------------------------------------------------------
  673. * C C o o k i e
  674. */
  675. /*===================================================================
  676. CCookie::CCookie
  677. constructor
  678. ===================================================================*/
  679. CCookie::CCookie(CIsapiReqInfo *pIReq, UINT lCodePage, IUnknown *pUnkOuter, PFNDESTROYED pfnDestroy)
  680. : m_WriteCookieInterface(this),
  681. m_ReadCookieInterface(this),
  682. m_CookieSupportErrorInfo(this)
  683. {
  684. m_szValue = NULL;
  685. m_tExpires = -1;
  686. m_szDomain = NULL;
  687. m_szPath = NULL;
  688. m_fSecure = FALSE;
  689. m_fDirty = FALSE;
  690. m_fDuplicate = FALSE;
  691. m_pfnDestroy = pfnDestroy;
  692. m_pIReq = pIReq;
  693. m_lCodePage = lCodePage;
  694. m_cRefs = 1;
  695. }
  696. /*===================================================================
  697. CCookie::~CCookie
  698. Destructor
  699. ===================================================================*/
  700. CCookie::~CCookie()
  701. {
  702. CCookiePair *pNukePair = static_cast<CCookiePair *>(m_mpszValues.Head());
  703. while (pNukePair != NULL)
  704. {
  705. CCookiePair *pNext = static_cast<CCookiePair *>(pNukePair->m_pNext);
  706. delete pNukePair;
  707. pNukePair = pNext;
  708. }
  709. m_mpszValues.UnInit();
  710. if (m_fDuplicate)
  711. free(m_szValue);
  712. if (m_szDomain) free(m_szDomain);
  713. if (m_szPath) free(m_szPath);
  714. }
  715. /*===================================================================
  716. CCookie::Init
  717. initialize the cookie. This initializes the cookie's value hashing
  718. table
  719. ===================================================================*/
  720. HRESULT CCookie::Init()
  721. {
  722. HRESULT hr = S_OK;
  723. TCHAR pathInfo[MAX_PATH];
  724. #if UNICODE
  725. CWCharToMBCS convStr;
  726. #endif
  727. if (FAILED(hr = m_mpszValues.Init(7)));
  728. // it would be nice if we could use the application path from the metabase,
  729. // but because of case sensitivity issues, we can't. The safest bet is
  730. // to use the request's path info up to the length of the application's
  731. // pathinfo.
  732. else if (FAILED(hr=FindApplicationPath(m_pIReq, pathInfo, sizeof(pathInfo))));
  733. #if UNICODE
  734. else if (FAILED(hr = convStr.Init(m_pIReq->QueryPszPathInfo(), m_lCodePage, _tcslen(pathInfo))));
  735. else {
  736. m_szPath = convStr.GetString(TRUE);
  737. }
  738. #else
  739. else {
  740. int cchPathInfo = _tcslen(pathInfo);
  741. if (!(m_szPath = (char *)malloc(cchPathInfo+1))) {
  742. hr = E_OUTOFMEMORY;
  743. }
  744. else {
  745. memcpy(m_szPath, pathInfo, cchPathInfo+1);
  746. }
  747. }
  748. #endif
  749. return hr;
  750. }
  751. /*===================================================================
  752. CCookie::QueryInterface
  753. CCookie::AddRef
  754. CCookie::Release
  755. IUnknown members for CCookie object.
  756. Note on CCookie::QueryInterface: The Query for IDispatch is
  757. ambiguous because it can either refer to IReadCookie or
  758. IWriteCookie. To resolve this, we resolve requests for IDispatch
  759. to IReadCookie. The rationale for this is that the code in
  760. request.cpp calls QueryInterface for a generic IDispatch pointer
  761. (because the collection is heterogenous) The Response.Cookies
  762. collection is homogeneous and so only calls QueryInterface for
  763. IWriteCookie.
  764. ===================================================================*/
  765. STDMETHODIMP CCookie::QueryInterface(const IID &idInterface, void **ppvObj)
  766. {
  767. if (idInterface == IID_IUnknown)
  768. *ppvObj = this;
  769. else if (idInterface == IID_IReadCookie || idInterface == IID_IDispatch)
  770. *ppvObj = &m_ReadCookieInterface;
  771. else if (idInterface == IID_IWriteCookie)
  772. *ppvObj = &m_WriteCookieInterface;
  773. else if (idInterface == IID_ISupportErrorInfo)
  774. *ppvObj = &m_CookieSupportErrorInfo;
  775. else
  776. *ppvObj = NULL;
  777. if (*ppvObj != NULL)
  778. {
  779. static_cast<IUnknown *>(*ppvObj)->AddRef();
  780. return S_OK;
  781. }
  782. return ResultFromScode(E_NOINTERFACE);
  783. }
  784. STDMETHODIMP_(ULONG) CCookie::AddRef()
  785. {
  786. return ++m_cRefs;
  787. }
  788. STDMETHODIMP_(ULONG) CCookie::Release(void)
  789. {
  790. if (--m_cRefs != 0)
  791. return m_cRefs;
  792. if (m_pfnDestroy != NULL)
  793. (*m_pfnDestroy)();
  794. delete this;
  795. return 0;
  796. }
  797. /*===================================================================
  798. CCookie::AddValue
  799. Set the cookie's primary value. One you set the primary value,
  800. you can't reset it.
  801. ===================================================================*/
  802. HRESULT CCookie::AddValue(char *szValue, BOOL fDuplicate)
  803. {
  804. if (m_szValue != NULL) // cookie already is marked as single-valued
  805. return E_FAIL;
  806. if (m_mpszValues.Count() != 0) // cookie already has a value
  807. return E_FAIL;
  808. if (fDuplicate)
  809. {
  810. char *szNew = (char *)malloc(strlen(szValue) + 1);
  811. if (szNew == NULL)
  812. return E_OUTOFMEMORY;
  813. m_szValue = strcpy(szNew, szValue);
  814. }
  815. else
  816. m_szValue = szValue;
  817. m_fDuplicate = fDuplicate;
  818. return S_OK;
  819. }
  820. /*===================================================================
  821. CCookie::AddKeyAndValue
  822. Add a key and value pair to the Cookie's dictionary. It fails
  823. if the cookie has a primary value already set. It will overwrite
  824. the value if the key already exists.
  825. ===================================================================*/
  826. HRESULT CCookie::AddKeyAndValue(char *szKey, char *szValue, BOOL fDuplicate)
  827. {
  828. if (m_szValue != NULL)
  829. return E_FAIL;
  830. delete static_cast<CCookiePair *>(m_mpszValues.DeleteElem(szKey, strlen(szKey)));
  831. CCookiePair *pCookiePair = new CCookiePair;
  832. if (pCookiePair == NULL)
  833. return E_OUTOFMEMORY;
  834. if (FAILED(pCookiePair->Init(szKey, szValue, fDuplicate)))
  835. return E_FAIL;
  836. m_mpszValues.AddElem(pCookiePair);
  837. return S_OK;
  838. }
  839. /*===================================================================
  840. CCookie::GetHTTPCookieSize
  841. Return the number of bytes required for the expansion of the HTTP_COOKIE variable
  842. ===================================================================*/
  843. size_t CCookie::GetHTTPCookieSize()
  844. {
  845. if (m_szValue)
  846. return URLEncodeLen(m_szValue);
  847. else
  848. {
  849. int cbValue = 1;
  850. CCookiePair *pPair = static_cast<CCookiePair *>(m_mpszValues.Head());
  851. while (pPair)
  852. {
  853. // Add size of the URL Encoded key, a character for the '=', and a
  854. // character for the '&' or the NUL terminator. URLEncodeLen
  855. // returns the size + 1, so the two calls to URLEncodeLen() add the
  856. // two characters we need.
  857. //
  858. cbValue += URLEncodeLen(reinterpret_cast<char *>(pPair->m_pKey)) + URLEncodeLen(pPair->m_szValue);
  859. pPair = static_cast<CCookiePair *>(pPair->m_pNext);
  860. }
  861. return cbValue;
  862. }
  863. }
  864. /*===================================================================
  865. CCookie::GetHTTPCookie
  866. Return the URL Encoded value a single cookie
  867. Parameters:
  868. szBuffer - pointer to the destination buffer to store the
  869. URL encoded value
  870. Returns:
  871. Returns a pointer to the terminating NUL character.
  872. ===================================================================*/
  873. char *CCookie::GetHTTPCookie(char *szBuffer)
  874. {
  875. if (m_szValue)
  876. return URLEncode(szBuffer, m_szValue);
  877. else
  878. {
  879. char *szDest = szBuffer;
  880. *szDest = '\0';
  881. CCookiePair *pPair = static_cast<CCookiePair *>(m_mpszValues.Head());
  882. while (pPair)
  883. {
  884. // Write <name>=<value> string
  885. szDest = URLEncode(szDest, reinterpret_cast<char *>(pPair->m_pKey));
  886. *szDest++ = '=';
  887. szDest = URLEncode(szDest, pPair->m_szValue);
  888. // Advance
  889. pPair = static_cast<CCookiePair *>(pPair->m_pNext);
  890. // Append '&' if there's another one following
  891. if (pPair)
  892. *szDest++ = '&';
  893. }
  894. Assert (*szDest == '\0'); // make sure we are nul-terminated
  895. return szDest;
  896. }
  897. }
  898. /*===================================================================
  899. CCookie::GetCookieHeaderSize
  900. Return the number of bytes required to allocate for the "Set-Cookie" header.
  901. Parameters:
  902. szName - the name of the cookie (the size of the name is added to the value)
  903. Returns:
  904. Returns 0 if *this does not contain a cookie value.
  905. ===================================================================*/
  906. size_t CCookie::GetCookieHeaderSize(const char *szName)
  907. {
  908. int cbCookie = sizeof "Set-Cookie: "; // initialize and add NUL terminator now
  909. // Add size of the URL Encoded name, a character for the '=', and the size
  910. // of the URL Encoded cookie value. URLEncodeLen, and GetHttpCookieSize
  911. // compensate for the NUL terminator, so we actually SUBTRACT 1. (-2 for
  912. // these two function calls, +1 for the '=' sign
  913. //
  914. cbCookie += URLEncodeLen(szName) + GetHTTPCookieSize() - 1;
  915. if (m_tExpires != -1)
  916. cbCookie += (sizeof "; expires=") + DATE_STRING_SIZE - 1;
  917. // BUG 250 - DBCS External
  918. // ASP does not URLEncode the domain and path attributes, which was noticed
  919. // during localizaiton.
  920. //
  921. // NOTE: URLEncodeLen and sizeof both add a space for the nul terminator,
  922. // so we subtract 2 to compensate.
  923. //
  924. if (m_szDomain)
  925. cbCookie += (sizeof "; domain=") + DBCSEncodeLen(m_szDomain) - 2;
  926. cbCookie += (sizeof "; path=") + DBCSEncodeLen(m_szPath) - 2;
  927. if (m_fSecure)
  928. cbCookie += (sizeof "; secure") - 1;
  929. return cbCookie;
  930. }
  931. /*===================================================================
  932. CCookie::GetCookieHeader
  933. Construct the appropriate "Set-Cookie" header for a cookie.
  934. Parameters:
  935. szName - the name of the cookie (the size of the name is added to the value)
  936. Returns:
  937. Returns 0 if *this does not contain a cookie value.
  938. ===================================================================*/
  939. char *CCookie::GetCookieHeader(const char *szName, char *szBuffer)
  940. {
  941. // write out the cookie name and value
  942. //
  943. char *szDest = strcpyExA(szBuffer, "Set-Cookie: ");
  944. szDest = URLEncode(szDest, szName);
  945. szDest = strcpyExA(szDest, "=");
  946. szDest = GetHTTPCookie(szDest);
  947. if (m_tExpires != -1) {
  948. char szExpires[DATE_STRING_SIZE];
  949. CTimeToStringGMT(&m_tExpires, szExpires, TRUE);
  950. szDest = strcpyExA(szDest, "; expires=");
  951. szDest = strcpyExA(szDest, szExpires);
  952. }
  953. if (m_szDomain) {
  954. szDest = strcpyExA(szDest, "; domain=");
  955. szDest = DBCSEncode(szDest, m_szDomain);
  956. }
  957. szDest = strcpyExA(szDest, "; path=");
  958. szDest = DBCSEncode(szDest, m_szPath);
  959. if (m_fSecure)
  960. szDest = strcpyExA(szDest, "; secure");
  961. return szDest;
  962. }
  963. /*------------------------------------------------------------------
  964. * C C o o k i e P a i r
  965. */
  966. /*===================================================================
  967. CCookiePair::CCookiePair
  968. constructor
  969. ===================================================================*/
  970. CCookiePair::CCookiePair()
  971. {
  972. m_fDuplicate = FALSE;
  973. m_szValue = NULL;
  974. }
  975. /*===================================================================
  976. CCookiePair::Init
  977. Initialize the cookie pair with a key and a value. Optionally,
  978. it will copy the strings as well.
  979. ===================================================================*/
  980. HRESULT CCookiePair::Init(const char *szKey, const char *szValue, BOOL fDuplicate)
  981. {
  982. m_fDuplicate = fDuplicate;
  983. if (fDuplicate)
  984. {
  985. char *szNewKey = (char *)malloc(strlen(szKey) + 1);
  986. if (szNewKey == NULL)
  987. return E_OUTOFMEMORY;
  988. char *szNewValue = (char *)malloc(strlen(szValue) + 1);
  989. if (szNewValue == NULL)
  990. {
  991. free(szNewKey);
  992. return E_OUTOFMEMORY;
  993. }
  994. if (FAILED(CLinkElem::Init(strcpy(szNewKey, szKey), strlen(szKey))))
  995. {
  996. free(szNewKey);
  997. free(szNewValue);
  998. return E_FAIL;
  999. }
  1000. m_szValue = strcpy(szNewValue, szValue);
  1001. }
  1002. else
  1003. {
  1004. if (FAILED(CLinkElem::Init(const_cast<char *>(szKey), strlen(szKey))))
  1005. return E_FAIL;
  1006. m_szValue = const_cast<char *>(szValue);
  1007. }
  1008. return S_OK;
  1009. }
  1010. /*===================================================================
  1011. CCookiePair::~CCookiePair
  1012. destructor
  1013. ===================================================================*/
  1014. CCookiePair::~CCookiePair()
  1015. {
  1016. if (m_fDuplicate)
  1017. {
  1018. if (m_pKey) free(m_pKey);
  1019. if (m_szValue) free(m_szValue);
  1020. }
  1021. }
  1022. /*------------------------------------------------------------------
  1023. * C C o o k i e I t e r a t o r
  1024. */
  1025. /*===================================================================
  1026. CCookieIterator::CCookieIterator
  1027. Constructor
  1028. ===================================================================*/
  1029. CCookieIterator::CCookieIterator(CCookie *pCookie)
  1030. {
  1031. m_pCookie = pCookie;
  1032. m_pCurrent = static_cast<CCookiePair *>(m_pCookie->m_mpszValues.Head());
  1033. m_cRefs = 1;
  1034. m_pCookie->AddRef();
  1035. }
  1036. /*===================================================================
  1037. CCookieIterator::CCookieIterator
  1038. Destructor
  1039. ===================================================================*/
  1040. CCookieIterator::~CCookieIterator()
  1041. {
  1042. m_pCookie->Release();
  1043. }
  1044. /*===================================================================
  1045. CCookieIterator::QueryInterface
  1046. CCookieIterator::AddRef
  1047. CCookieIterator::Release
  1048. IUnknown members for CServVarsIterator object.
  1049. ===================================================================*/
  1050. STDMETHODIMP CCookieIterator::QueryInterface(REFIID iid, void **ppvObj)
  1051. {
  1052. if (iid == IID_IUnknown || iid == IID_IEnumVARIANT)
  1053. {
  1054. AddRef();
  1055. *ppvObj = this;
  1056. return S_OK;
  1057. }
  1058. *ppvObj = NULL;
  1059. return E_NOINTERFACE;
  1060. }
  1061. STDMETHODIMP_(ULONG) CCookieIterator::AddRef()
  1062. {
  1063. return ++m_cRefs;
  1064. }
  1065. STDMETHODIMP_(ULONG) CCookieIterator::Release()
  1066. {
  1067. if (--m_cRefs > 0)
  1068. return m_cRefs;
  1069. delete this;
  1070. return 0;
  1071. }
  1072. /*===================================================================
  1073. CCookieIterator::Clone
  1074. Clone this iterator (standard method)
  1075. ===================================================================*/
  1076. STDMETHODIMP CCookieIterator::Clone(IEnumVARIANT **ppEnumReturn)
  1077. {
  1078. CCookieIterator *pNewIterator = new CCookieIterator(m_pCookie);
  1079. if (pNewIterator == NULL)
  1080. return E_OUTOFMEMORY;
  1081. // new iterator should point to same location as this.
  1082. pNewIterator->m_pCurrent = m_pCurrent;
  1083. *ppEnumReturn = pNewIterator;
  1084. return S_OK;
  1085. }
  1086. /*===================================================================
  1087. CCookieIterator::Next
  1088. Get next value (standard method)
  1089. To rehash standard OLE semantics:
  1090. We get the next "cElements" from the collection and store them
  1091. in "rgVariant" which holds at least "cElements" items. On
  1092. return "*pcElementsFetched" contains the actual number of elements
  1093. stored. Returns S_FALSE if less than "cElements" were stored, S_OK
  1094. otherwise.
  1095. ===================================================================*/
  1096. STDMETHODIMP CCookieIterator::Next(unsigned long cElementsRequested, VARIANT *rgVariant, unsigned long *pcElementsFetched)
  1097. {
  1098. // give a valid pointer value to 'pcElementsFetched'
  1099. //
  1100. unsigned long cElementsFetched;
  1101. if (pcElementsFetched == NULL)
  1102. pcElementsFetched = &cElementsFetched;
  1103. // Loop through the collection until either we reach the end or
  1104. // cElements becomes zero
  1105. //
  1106. unsigned long cElements = cElementsRequested;
  1107. *pcElementsFetched = 0;
  1108. while (cElements > 0 && m_pCurrent != NULL)
  1109. {
  1110. BSTR bstrT;
  1111. if (FAILED(SysAllocStringFromSz(reinterpret_cast<char *>(m_pCurrent->m_pKey), 0, &bstrT, m_pCookie->m_lCodePage)))
  1112. return E_OUTOFMEMORY;
  1113. V_VT(rgVariant) = VT_BSTR;
  1114. V_BSTR(rgVariant) = bstrT;
  1115. ++rgVariant;
  1116. --cElements;
  1117. ++*pcElementsFetched;
  1118. m_pCurrent = static_cast<CCookiePair *>(m_pCurrent->m_pNext);
  1119. }
  1120. // initialize the remaining variants
  1121. //
  1122. while (cElements-- > 0)
  1123. VariantInit(rgVariant++);
  1124. return (*pcElementsFetched == cElementsRequested)? S_OK : S_FALSE;
  1125. }
  1126. /*===================================================================
  1127. CCookieIterator::Skip
  1128. Skip items (standard method)
  1129. To rehash standard OLE semantics:
  1130. We skip over the next "cElements" from the collection.
  1131. Returns S_FALSE if less than "cElements" were skipped, S_OK
  1132. otherwise.
  1133. ===================================================================*/
  1134. STDMETHODIMP CCookieIterator::Skip(unsigned long cElements)
  1135. {
  1136. /* Loop through the collection until either we reach the end or
  1137. * cElements becomes zero
  1138. */
  1139. while (cElements > 0 && m_pCurrent != NULL)
  1140. {
  1141. --cElements;
  1142. m_pCurrent = static_cast<CCookiePair *>(m_pCurrent->m_pNext);
  1143. }
  1144. return (cElements == 0)? S_OK : S_FALSE;
  1145. }
  1146. /*===================================================================
  1147. CCookieIterator::Reset
  1148. Reset the iterator (standard method)
  1149. ===================================================================*/
  1150. STDMETHODIMP CCookieIterator::Reset()
  1151. {
  1152. m_pCurrent = static_cast<CCookiePair *>(m_pCookie->m_mpszValues.Head());
  1153. return S_OK;
  1154. }