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
383 lines
9.6 KiB
// BrowCap.cpp : Implementation of CBrowserCap
|
|
#include "stdafx.h"
|
|
#include "BrwCap.h"
|
|
#include "BrowCap.h"
|
|
#include "CapMap.h"
|
|
#include "context.h"
|
|
|
|
static const DISPID FIRST_DYNAMIC_DISPID = 10000;
|
|
|
|
#ifdef DBG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
#define MAX_RESSTRINGSIZE 512
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CBrowserFactory
|
|
|
|
HRESULT CBrowserFactory::QueryInterface(const IID &riid, void **ppvObj)
|
|
{
|
|
if (riid == IID_IUnknown || riid == IID_IClassFactory)
|
|
{
|
|
*ppvObj = this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
ULONG CBrowserFactory::AddRef()
|
|
{
|
|
InterlockedIncrement(&m_cRefs);
|
|
return m_cRefs;
|
|
}
|
|
|
|
ULONG CBrowserFactory::Release()
|
|
{
|
|
if (InterlockedDecrement(&m_cRefs) == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
return m_cRefs;
|
|
}
|
|
|
|
HRESULT CBrowserFactory::CreateInstance(IUnknown *pUnkOuter, const IID &riid, void **ppvObj)
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
CContext cxt;
|
|
IRequestDictionary *pDictCookies = NULL;
|
|
|
|
if (FAILED(hr = cxt.Init(CContext::get_Request)))
|
|
return hr;
|
|
|
|
String strBrowser;
|
|
CComPtr<IDispatch> piDispUserAgent;
|
|
CComVariant varUserAgent;
|
|
|
|
if (FAILED(hr = cxt.Request()->get_Item(L"HTTP_USER_AGENT", &piDispUserAgent)))
|
|
return hr;
|
|
|
|
varUserAgent = piDispUserAgent;
|
|
varUserAgent.ChangeType(VT_BSTR);
|
|
strBrowser = OLE2T(V_BSTR(&varUserAgent));
|
|
|
|
_Module.Lock();
|
|
CBrowserCap *pBrowserCapObj = _Module.CapMap()->LookUp(strBrowser.c_str());
|
|
_Module.Unlock();
|
|
|
|
if (pBrowserCapObj == NULL)
|
|
return E_FAIL;
|
|
|
|
// IF there is a cookie, then clone the browscap object we got and add cookie properties
|
|
// Otherwise, when there is no cookie, QueryInterface for "riid".
|
|
//
|
|
CComVariant varBrowscapCookie;
|
|
if (SUCCEEDED(cxt.Request()->get_Cookies(&pDictCookies)))
|
|
{
|
|
IReadCookie *pReadCookie = NULL; // Intermediate dictionary ptr
|
|
CComVariant varCookieName; // current key
|
|
CComVariant varCookieValue; // value of "varCookieName"
|
|
IEnumVARIANT *pEnumKeys;
|
|
|
|
|
|
// Get the BROWSCAP cookie
|
|
if (FAILED(pDictCookies->get_Item(CComVariant(L"BROWSCAP"), &varBrowscapCookie)))
|
|
goto LReleaseDict;
|
|
|
|
// If the cookie exists, it will be an IDispatch. Otherwise it will be VT_EMPTY
|
|
if (V_VT(&varBrowscapCookie) == VT_DISPATCH)
|
|
{
|
|
// Clone the cookie. Since LookUp DID NOT AddRef(), we don't need to Release()
|
|
// the pBrowserCapObj. Thus cloning to the same pointer is OK here.
|
|
// the clone will have a refcount of zero, so the QueryInterface call at the
|
|
// end is also correct.
|
|
//
|
|
if (FAILED(hr = pBrowserCapObj->Clone(&pBrowserCapObj)))
|
|
goto LReleaseDict;
|
|
|
|
hr = V_DISPATCH(&varBrowscapCookie)->QueryInterface(IID_IReadCookie, reinterpret_cast<void **>(&pReadCookie));
|
|
_ASSERT (SUCCEEDED(hr));
|
|
|
|
// Iterate over all cookie values
|
|
if (FAILED(hr = pReadCookie->get__NewEnum(reinterpret_cast<IUnknown **>(&pEnumKeys))))
|
|
goto LReleaseDict;
|
|
|
|
while (pEnumKeys->Next(1, &varCookieName, NULL) == S_OK)
|
|
{
|
|
// Expecting a string
|
|
_ASSERT (V_VT(&varCookieName) == VT_BSTR);
|
|
|
|
// read the cookie value -- better succeed
|
|
hr = pReadCookie->get_Item(varCookieName, &varCookieValue);
|
|
_ASSERT (SUCCEEDED(hr) && V_VT(&varCookieValue) == VT_BSTR);
|
|
|
|
// Store key & value in dictionary (over-rides previous settings)
|
|
pBrowserCapObj->AddProperty(OLE2T(V_BSTR(&varCookieName)), OLE2T(V_BSTR(&varCookieValue)), TRUE);
|
|
|
|
// Clear "varCookieName" to prevent leak. Since we pass address to Next(), C++ cleanup won't happen on its own
|
|
varCookieName.Clear();
|
|
}
|
|
|
|
pEnumKeys->Release();
|
|
}
|
|
|
|
LReleaseDict:
|
|
pDictCookies->Release();
|
|
if (pReadCookie)
|
|
pReadCookie->Release();
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
return pBrowserCapObj->QueryInterface(riid, ppvObj);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CBrowserCap
|
|
|
|
CBrowserCap::CBrowserCap()
|
|
{
|
|
}
|
|
|
|
CBrowserCap::~CBrowserCap()
|
|
{
|
|
}
|
|
|
|
STDMETHODIMP CBrowserCap::InterfaceSupportsErrorInfo(REFIID riid)
|
|
{
|
|
static const IID* arr[] =
|
|
{
|
|
&IID_IBrowserCap,
|
|
};
|
|
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
|
|
{
|
|
if (InlineIsEqualGUID(*arr[i],riid))
|
|
return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CBrowserCap::Invoke(
|
|
DISPID dispidMember,
|
|
REFIID riid,
|
|
LCID lcid,
|
|
WORD wFlags,
|
|
DISPPARAMS* pdispparams,
|
|
VARIANT* pvarResult,
|
|
EXCEPINFO* pexcepinfo,
|
|
UINT* puArgErr )
|
|
{
|
|
HRESULT rc;
|
|
try
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
if ( dispidMember >= FIRST_DYNAMIC_DISPID )
|
|
{
|
|
if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
|
|
{
|
|
char szClass[25], szDescription[80];
|
|
LoadString(IDS_ERROR_SOURCE, szClass);
|
|
LoadString(IDS_ERROR_PROP_RO, szDescription);
|
|
|
|
pexcepinfo->scode = E_FAIL;
|
|
pexcepinfo->bstrSource = SysAllocString(T2OLE(szClass));
|
|
pexcepinfo->bstrDescription = SysAllocString(T2OLE(szDescription));
|
|
pexcepinfo->wCode = WORD(dispidMember);
|
|
|
|
return DISP_E_EXCEPTION;
|
|
}
|
|
|
|
UINT i = dispidMember - FIRST_DYNAMIC_DISPID;
|
|
CLock csT(m_strmapProperties);
|
|
|
|
if (i < m_strmapProperties.size()) // dynamic property -- get value
|
|
{
|
|
rc = VariantCopy(pvarResult, &m_strmapProperties[i]);
|
|
}
|
|
else // property does not exist, return empty
|
|
{
|
|
V_VT(pvarResult) = VT_BSTR;
|
|
V_BSTR(pvarResult) = SysAllocString(L"unknown");
|
|
rc = S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = IDispatchImpl<IBrowserCap, &IID_IBrowserCap, &LIBID_BrowserType>::Invoke(
|
|
dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr);
|
|
}
|
|
}
|
|
catch( _com_error& ce )
|
|
{
|
|
rc = ce.Error();
|
|
}
|
|
catch( ... )
|
|
{
|
|
rc = E_FAIL;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CBrowserCap::GetIDsOfNames(
|
|
REFIID riid,
|
|
LPOLESTR* rgszNames,
|
|
UINT cNames,
|
|
LCID lcid,
|
|
DISPID* rgdispid )
|
|
{
|
|
HRESULT rc = E_FAIL;
|
|
try
|
|
{
|
|
// first get the disp IDs of the known methods
|
|
rc = IDispatchImpl<IBrowserCap, &IID_IBrowserCap, &LIBID_BrowserType>::GetIDsOfNames(
|
|
riid,
|
|
rgszNames,
|
|
cNames,
|
|
lcid,
|
|
rgdispid);
|
|
|
|
if (rc == DISP_E_UNKNOWNNAME)
|
|
{
|
|
// IDs for other methods are based on property list ID offset after last known method ID
|
|
// this allows a client to say browsercap.Cookies instead of browsercap( "Cookies" ).
|
|
// A property that does not exist is set to a value beyond the end of the strmap.
|
|
// (this tells Invoke not to bother with "get_Value") This trick only works because
|
|
// properties are all set at creation time and cannot be added later.
|
|
//
|
|
rc = S_OK;
|
|
for (UINT i = 0; i < cNames; i++)
|
|
if (rgdispid[i] == DISPID_UNKNOWN &&
|
|
(rgdispid[i] = DispatchID(rgszNames[i])) == DISPID_UNKNOWN)
|
|
rc = DISP_E_UNKNOWNNAME;
|
|
}
|
|
}
|
|
catch (_com_error& ce)
|
|
{
|
|
rc = ce.Error();
|
|
}
|
|
catch (...)
|
|
{
|
|
rc = E_FAIL;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
void CBrowserCap::AddProperty(TCHAR *szKey, TCHAR *szValue, BOOL fOverwriteProperty)
|
|
{
|
|
USES_CONVERSION;
|
|
CComVariant varT;
|
|
|
|
// See if the key already exists, since the first key written into the
|
|
// dictionary wins. (This is to make sure that the parent UA string property
|
|
// never overwrites the child.)
|
|
//
|
|
_tcslwr(szKey);
|
|
if (!fOverwriteProperty && m_strmapProperties.find(szKey) != m_strmapProperties.end())
|
|
return;
|
|
|
|
if (szValue[0] == _T('#'))
|
|
varT = _ttol(szValue+1);
|
|
|
|
else if (_tcsncicmp(szValue, _T("TRUE"), 5) == 0)
|
|
varT = true;
|
|
|
|
else if (_tcsncicmp(szValue, _T("FALSE"), 6) == 0)
|
|
varT = false;
|
|
|
|
else
|
|
varT = T2CW(szValue);
|
|
|
|
m_strmapProperties[szKey] = varT;
|
|
}
|
|
|
|
STDMETHODIMP CBrowserCap::get_Value(BSTR bstrName, VARIANT * pVal)
|
|
{
|
|
USES_CONVERSION;
|
|
CLock csT(m_strmapProperties);
|
|
|
|
TSafeStringMap<CComVariant>::iterator itProp = m_strmapProperties.find(_tcslwr(OLE2T(bstrName)));
|
|
if (itProp == m_strmapProperties.end())
|
|
{
|
|
V_VT(pVal) = VT_BSTR;
|
|
V_BSTR(pVal) = SysAllocString(L"unknown");
|
|
return V_BSTR(pVal) != NULL? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
return VariantCopy(pVal, &(*itProp).second);
|
|
}
|
|
|
|
DISPID
|
|
CBrowserCap::DispatchID(
|
|
LPOLESTR szName )
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
static const TCHAR *szOnStartPage = _T("onstartpage");
|
|
static const TCHAR *szOnEndPage = _T("onendpage");
|
|
|
|
TCHAR *szT = _tcslwr(OLE2T(szName));
|
|
if ((szT == NULL)
|
|
|| (_tcscmp(szT, szOnStartPage) == 0)
|
|
|| (_tcscmp(szT, szOnEndPage) == 0))
|
|
return DISPID_UNKNOWN;
|
|
|
|
CLock csT(m_strmapProperties);
|
|
String strName = szT;
|
|
TSafeStringMap<CComVariant>::iterator iter = m_strmapProperties.find(strName);
|
|
if (iter == m_strmapProperties.end())
|
|
return m_strmapProperties.size() + FIRST_DYNAMIC_DISPID;
|
|
|
|
else
|
|
return (iter - m_strmapProperties.begin()) + FIRST_DYNAMIC_DISPID;
|
|
}
|
|
|
|
HRESULT CBrowserCap::Clone(CBrowserCap **ppBrowserCapCopy)
|
|
{
|
|
if ((*ppBrowserCapCopy = new CComObject<CBrowserCap>) == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
(*ppBrowserCapCopy)->FinalConstruct(); // Create FTM
|
|
|
|
CLock csT(m_strmapProperties);
|
|
TSafeStringMap<CComVariant>::iterator iter;
|
|
|
|
for (iter = m_strmapProperties.begin(); iter < m_strmapProperties.end(); ++iter)
|
|
(*ppBrowserCapCopy)->m_strmapProperties[(*iter).first] = (*iter).second;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
CBrowserCap::LoadString(
|
|
UINT nID,
|
|
TCHAR *szText
|
|
)
|
|
{
|
|
if (::LoadString(_Module.GetResourceInstance(), nID, szText, MAX_RESSTRINGSIZE) == 0)
|
|
{
|
|
_tcscpy(szText, _T("?? Unknown (Can't find resource)"));
|
|
}
|
|
}
|
|
|