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
isEqual(LPCWSTR s1,LPCWSTR s2)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:
DatabaseDetailsPropertyBag(const DatabaseDetails & details)67 DatabaseDetailsPropertyBag(const DatabaseDetails& details)
68 : m_refCount(0)
69 , m_details(details) { }
~DatabaseDetailsPropertyBag()70 ~DatabaseDetailsPropertyBag() { }
71
72 ULONG m_refCount;
73 DatabaseDetails m_details;
74 };
75
76 // DatabaseDetailsPropertyBag ------------------------------------------------------
createInstance(const DatabaseDetails & details)77 DatabaseDetailsPropertyBag* DatabaseDetailsPropertyBag::createInstance(const DatabaseDetails& details)
78 {
79 DatabaseDetailsPropertyBag* instance = new DatabaseDetailsPropertyBag(details);
80 instance->AddRef();
81 return instance;
82 }
83
84 // IUnknown ------------------------------------------------------------------------
AddRef()85 ULONG STDMETHODCALLTYPE DatabaseDetailsPropertyBag::AddRef()
86 {
87 return ++m_refCount;
88 }
89
Release()90 ULONG STDMETHODCALLTYPE DatabaseDetailsPropertyBag::Release()
91 {
92 ULONG newRef = --m_refCount;
93 if (!newRef)
94 delete this;
95
96 return newRef;
97 }
98
QueryInterface(REFIID riid,void ** ppvObject)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 --------------------------------------------------------------------
Read(LPCOLESTR pszPropName,VARIANT * pVar,IErrorLog *)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
Write(LPCOLESTR pszPropName,VARIANT * pVar)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 --------------------------------------------------------------
createInstance()146 WebDatabaseManager* WebDatabaseManager::createInstance()
147 {
148 WebDatabaseManager* manager = new WebDatabaseManager();
149 manager->AddRef();
150 return manager;
151 }
152
WebDatabaseManager()153 WebDatabaseManager::WebDatabaseManager()
154 : m_refCount(0)
155 {
156 gClassCount++;
157 gClassNameCount.add("WebDatabaseManager");
158 }
159
~WebDatabaseManager()160 WebDatabaseManager::~WebDatabaseManager()
161 {
162 gClassCount--;
163 gClassNameCount.remove("WebDatabaseManager");
164 }
165
166 // IUnknown ------------------------------------------------------------------------
QueryInterface(REFIID riid,void ** ppvObject)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
AddRef()181 ULONG STDMETHODCALLTYPE WebDatabaseManager::AddRef()
182 {
183 return ++m_refCount;
184 }
185
Release()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 -------------------------------------------------------------
sharedWebDatabaseManager(IWebDatabaseManager ** result)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
origins(IEnumVARIANT ** result)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
databasesWithOrigin(IWebSecurityOrigin * origin,IEnumVARIANT ** result)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
detailsForDatabase(BSTR databaseName,IWebSecurityOrigin * origin,IPropertyBag ** result)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
deleteAllDatabases()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
deleteOrigin(IWebSecurityOrigin * origin)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
deleteDatabase(BSTR databaseName,IWebSecurityOrigin * origin)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
dispatchDidModifyOrigin(SecurityOrigin * origin)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
dispatchDidModifyDatabase(SecurityOrigin * origin,const String & databaseName)339 void WebDatabaseManager::dispatchDidModifyDatabase(SecurityOrigin* origin, const String& databaseName)
340 {
341 static BSTR databaseDidModifyOriginName = SysAllocString(WebDatabaseDidModifyDatabaseNotification);
342 IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
343
344 COMPtr<WebSecurityOrigin> securityOrigin(AdoptCOM, WebSecurityOrigin::createInstance(origin));
345
346 RetainPtr<CFMutableDictionaryRef> userInfo(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
347
348 static CFStringRef databaseNameKey = MarshallingHelpers::LPCOLESTRToCFStringRef(WebDatabaseNameKey);
349 RetainPtr<CFStringRef> str(AdoptCF, databaseName.createCFString());
350 CFDictionarySetValue(userInfo.get(), databaseNameKey, str.get());
351
352 COMPtr<CFDictionaryPropertyBag> userInfoBag(AdoptCOM, CFDictionaryPropertyBag::createInstance());
353 userInfoBag->setDictionary(userInfo.get());
354
355 notifyCenter->postNotificationName(databaseDidModifyOriginName, securityOrigin.get(), userInfoBag.get());
356 }
357
WebKitSetWebDatabasesPathIfNecessary()358 void WebKitSetWebDatabasesPathIfNecessary()
359 {
360 static bool pathSet = false;
361 if (pathSet)
362 return;
363
364 WebCore::String databasesDirectory = WebCore::pathByAppendingComponent(WebCore::localUserSpecificStorageDirectory(), "Databases");
365 WebCore::DatabaseTracker::tracker().setDatabaseDirectoryPath(databasesDirectory);
366
367 pathSet = true;
368 }
369
370 #endif
371