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