1/* 2 * Copyright (C) 2007,2012 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "WebDatabaseManagerClient.h" 27 28#if ENABLE(SQL_DATABASE) 29 30#import "WebDatabaseManagerPrivate.h" 31#import "WebSecurityOriginInternal.h" 32#import <wtf/MainThread.h> 33#import <wtf/RetainPtr.h> 34#import <WebCore/DatabaseTracker.h> 35#import <WebCore/SecurityOrigin.h> 36 37#if PLATFORM(IOS) 38#import <WebCore/WebCoreThread.h> 39#endif 40 41using namespace WebCore; 42 43#if PLATFORM(IOS) 44static CFStringRef WebDatabaseOriginWasAddedNotification = CFSTR("com.apple.MobileSafariSettings.WebDatabaseOriginWasAddedNotification"); 45static CFStringRef WebDatabaseWasDeletedNotification = CFSTR("com.apple.MobileSafariSettings.WebDatabaseWasDeletedNotification"); 46static CFStringRef WebDatabaseOriginWasDeletedNotification = CFSTR("com.apple.MobileSafariSettings.WebDatabaseOriginWasDeletedNotification"); 47#endif 48 49WebDatabaseManagerClient* WebDatabaseManagerClient::sharedWebDatabaseManagerClient() 50{ 51 static WebDatabaseManagerClient* sharedClient = new WebDatabaseManagerClient(); 52 return sharedClient; 53} 54 55#if PLATFORM(IOS) 56static void onNewDatabaseOriginAdded(CFNotificationCenterRef, void* observer, CFStringRef, const void*, CFDictionaryRef) 57{ 58 ASSERT(observer); 59 60 WebDatabaseManagerClient* client = reinterpret_cast<WebDatabaseManagerClient*>(observer); 61 client->newDatabaseOriginWasAdded(); 62} 63 64static void onDatabaseDeleted(CFNotificationCenterRef, void* observer, CFStringRef, const void*, CFDictionaryRef) 65{ 66 ASSERT(observer); 67 68 WebDatabaseManagerClient* client = reinterpret_cast<WebDatabaseManagerClient*>(observer); 69 client->databaseWasDeleted(); 70} 71 72static void onDatabaseOriginDeleted(CFNotificationCenterRef, void* observer, CFStringRef, const void*, CFDictionaryRef) 73{ 74 ASSERT(observer); 75 76 WebDatabaseManagerClient* client = reinterpret_cast<WebDatabaseManagerClient*>(observer); 77 client->databaseOriginWasDeleted(); 78} 79#endif 80 81WebDatabaseManagerClient::WebDatabaseManagerClient() 82#if PLATFORM(IOS) 83 : m_isHandlingNewDatabaseOriginNotification(false) 84 , m_isHandlingDeleteDatabaseNotification(false) 85 , m_isHandlingDeleteDatabaseOriginNotification(false) 86#endif 87{ 88#if PLATFORM(IOS) 89 CFNotificationCenterRef center = CFNotificationCenterGetDarwinNotifyCenter(); 90 CFNotificationCenterAddObserver(center, this, onNewDatabaseOriginAdded, WebDatabaseOriginWasAddedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately); 91 CFNotificationCenterAddObserver(center, this, onDatabaseDeleted, WebDatabaseWasDeletedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately); 92 CFNotificationCenterAddObserver(center, this, onDatabaseOriginDeleted, WebDatabaseOriginWasDeletedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately); 93#endif 94} 95 96WebDatabaseManagerClient::~WebDatabaseManagerClient() 97{ 98#if PLATFORM(IOS) 99 CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, 0, 0); 100#endif 101} 102 103class DidModifyOriginData { 104 WTF_MAKE_NONCOPYABLE(DidModifyOriginData); 105public: 106 static void dispatchToMainThread(WebDatabaseManagerClient* client, SecurityOrigin* origin) 107 { 108 DidModifyOriginData* context = new DidModifyOriginData(client, origin->isolatedCopy()); 109 callOnMainThread(&DidModifyOriginData::dispatchDidModifyOriginOnMainThread, context); 110 } 111 112private: 113 DidModifyOriginData(WebDatabaseManagerClient* client, PassRefPtr<SecurityOrigin> origin) 114 : client(client) 115 , origin(origin) 116 { 117 } 118 119 static void dispatchDidModifyOriginOnMainThread(void* context) 120 { 121 ASSERT(isMainThread()); 122 DidModifyOriginData* info = static_cast<DidModifyOriginData*>(context); 123 info->client->dispatchDidModifyOrigin(info->origin.get()); 124 delete info; 125 } 126 127 WebDatabaseManagerClient* client; 128 RefPtr<SecurityOrigin> origin; 129}; 130 131void WebDatabaseManagerClient::dispatchDidModifyOrigin(SecurityOrigin* origin) 132{ 133 if (!isMainThread()) { 134 DidModifyOriginData::dispatchToMainThread(this, origin); 135 return; 136 } 137 138 RetainPtr<WebSecurityOrigin> webSecurityOrigin = adoptNS([[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:origin]); 139 140 [[NSNotificationCenter defaultCenter] postNotificationName:WebDatabaseDidModifyOriginNotification 141 object:webSecurityOrigin.get()]; 142} 143 144void WebDatabaseManagerClient::dispatchDidModifyDatabase(SecurityOrigin* origin, const String& databaseIdentifier) 145{ 146 if (!isMainThread()) { 147 DidModifyOriginData::dispatchToMainThread(this, origin); 148 return; 149 } 150 151 RetainPtr<WebSecurityOrigin> webSecurityOrigin = adoptNS([[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:origin]); 152 RetainPtr<NSDictionary> userInfo = adoptNS([[NSDictionary alloc] 153 initWithObjectsAndKeys:(NSString *)databaseIdentifier, WebDatabaseIdentifierKey, nil]); 154 155 [[NSNotificationCenter defaultCenter] postNotificationName:WebDatabaseDidModifyDatabaseNotification 156 object:webSecurityOrigin.get() 157 userInfo:userInfo.get()]; 158} 159 160#if PLATFORM(IOS) 161void WebDatabaseManagerClient::dispatchDidAddNewOrigin(SecurityOrigin*) 162{ 163 m_isHandlingNewDatabaseOriginNotification = true; 164 // Send a notification to all apps that a new origin has been added, so other apps with opened database can refresh their origin maps. 165 CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), WebDatabaseOriginWasAddedNotification, 0, 0, true); 166} 167 168void WebDatabaseManagerClient::dispatchDidDeleteDatabase() 169{ 170 m_isHandlingDeleteDatabaseNotification = true; 171 // Send a notification to all apps that a database has been deleted, so other apps with the deleted database open will close it properly. 172 CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), WebDatabaseWasDeletedNotification, 0, 0, true); 173} 174 175void WebDatabaseManagerClient::dispatchDidDeleteDatabaseOrigin() 176{ 177 m_isHandlingDeleteDatabaseOriginNotification = true; 178 // Send a notification to all apps that an origin has been deleted, so other apps can update their origin maps. 179 CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), WebDatabaseOriginWasDeletedNotification, 0, 0, true); 180} 181 182void WebDatabaseManagerClient::newDatabaseOriginWasAdded() 183{ 184 // Locks the WebThread for the rest of the run loop. 185 WebThreadLock(); 186 187 // If this is the process that added the new origin, its quota map should have been updated 188 // and does not need to be invalidated. 189 if (m_isHandlingNewDatabaseOriginNotification) { 190 m_isHandlingNewDatabaseOriginNotification = false; 191 return; 192 } 193 194 databaseOriginsDidChange(); 195} 196 197void WebDatabaseManagerClient::databaseWasDeleted() 198{ 199 // Locks the WebThread for the rest of the run loop. 200 WebThreadLock(); 201 202 // If this is the process that added the new origin, its quota map should have been updated 203 // and does not need to be invalidated. 204 if (m_isHandlingDeleteDatabaseNotification) { 205 m_isHandlingDeleteDatabaseNotification = false; 206 return; 207 } 208 209 DatabaseTracker::tracker().removeDeletedOpenedDatabases(); 210} 211 212void WebDatabaseManagerClient::databaseOriginWasDeleted() 213{ 214 // Locks the WebThread for the rest of the run loop. 215 WebThreadLock(); 216 217 // If this is the process that added the new origin, its quota map should have been updated 218 // and does not need to be invalidated. 219 if (m_isHandlingDeleteDatabaseOriginNotification) { 220 m_isHandlingDeleteDatabaseOriginNotification = false; 221 return; 222 } 223 224 databaseOriginsDidChange(); 225} 226 227void WebDatabaseManagerClient::databaseOriginsDidChange() 228{ 229 // Send a notification (within the app) about the origins change. If an app needs to update its UI when the origins change 230 // (such as Safari Settings), it can listen for that notification. 231 CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), WebDatabaseOriginsDidChangeNotification, 0, 0, true); 232} 233 234#endif // PLATFORM(IOS) 235 236#endif 237