Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14  *     its contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "WebDatabaseManager.h"
     31 #include "WebKitDLL.h"
     32 
     33 #if ENABLE(DATABASE)
     34 
     35 #include "CFDictionaryPropertyBag.h"
     36 #include "COMEnumVariant.h"
     37 #include "MarshallingHelpers.h"
     38 #include "WebNotificationCenter.h"
     39 #include "WebSecurityOrigin.h"
     40 
     41 #include <WebCore/BString.h>
     42 #include <WebCore/COMPtr.h>
     43 #include <WebCore/DatabaseTracker.h>
     44 #include <WebCore/FileSystem.h>
     45 #include <WebCore/SecurityOrigin.h>
     46 
     47 using namespace WebCore;
     48 
     49 static inline bool isEqual(LPCWSTR s1, LPCWSTR s2)
     50 {
     51     return !wcscmp(s1, s2);
     52 }
     53 
     54 class DatabaseDetailsPropertyBag : public IPropertyBag, public Noncopyable {
     55 public:
     56     static DatabaseDetailsPropertyBag* createInstance(const DatabaseDetails&);
     57 
     58     // IUnknown
     59     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
     60     virtual ULONG STDMETHODCALLTYPE AddRef();
     61     virtual ULONG STDMETHODCALLTYPE Release();
     62 
     63     // IPropertyBag
     64     virtual HRESULT STDMETHODCALLTYPE Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog);
     65     virtual HRESULT STDMETHODCALLTYPE Write(LPCOLESTR pszPropName, VARIANT* pVar);
     66 private:
     67     DatabaseDetailsPropertyBag(const DatabaseDetails& details)
     68         : m_refCount(0)
     69         , m_details(details) { }
     70     ~DatabaseDetailsPropertyBag() { }
     71 
     72     ULONG m_refCount;
     73     DatabaseDetails m_details;
     74 };
     75 
     76 // DatabaseDetailsPropertyBag ------------------------------------------------------
     77 DatabaseDetailsPropertyBag* DatabaseDetailsPropertyBag::createInstance(const DatabaseDetails& details)
     78 {
     79     DatabaseDetailsPropertyBag* instance = new DatabaseDetailsPropertyBag(details);
     80     instance->AddRef();
     81     return instance;
     82 }
     83 
     84 // IUnknown ------------------------------------------------------------------------
     85 ULONG STDMETHODCALLTYPE DatabaseDetailsPropertyBag::AddRef()
     86 {
     87     return ++m_refCount;
     88 }
     89 
     90 ULONG STDMETHODCALLTYPE DatabaseDetailsPropertyBag::Release()
     91 {
     92     ULONG newRef = --m_refCount;
     93     if (!newRef)
     94         delete this;
     95 
     96     return newRef;
     97 }
     98 
     99 HRESULT STDMETHODCALLTYPE DatabaseDetailsPropertyBag::QueryInterface(REFIID riid, void** ppvObject)
    100 {
    101     *ppvObject = 0;
    102     if (IsEqualGUID(riid, IID_IUnknown))
    103         *ppvObject = static_cast<DatabaseDetailsPropertyBag*>(this);
    104     else if (IsEqualGUID(riid, IID_IPropertyBag))
    105         *ppvObject = static_cast<DatabaseDetailsPropertyBag*>(this);
    106     else
    107         return E_NOINTERFACE;
    108 
    109     AddRef();
    110     return S_OK;
    111 }
    112 
    113 // IPropertyBag --------------------------------------------------------------------
    114 HRESULT STDMETHODCALLTYPE DatabaseDetailsPropertyBag::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog*)
    115 {
    116     if (!pszPropName || !pVar)
    117         return E_POINTER;
    118 
    119     VariantInit(pVar);
    120 
    121     if (isEqual(pszPropName, WebDatabaseDisplayNameKey)) {
    122         COMVariantSetter<String>::setVariant(pVar, m_details.displayName());
    123         return S_OK;
    124     } else if (isEqual(pszPropName, WebDatabaseExpectedSizeKey)) {
    125         COMVariantSetter<unsigned long long>::setVariant(pVar, m_details.expectedUsage());
    126         return S_OK;
    127     } else if (isEqual(pszPropName, WebDatabaseUsageKey)) {
    128         COMVariantSetter<unsigned long long>::setVariant(pVar, m_details.currentUsage());
    129         return S_OK;
    130     }
    131 
    132     return E_INVALIDARG;
    133 }
    134 
    135 HRESULT STDMETHODCALLTYPE DatabaseDetailsPropertyBag::Write(LPCOLESTR pszPropName, VARIANT* pVar)
    136 {
    137     if (!pszPropName || !pVar)
    138         return E_POINTER;
    139 
    140     return E_FAIL;
    141 }
    142 
    143 static COMPtr<WebDatabaseManager> s_sharedWebDatabaseManager;
    144 
    145 // WebDatabaseManager --------------------------------------------------------------
    146 WebDatabaseManager* WebDatabaseManager::createInstance()
    147 {
    148     WebDatabaseManager* manager = new WebDatabaseManager();
    149     manager->AddRef();
    150     return manager;
    151 }
    152 
    153 WebDatabaseManager::WebDatabaseManager()
    154     : m_refCount(0)
    155 {
    156     gClassCount++;
    157     gClassNameCount.add("WebDatabaseManager");
    158 }
    159 
    160 WebDatabaseManager::~WebDatabaseManager()
    161 {
    162     gClassCount--;
    163     gClassNameCount.remove("WebDatabaseManager");
    164 }
    165 
    166 // IUnknown ------------------------------------------------------------------------
    167 HRESULT STDMETHODCALLTYPE WebDatabaseManager::QueryInterface(REFIID riid, void** ppvObject)
    168 {
    169     *ppvObject = 0;
    170     if (IsEqualGUID(riid, IID_IUnknown))
    171         *ppvObject = static_cast<WebDatabaseManager*>(this);
    172     else if (IsEqualGUID(riid, IID_IWebDatabaseManager))
    173         *ppvObject = static_cast<WebDatabaseManager*>(this);
    174     else
    175         return E_NOINTERFACE;
    176 
    177     AddRef();
    178     return S_OK;
    179 }
    180 
    181 ULONG STDMETHODCALLTYPE WebDatabaseManager::AddRef()
    182 {
    183     return ++m_refCount;
    184 }
    185 
    186 ULONG STDMETHODCALLTYPE WebDatabaseManager::Release()
    187 {
    188     ULONG newRef = --m_refCount;
    189     if (!newRef)
    190         delete this;
    191 
    192     return newRef;
    193 }
    194 
    195 template<> struct COMVariantSetter<RefPtr<SecurityOrigin> > : COMIUnknownVariantSetter<WebSecurityOrigin, RefPtr<SecurityOrigin> > {};
    196 
    197 // IWebDatabaseManager -------------------------------------------------------------
    198 HRESULT STDMETHODCALLTYPE WebDatabaseManager::sharedWebDatabaseManager(
    199     /* [retval][out] */ IWebDatabaseManager** result)
    200 {
    201     if (!s_sharedWebDatabaseManager) {
    202         s_sharedWebDatabaseManager.adoptRef(WebDatabaseManager::createInstance());
    203         DatabaseTracker::tracker().setClient(s_sharedWebDatabaseManager.get());
    204     }
    205 
    206     return s_sharedWebDatabaseManager.copyRefTo(result);
    207 }
    208 
    209 HRESULT STDMETHODCALLTYPE WebDatabaseManager::origins(
    210     /* [retval][out] */ IEnumVARIANT** result)
    211 {
    212     if (!result)
    213         return E_POINTER;
    214 
    215     *result = 0;
    216 
    217     if (this != s_sharedWebDatabaseManager)
    218         return E_FAIL;
    219 
    220     Vector<RefPtr<SecurityOrigin> > origins;
    221     DatabaseTracker::tracker().origins(origins);
    222         COMPtr<COMEnumVariant<Vector<RefPtr<SecurityOrigin> > > > enumVariant(AdoptCOM, COMEnumVariant<Vector<RefPtr<SecurityOrigin> > >::adopt(origins));
    223 
    224     *result = enumVariant.releaseRef();
    225     return S_OK;
    226 }
    227 
    228 HRESULT STDMETHODCALLTYPE WebDatabaseManager::databasesWithOrigin(
    229     /* [in] */ IWebSecurityOrigin* origin,
    230     /* [retval][out] */ IEnumVARIANT** result)
    231 {
    232     if (!origin || !result)
    233         return E_POINTER;
    234 
    235     *result = 0;
    236 
    237     if (this != s_sharedWebDatabaseManager)
    238         return E_FAIL;
    239 
    240     COMPtr<WebSecurityOrigin> webSecurityOrigin(Query, origin);
    241     if (!webSecurityOrigin)
    242         return E_FAIL;
    243 
    244     Vector<String> databaseNames;
    245     DatabaseTracker::tracker().databaseNamesForOrigin(webSecurityOrigin->securityOrigin(), databaseNames);
    246 
    247     COMPtr<COMEnumVariant<Vector<String> > > enumVariant(AdoptCOM, COMEnumVariant<Vector<String> >::adopt(databaseNames));
    248 
    249     *result = enumVariant.releaseRef();
    250     return S_OK;
    251 }
    252 
    253 HRESULT STDMETHODCALLTYPE WebDatabaseManager::detailsForDatabase(
    254     /* [in] */ BSTR databaseName,
    255     /* [in] */ IWebSecurityOrigin* origin,
    256     /* [retval][out] */ IPropertyBag** result)
    257 {
    258     if (!origin || !result)
    259         return E_POINTER;
    260 
    261     *result = 0;
    262 
    263     if (this != s_sharedWebDatabaseManager)
    264         return E_FAIL;
    265 
    266     COMPtr<WebSecurityOrigin> webSecurityOrigin(Query, origin);
    267     if (!webSecurityOrigin)
    268         return E_FAIL;
    269 
    270     DatabaseDetails details = DatabaseTracker::tracker().detailsForNameAndOrigin(String(databaseName, SysStringLen(databaseName)),
    271         webSecurityOrigin->securityOrigin());
    272 
    273     if (details.name().isNull())
    274         return E_INVALIDARG;
    275 
    276     *result = DatabaseDetailsPropertyBag::createInstance(details);
    277     return S_OK;
    278 }
    279 
    280 HRESULT STDMETHODCALLTYPE WebDatabaseManager::deleteAllDatabases()
    281 {
    282     if (this != s_sharedWebDatabaseManager)
    283         return E_FAIL;
    284 
    285     DatabaseTracker::tracker().deleteAllDatabases();
    286 
    287     return S_OK;
    288 }
    289 
    290 HRESULT STDMETHODCALLTYPE WebDatabaseManager::deleteOrigin(
    291     /* [in] */ IWebSecurityOrigin* origin)
    292 {
    293     if (!origin)
    294         return E_POINTER;
    295 
    296     if (this != s_sharedWebDatabaseManager)
    297         return E_FAIL;
    298 
    299     COMPtr<WebSecurityOrigin> webSecurityOrigin(Query, origin);
    300     if (!webSecurityOrigin)
    301         return E_FAIL;
    302 
    303     DatabaseTracker::tracker().deleteOrigin(webSecurityOrigin->securityOrigin());
    304 
    305     return S_OK;
    306 }
    307 
    308 HRESULT STDMETHODCALLTYPE WebDatabaseManager::deleteDatabase(
    309     /* [in] */ BSTR databaseName,
    310     /* [in] */ IWebSecurityOrigin* origin)
    311 {
    312     if (!origin)
    313         return E_POINTER;
    314 
    315     if (!databaseName)
    316         return E_INVALIDARG;
    317 
    318     if (this != s_sharedWebDatabaseManager)
    319         return E_FAIL;
    320 
    321     COMPtr<WebSecurityOrigin> webSecurityOrigin(Query, origin);
    322     if (!webSecurityOrigin)
    323         return E_FAIL;
    324 
    325     DatabaseTracker::tracker().deleteDatabase(webSecurityOrigin->securityOrigin(), String(databaseName, SysStringLen(databaseName)));
    326 
    327     return S_OK;
    328 }
    329 
    330 void WebDatabaseManager::dispatchDidModifyOrigin(SecurityOrigin* origin)
    331 {
    332     static BSTR databaseDidModifyOriginName = SysAllocString(WebDatabaseDidModifyOriginNotification);
    333     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
    334 
    335     COMPtr<WebSecurityOrigin> securityOrigin(AdoptCOM, WebSecurityOrigin::createInstance(origin));
    336     notifyCenter->postNotificationName(databaseDidModifyOriginName, securityOrigin.get(), 0);
    337 }
    338 
    339 HRESULT STDMETHODCALLTYPE WebDatabaseManager::setQuota(
    340     /* [in] */ BSTR origin,
    341     /* [in] */ unsigned long long quota)
    342 {
    343     if (!origin)
    344         return E_POINTER;
    345 
    346     if (this != s_sharedWebDatabaseManager)
    347         return E_FAIL;
    348 
    349     DatabaseTracker::tracker().setQuota(SecurityOrigin::createFromString(origin).get(), quota);
    350 
    351     return S_OK;
    352 }
    353 
    354 void WebDatabaseManager::dispatchDidModifyDatabase(SecurityOrigin* origin, const String& databaseName)
    355 {
    356     static BSTR databaseDidModifyOriginName = SysAllocString(WebDatabaseDidModifyDatabaseNotification);
    357     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
    358 
    359     COMPtr<WebSecurityOrigin> securityOrigin(AdoptCOM, WebSecurityOrigin::createInstance(origin));
    360 
    361     RetainPtr<CFMutableDictionaryRef> userInfo(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    362 
    363     static CFStringRef databaseNameKey = MarshallingHelpers::LPCOLESTRToCFStringRef(WebDatabaseNameKey);
    364     RetainPtr<CFStringRef> str(AdoptCF, databaseName.createCFString());
    365     CFDictionarySetValue(userInfo.get(), databaseNameKey, str.get());
    366 
    367     COMPtr<CFDictionaryPropertyBag> userInfoBag = CFDictionaryPropertyBag::createInstance();
    368     userInfoBag->setDictionary(userInfo.get());
    369 
    370     notifyCenter->postNotificationName(databaseDidModifyOriginName, securityOrigin.get(), userInfoBag.get());
    371 }
    372 
    373 void WebKitSetWebDatabasesPathIfNecessary()
    374 {
    375     static bool pathSet = false;
    376     if (pathSet)
    377         return;
    378 
    379     WebCore::String databasesDirectory = WebCore::pathByAppendingComponent(WebCore::localUserSpecificStorageDirectory(), "Databases");
    380     WebCore::DatabaseTracker::tracker().setDatabaseDirectoryPath(databasesDirectory);
    381 
    382     pathSet = true;
    383 }
    384 
    385 #endif
    386