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