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

383 lines
9.6 KiB

  1. // BrowCap.cpp : Implementation of CBrowserCap
  2. #include "stdafx.h"
  3. #include "BrwCap.h"
  4. #include "BrowCap.h"
  5. #include "CapMap.h"
  6. #include "context.h"
  7. static const DISPID FIRST_DYNAMIC_DISPID = 10000;
  8. #ifdef DBG
  9. #undef THIS_FILE
  10. static char THIS_FILE[]=__FILE__;
  11. #define new DEBUG_NEW
  12. #endif
  13. #define MAX_RESSTRINGSIZE 512
  14. /////////////////////////////////////////////////////////////////////////////
  15. // CBrowserFactory
  16. HRESULT CBrowserFactory::QueryInterface(const IID &riid, void **ppvObj)
  17. {
  18. if (riid == IID_IUnknown || riid == IID_IClassFactory)
  19. {
  20. *ppvObj = this;
  21. AddRef();
  22. return S_OK;
  23. }
  24. else
  25. {
  26. *ppvObj = NULL;
  27. return E_NOINTERFACE;
  28. }
  29. }
  30. ULONG CBrowserFactory::AddRef()
  31. {
  32. InterlockedIncrement(&m_cRefs);
  33. return m_cRefs;
  34. }
  35. ULONG CBrowserFactory::Release()
  36. {
  37. if (InterlockedDecrement(&m_cRefs) == 0)
  38. {
  39. delete this;
  40. return 0;
  41. }
  42. else
  43. return m_cRefs;
  44. }
  45. HRESULT CBrowserFactory::CreateInstance(IUnknown *pUnkOuter, const IID &riid, void **ppvObj)
  46. {
  47. USES_CONVERSION;
  48. HRESULT hr;
  49. CContext cxt;
  50. IRequestDictionary *pDictCookies = NULL;
  51. if (FAILED(hr = cxt.Init(CContext::get_Request)))
  52. return hr;
  53. String strBrowser;
  54. CComPtr<IDispatch> piDispUserAgent;
  55. CComVariant varUserAgent;
  56. if (FAILED(hr = cxt.Request()->get_Item(L"HTTP_USER_AGENT", &piDispUserAgent)))
  57. return hr;
  58. varUserAgent = piDispUserAgent;
  59. varUserAgent.ChangeType(VT_BSTR);
  60. strBrowser = OLE2T(V_BSTR(&varUserAgent));
  61. _Module.Lock();
  62. CBrowserCap *pBrowserCapObj = _Module.CapMap()->LookUp(strBrowser.c_str());
  63. _Module.Unlock();
  64. if (pBrowserCapObj == NULL)
  65. return E_FAIL;
  66. // IF there is a cookie, then clone the browscap object we got and add cookie properties
  67. // Otherwise, when there is no cookie, QueryInterface for "riid".
  68. //
  69. CComVariant varBrowscapCookie;
  70. if (SUCCEEDED(cxt.Request()->get_Cookies(&pDictCookies)))
  71. {
  72. IReadCookie *pReadCookie = NULL; // Intermediate dictionary ptr
  73. CComVariant varCookieName; // current key
  74. CComVariant varCookieValue; // value of "varCookieName"
  75. IEnumVARIANT *pEnumKeys;
  76. // Get the BROWSCAP cookie
  77. if (FAILED(pDictCookies->get_Item(CComVariant(L"BROWSCAP"), &varBrowscapCookie)))
  78. goto LReleaseDict;
  79. // If the cookie exists, it will be an IDispatch. Otherwise it will be VT_EMPTY
  80. if (V_VT(&varBrowscapCookie) == VT_DISPATCH)
  81. {
  82. // Clone the cookie. Since LookUp DID NOT AddRef(), we don't need to Release()
  83. // the pBrowserCapObj. Thus cloning to the same pointer is OK here.
  84. // the clone will have a refcount of zero, so the QueryInterface call at the
  85. // end is also correct.
  86. //
  87. if (FAILED(hr = pBrowserCapObj->Clone(&pBrowserCapObj)))
  88. goto LReleaseDict;
  89. hr = V_DISPATCH(&varBrowscapCookie)->QueryInterface(IID_IReadCookie, reinterpret_cast<void **>(&pReadCookie));
  90. _ASSERT (SUCCEEDED(hr));
  91. // Iterate over all cookie values
  92. if (FAILED(hr = pReadCookie->get__NewEnum(reinterpret_cast<IUnknown **>(&pEnumKeys))))
  93. goto LReleaseDict;
  94. while (pEnumKeys->Next(1, &varCookieName, NULL) == S_OK)
  95. {
  96. // Expecting a string
  97. _ASSERT (V_VT(&varCookieName) == VT_BSTR);
  98. // read the cookie value -- better succeed
  99. hr = pReadCookie->get_Item(varCookieName, &varCookieValue);
  100. _ASSERT (SUCCEEDED(hr) && V_VT(&varCookieValue) == VT_BSTR);
  101. // Store key & value in dictionary (over-rides previous settings)
  102. pBrowserCapObj->AddProperty(OLE2T(V_BSTR(&varCookieName)), OLE2T(V_BSTR(&varCookieValue)), TRUE);
  103. // Clear "varCookieName" to prevent leak. Since we pass address to Next(), C++ cleanup won't happen on its own
  104. varCookieName.Clear();
  105. }
  106. pEnumKeys->Release();
  107. }
  108. LReleaseDict:
  109. pDictCookies->Release();
  110. if (pReadCookie)
  111. pReadCookie->Release();
  112. if (FAILED(hr))
  113. return hr;
  114. }
  115. return pBrowserCapObj->QueryInterface(riid, ppvObj);
  116. }
  117. /////////////////////////////////////////////////////////////////////////////
  118. // CBrowserCap
  119. CBrowserCap::CBrowserCap()
  120. {
  121. }
  122. CBrowserCap::~CBrowserCap()
  123. {
  124. }
  125. STDMETHODIMP CBrowserCap::InterfaceSupportsErrorInfo(REFIID riid)
  126. {
  127. static const IID* arr[] =
  128. {
  129. &IID_IBrowserCap,
  130. };
  131. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  132. {
  133. if (InlineIsEqualGUID(*arr[i],riid))
  134. return S_OK;
  135. }
  136. return S_FALSE;
  137. }
  138. STDMETHODIMP
  139. CBrowserCap::Invoke(
  140. DISPID dispidMember,
  141. REFIID riid,
  142. LCID lcid,
  143. WORD wFlags,
  144. DISPPARAMS* pdispparams,
  145. VARIANT* pvarResult,
  146. EXCEPINFO* pexcepinfo,
  147. UINT* puArgErr )
  148. {
  149. HRESULT rc;
  150. try
  151. {
  152. USES_CONVERSION;
  153. if ( dispidMember >= FIRST_DYNAMIC_DISPID )
  154. {
  155. if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
  156. {
  157. char szClass[25], szDescription[80];
  158. LoadString(IDS_ERROR_SOURCE, szClass);
  159. LoadString(IDS_ERROR_PROP_RO, szDescription);
  160. pexcepinfo->scode = E_FAIL;
  161. pexcepinfo->bstrSource = SysAllocString(T2OLE(szClass));
  162. pexcepinfo->bstrDescription = SysAllocString(T2OLE(szDescription));
  163. pexcepinfo->wCode = WORD(dispidMember);
  164. return DISP_E_EXCEPTION;
  165. }
  166. UINT i = dispidMember - FIRST_DYNAMIC_DISPID;
  167. CLock csT(m_strmapProperties);
  168. if (i < m_strmapProperties.size()) // dynamic property -- get value
  169. {
  170. rc = VariantCopy(pvarResult, &m_strmapProperties[i]);
  171. }
  172. else // property does not exist, return empty
  173. {
  174. V_VT(pvarResult) = VT_BSTR;
  175. V_BSTR(pvarResult) = SysAllocString(L"unknown");
  176. rc = S_OK;
  177. }
  178. }
  179. else
  180. {
  181. rc = IDispatchImpl<IBrowserCap, &IID_IBrowserCap, &LIBID_BrowserType>::Invoke(
  182. dispidMember,
  183. riid,
  184. lcid,
  185. wFlags,
  186. pdispparams,
  187. pvarResult,
  188. pexcepinfo,
  189. puArgErr);
  190. }
  191. }
  192. catch( _com_error& ce )
  193. {
  194. rc = ce.Error();
  195. }
  196. catch( ... )
  197. {
  198. rc = E_FAIL;
  199. }
  200. return rc;
  201. }
  202. STDMETHODIMP
  203. CBrowserCap::GetIDsOfNames(
  204. REFIID riid,
  205. LPOLESTR* rgszNames,
  206. UINT cNames,
  207. LCID lcid,
  208. DISPID* rgdispid )
  209. {
  210. HRESULT rc = E_FAIL;
  211. try
  212. {
  213. // first get the disp IDs of the known methods
  214. rc = IDispatchImpl<IBrowserCap, &IID_IBrowserCap, &LIBID_BrowserType>::GetIDsOfNames(
  215. riid,
  216. rgszNames,
  217. cNames,
  218. lcid,
  219. rgdispid);
  220. if (rc == DISP_E_UNKNOWNNAME)
  221. {
  222. // IDs for other methods are based on property list ID offset after last known method ID
  223. // this allows a client to say browsercap.Cookies instead of browsercap( "Cookies" ).
  224. // A property that does not exist is set to a value beyond the end of the strmap.
  225. // (this tells Invoke not to bother with "get_Value") This trick only works because
  226. // properties are all set at creation time and cannot be added later.
  227. //
  228. rc = S_OK;
  229. for (UINT i = 0; i < cNames; i++)
  230. if (rgdispid[i] == DISPID_UNKNOWN &&
  231. (rgdispid[i] = DispatchID(rgszNames[i])) == DISPID_UNKNOWN)
  232. rc = DISP_E_UNKNOWNNAME;
  233. }
  234. }
  235. catch (_com_error& ce)
  236. {
  237. rc = ce.Error();
  238. }
  239. catch (...)
  240. {
  241. rc = E_FAIL;
  242. }
  243. return rc;
  244. }
  245. void CBrowserCap::AddProperty(TCHAR *szKey, TCHAR *szValue, BOOL fOverwriteProperty)
  246. {
  247. USES_CONVERSION;
  248. CComVariant varT;
  249. // See if the key already exists, since the first key written into the
  250. // dictionary wins. (This is to make sure that the parent UA string property
  251. // never overwrites the child.)
  252. //
  253. _tcslwr(szKey);
  254. if (!fOverwriteProperty && m_strmapProperties.find(szKey) != m_strmapProperties.end())
  255. return;
  256. if (szValue[0] == _T('#'))
  257. varT = _ttol(szValue+1);
  258. else if (_tcsncicmp(szValue, _T("TRUE"), 5) == 0)
  259. varT = true;
  260. else if (_tcsncicmp(szValue, _T("FALSE"), 6) == 0)
  261. varT = false;
  262. else
  263. varT = T2CW(szValue);
  264. m_strmapProperties[szKey] = varT;
  265. }
  266. STDMETHODIMP CBrowserCap::get_Value(BSTR bstrName, VARIANT * pVal)
  267. {
  268. USES_CONVERSION;
  269. CLock csT(m_strmapProperties);
  270. TSafeStringMap<CComVariant>::iterator itProp = m_strmapProperties.find(_tcslwr(OLE2T(bstrName)));
  271. if (itProp == m_strmapProperties.end())
  272. {
  273. V_VT(pVal) = VT_BSTR;
  274. V_BSTR(pVal) = SysAllocString(L"unknown");
  275. return V_BSTR(pVal) != NULL? S_OK : E_OUTOFMEMORY;
  276. }
  277. else
  278. return VariantCopy(pVal, &(*itProp).second);
  279. }
  280. DISPID
  281. CBrowserCap::DispatchID(
  282. LPOLESTR szName )
  283. {
  284. USES_CONVERSION;
  285. static const TCHAR *szOnStartPage = _T("onstartpage");
  286. static const TCHAR *szOnEndPage = _T("onendpage");
  287. TCHAR *szT = _tcslwr(OLE2T(szName));
  288. if ((szT == NULL)
  289. || (_tcscmp(szT, szOnStartPage) == 0)
  290. || (_tcscmp(szT, szOnEndPage) == 0))
  291. return DISPID_UNKNOWN;
  292. CLock csT(m_strmapProperties);
  293. String strName = szT;
  294. TSafeStringMap<CComVariant>::iterator iter = m_strmapProperties.find(strName);
  295. if (iter == m_strmapProperties.end())
  296. return m_strmapProperties.size() + FIRST_DYNAMIC_DISPID;
  297. else
  298. return (iter - m_strmapProperties.begin()) + FIRST_DYNAMIC_DISPID;
  299. }
  300. HRESULT CBrowserCap::Clone(CBrowserCap **ppBrowserCapCopy)
  301. {
  302. if ((*ppBrowserCapCopy = new CComObject<CBrowserCap>) == NULL)
  303. return E_OUTOFMEMORY;
  304. (*ppBrowserCapCopy)->FinalConstruct(); // Create FTM
  305. CLock csT(m_strmapProperties);
  306. TSafeStringMap<CComVariant>::iterator iter;
  307. for (iter = m_strmapProperties.begin(); iter < m_strmapProperties.end(); ++iter)
  308. (*ppBrowserCapCopy)->m_strmapProperties[(*iter).first] = (*iter).second;
  309. return S_OK;
  310. }
  311. void
  312. CBrowserCap::LoadString(
  313. UINT nID,
  314. TCHAR *szText
  315. )
  316. {
  317. if (::LoadString(_Module.GetResourceInstance(), nID, szText, MAX_RESSTRINGSIZE) == 0)
  318. {
  319. _tcscpy(szText, _T("?? Unknown (Can't find resource)"));
  320. }
  321. }