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