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 <JavaScriptCore/MainThread.h>
     42 #include <WebCore/BString.h>
     43 #include <WebCore/COMPtr.h>
     44 #include <WebCore/DatabaseTracker.h>
     45 #include <WebCore/FileSystem.h>
     46 #include <WebCore/SecurityOrigin.h>
     47 
     48 using namespace WebCore;
     49 
     50 static inline bool isEqual(LPCWSTR s1, LPCWSTR s2)
     51 {
     52     return !wcscmp(s1, s2);
     53 }
     54 
     55 class DatabaseDetailsPropertyBag : public IPropertyBag {
     56     WTF_MAKE_NONCOPYABLE(DatabaseDetailsPropertyBag);
     57 public:
     58     static DatabaseDetailsPropertyBag* createInstance(const DatabaseDetails&);
     59 
     60     // IUnknown
     61     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
     62     virtual ULONG STDMETHODCALLTYPE AddRef();
     63     virtual ULONG STDMETHODCALLTYPE Release();
     64 
     65     // IPropertyBag
     66     virtual HRESULT STDMETHODCALLTYPE Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog);
     67     virtual HRESULT STDMETHODCALLTYPE Write(LPCOLESTR pszPropName, VARIANT* pVar);
     68 private:
     69     DatabaseDetailsPropertyBag(const DatabaseDetails& details)
     70         : m_refCount(0)
     71         , m_details(details) { }
     72     ~DatabaseDetailsPropertyBag() { }
     73 
     74     ULONG m_refCount;
     75     DatabaseDetails m_details;
     76 };
     77 
     78 // DatabaseDetailsPropertyBag ------------------------------------------------------
     79 DatabaseDetailsPropertyBag* DatabaseDetailsPropertyBag::createInstance(const DatabaseDetails& details)
     80 {
     81     DatabaseDetailsPropertyBag* instance = new DatabaseDetailsPropertyBag(details);
     82     instance->AddRef();
     83     return instance;
     84 }
     85 
     86 // IUnknown ------------------------------------------------------------------------
     87 ULONG STDMETHODCALLTYPE DatabaseDetailsPropertyBag::AddRef()
     88 {
     89     return ++m_refCount;
     90 }
     91 
     92 ULONG STDMETHODCALLTYPE DatabaseDetailsPropertyBag::Release()
     93 {
     94     ULONG newRef = --m_refCount;
     95     if (!newRef)
     96         delete this;
     97 
     98     return newRef;
     99 }
    100 
    101 HRESULT STDMETHODCALLTYPE DatabaseDetailsPropertyBag::QueryInterface(REFIID riid, void** ppvObject)
    102 {
    103     *ppvObject = 0;
    104     if (IsEqualGUID(riid, IID_IUnknown))
    105         *ppvObject = static_cast<DatabaseDetailsPropertyBag*>(this);
    106     else if (IsEqualGUID(riid, IID_IPropertyBag))
    107         *ppvObject = static_cast<DatabaseDetailsPropertyBag*>(this);
    108     else
    109         return E_NOINTERFACE;
    110 
    111     AddRef();
    112     return S_OK;
    113 }
    114 
    115 // IPropertyBag --------------------------------------------------------------------
    116 HRESULT STDMETHODCALLTYPE DatabaseDetailsPropertyBag::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog*)
    117 {
    118     if (!pszPropName || !pVar)
    119         return E_POINTER;
    120 
    121     VariantInit(pVar);
    122 
    123     if (isEqual(pszPropName, WebDatabaseDisplayNameKey)) {
    124         COMVariantSetter<String>::setVariant(pVar, m_details.displayName());
    125         return S_OK;
    126     } else if (isEqual(pszPropName, WebDatabaseExpectedSizeKey)) {
    127         COMVariantSetter<unsigned long long>::setVariant(pVar, m_details.expectedUsage());
    128         return S_OK;
    129     } else if (isEqual(pszPropName, WebDatabaseUsageKey)) {
    130         COMVariantSetter<unsigned long long>::setVariant(pVar, m_details.currentUsage());
    131         return S_OK;
    132     }
    133 
    134     return E_INVALIDARG;
    135 }
    136 
    137 HRESULT STDMETHODCALLTYPE DatabaseDetailsPropertyBag::Write(LPCOLESTR pszPropName, VARIANT* pVar)
    138 {
    139     if (!pszPropName || !pVar)
    140         return E_POINTER;
    141 
    142     return E_FAIL;
    143 }
    144 
    145 static COMPtr<WebDatabaseManager> s_sharedWebDatabaseManager;
    146 
    147 // WebDatabaseManager --------------------------------------------------------------
    148 WebDatabaseManager* WebDatabaseManager::createInstance()
    149 {
    150     WebDatabaseManager* manager = new WebDatabaseManager();
    151     manager->AddRef();
    152     return manager;
    153 }
    154 
    155 WebDatabaseManager::WebDatabaseManager()
    156     : m_refCount(0)
    157 {
    158     gClassCount++;
    159     gClassNameCount.add("WebDatabaseManager");
    160 }
    161 
    162 WebDatabaseManager::~WebDatabaseManager()
    163 {
    164     gClassCount--;
    165     gClassNameCount.remove("WebDatabaseManager");
    166 }
    167 
    168 // IUnknown ------------------------------------------------------------------------
    169 HRESULT STDMETHODCALLTYPE WebDatabaseManager::QueryInterface(REFIID riid, void** ppvObject)
    170 {
    171     *ppvObject = 0;
    172     if (IsEqualGUID(riid, IID_IUnknown))
    173         *ppvObject = static_cast<WebDatabaseManager*>(this);
    174     else if (IsEqualGUID(riid, IID_IWebDatabaseManager))
    175         *ppvObject = static_cast<WebDatabaseManager*>(this);
    176     else
    177         return E_NOINTERFACE;
    178 
    179     AddRef();
    180     return S_OK;
    181 }
    182 
    183 ULONG STDMETHODCALLTYPE WebDatabaseManager::AddRef()
    184 {
    185     return ++m_refCount;
    186 }
    187 
    188 ULONG STDMETHODCALLTYPE WebDatabaseManager::Release()
    189 {
    190     ULONG newRef = --m_refCount;
    191     if (!newRef)
    192         delete this;
    193 
    194     return newRef;
    195 }
    196 
    197 template<> struct COMVariantSetter<RefPtr<SecurityOrigin> > : COMIUnknownVariantSetter<WebSecurityOrigin, RefPtr<SecurityOrigin> > {};
    198 
    199 // IWebDatabaseManager -------------------------------------------------------------
    200 HRESULT STDMETHODCALLTYPE WebDatabaseManager::sharedWebDatabaseManager(
    201     /* [retval][out] */ IWebDatabaseManager** result)
    202 {
    203     if (!s_sharedWebDatabaseManager) {
    204         s_sharedWebDatabaseManager.adoptRef(WebDatabaseManager::createInstance());
    205         DatabaseTracker::tracker().setClient(s_sharedWebDatabaseManager.get());
    206     }
    207 
    208     return s_sharedWebDatabaseManager.copyRefTo(result);
    209 }
    210 
    211 HRESULT STDMETHODCALLTYPE WebDatabaseManager::origins(
    212     /* [retval][out] */ IEnumVARIANT** result)
    213 {
    214     if (!result)
    215         return E_POINTER;
    216 
    217     *result = 0;
    218 
    219     if (this != s_sharedWebDatabaseManager)
    220         return E_FAIL;
    221 
    222     Vector<RefPtr<SecurityOrigin> > origins;
    223     DatabaseTracker::tracker().origins(origins);
    224         COMPtr<COMEnumVariant<Vector<RefPtr<SecurityOrigin> > > > enumVariant(AdoptCOM, COMEnumVariant<Vector<RefPtr<SecurityOrigin> > >::adopt(origins));
    225 
    226     *result = enumVariant.releaseRef();
    227     return S_OK;
    228 }
    229 
    230 HRESULT STDMETHODCALLTYPE WebDatabaseManager::databasesWithOrigin(
    231     /* [in] */ IWebSecurityOrigin* origin,
    232     /* [retval][out] */ IEnumVARIANT** result)
    233 {
    234     if (!origin || !result)
    235         return E_POINTER;
    236 
    237     *result = 0;
    238 
    239     if (this != s_sharedWebDatabaseManager)
    240         return E_FAIL;
    241 
    242     COMPtr<WebSecurityOrigin> webSecurityOrigin(Query, origin);
    243     if (!webSecurityOrigin)
    244         return E_FAIL;
    245 
    246     Vector<String> databaseNames;
    247     DatabaseTracker::tracker().databaseNamesForOrigin(webSecurityOrigin->securityOrigin(), databaseNames);
    248 
    249     COMPtr<COMEnumVariant<Vector<String> > > enumVariant(AdoptCOM, COMEnumVariant<Vector<String> >::adopt(databaseNames));
    250 
    251     *result = enumVariant.releaseRef();
    252     return S_OK;
    253 }
    254 
    255 HRESULT STDMETHODCALLTYPE WebDatabaseManager::detailsForDatabase(
    256     /* [in] */ BSTR databaseName,
    257     /* [in] */ IWebSecurityOrigin* origin,
    258     /* [retval][out] */ IPropertyBag** result)
    259 {
    260     if (!origin || !result)
    261         return E_POINTER;
    262 
    263     *result = 0;
    264 
    265     if (this != s_sharedWebDatabaseManager)
    266         return E_FAIL;
    267 
    268     COMPtr<WebSecurityOrigin> webSecurityOrigin(Query, origin);
    269     if (!webSecurityOrigin)
    270         return E_FAIL;
    271 
    272     DatabaseDetails details = DatabaseTracker::tracker().detailsForNameAndOrigin(String(databaseName, SysStringLen(databaseName)),
    273         webSecurityOrigin->securityOrigin());
    274 
    275     if (details.name().isNull())
    276         return E_INVALIDARG;
    277 
    278     *result = DatabaseDetailsPropertyBag::createInstance(details);
    279     return S_OK;
    280 }
    281 
    282 HRESULT STDMETHODCALLTYPE WebDatabaseManager::deleteAllDatabases()
    283 {
    284     if (this != s_sharedWebDatabaseManager)
    285         return E_FAIL;
    286 
    287     DatabaseTracker::tracker().deleteAllDatabases();
    288 
    289     return S_OK;
    290 }
    291 
    292 HRESULT STDMETHODCALLTYPE WebDatabaseManager::deleteOrigin(
    293     /* [in] */ IWebSecurityOrigin* origin)
    294 {
    295     if (!origin)
    296         return E_POINTER;
    297 
    298     if (this != s_sharedWebDatabaseManager)
    299         return E_FAIL;
    300 
    301     COMPtr<WebSecurityOrigin> webSecurityOrigin(Query, origin);
    302     if (!webSecurityOrigin)
    303         return E_FAIL;
    304 
    305     DatabaseTracker::tracker().deleteOrigin(webSecurityOrigin->securityOrigin());
    306 
    307     return S_OK;
    308 }
    309 
    310 HRESULT STDMETHODCALLTYPE WebDatabaseManager::deleteDatabase(
    311     /* [in] */ BSTR databaseName,
    312     /* [in] */ IWebSecurityOrigin* origin)
    313 {
    314     if (!origin)
    315         return E_POINTER;
    316 
    317     if (!databaseName)
    318         return E_INVALIDARG;
    319 
    320     if (this != s_sharedWebDatabaseManager)
    321         return E_FAIL;
    322 
    323     COMPtr<WebSecurityOrigin> webSecurityOrigin(Query, origin);
    324     if (!webSecurityOrigin)
    325         return E_FAIL;
    326 
    327     DatabaseTracker::tracker().deleteDatabase(webSecurityOrigin->securityOrigin(), String(databaseName, SysStringLen(databaseName)));
    328 
    329     return S_OK;
    330 }
    331 
    332 class DidModifyOriginData {
    333     WTF_MAKE_NONCOPYABLE(DidModifyOriginData);
    334 public:
    335     static void dispatchToMainThread(WebDatabaseManager* databaseManager, SecurityOrigin* origin)
    336     {
    337         DidModifyOriginData* context = new DidModifyOriginData(databaseManager, origin->threadsafeCopy());
    338         callOnMainThread(&DidModifyOriginData::dispatchDidModifyOriginOnMainThread, context);
    339     }
    340 
    341 private:
    342     DidModifyOriginData(WebDatabaseManager* databaseManager, PassRefPtr<SecurityOrigin> origin)
    343         : databaseManager(databaseManager)
    344         , origin(origin)
    345     {
    346     }
    347 
    348     static void dispatchDidModifyOriginOnMainThread(void* context)
    349     {
    350         ASSERT(isMainThread());
    351         DidModifyOriginData* info = static_cast<DidModifyOriginData*>(context);
    352         info->databaseManager->dispatchDidModifyOrigin(info->origin.get());
    353         delete info;
    354     }
    355 
    356     WebDatabaseManager* databaseManager;
    357     RefPtr<SecurityOrigin> origin;
    358 };
    359 
    360 void WebDatabaseManager::dispatchDidModifyOrigin(SecurityOrigin* origin)
    361 {
    362     if (!isMainThread()) {
    363         DidModifyOriginData::dispatchToMainThread(this, origin);
    364         return;
    365     }
    366 
    367     static BSTR databaseDidModifyOriginName = SysAllocString(WebDatabaseDidModifyOriginNotification);
    368     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
    369 
    370     COMPtr<WebSecurityOrigin> securityOrigin(AdoptCOM, WebSecurityOrigin::createInstance(origin));
    371     notifyCenter->postNotificationName(databaseDidModifyOriginName, securityOrigin.get(), 0);
    372 }
    373 
    374 HRESULT STDMETHODCALLTYPE WebDatabaseManager::setQuota(
    375     /* [in] */ BSTR origin,
    376     /* [in] */ unsigned long long quota)
    377 {
    378     if (!origin)
    379         return E_POINTER;
    380 
    381     if (this != s_sharedWebDatabaseManager)
    382         return E_FAIL;
    383 
    384     DatabaseTracker::tracker().setQuota(SecurityOrigin::createFromString(origin).get(), quota);
    385 
    386     return S_OK;
    387 }
    388 
    389 void WebDatabaseManager::dispatchDidModifyDatabase(SecurityOrigin* origin, const String& databaseName)
    390 {
    391     if (!isMainThread()) {
    392         DidModifyOriginData::dispatchToMainThread(this, origin);
    393         return;
    394     }
    395 
    396     static BSTR databaseDidModifyOriginName = SysAllocString(WebDatabaseDidModifyDatabaseNotification);
    397     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
    398 
    399     COMPtr<WebSecurityOrigin> securityOrigin(AdoptCOM, WebSecurityOrigin::createInstance(origin));
    400 
    401     RetainPtr<CFMutableDictionaryRef> userInfo(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    402 
    403     static CFStringRef databaseNameKey = MarshallingHelpers::LPCOLESTRToCFStringRef(WebDatabaseNameKey);
    404     RetainPtr<CFStringRef> str(AdoptCF, databaseName.createCFString());
    405     CFDictionarySetValue(userInfo.get(), databaseNameKey, str.get());
    406 
    407     COMPtr<CFDictionaryPropertyBag> userInfoBag = CFDictionaryPropertyBag::createInstance();
    408     userInfoBag->setDictionary(userInfo.get());
    409 
    410     notifyCenter->postNotificationName(databaseDidModifyOriginName, securityOrigin.get(), userInfoBag.get());
    411 }
    412 
    413 void WebKitInitializeWebDatabasesIfNecessary()
    414 {
    415     static bool initialized = false;
    416     if (initialized)
    417         return;
    418 
    419     WTF::String databasesDirectory = WebCore::pathByAppendingComponent(WebCore::localUserSpecificStorageDirectory(), "Databases");
    420     WebCore::DatabaseTracker::initializeTracker(databasesDirectory);
    421 
    422     initialized = true;
    423 }
    424 
    425 #endif
    426