WinCairo build fails to link.
[WebKit-https.git] / Source / WebKit / chromium / src / IDBFactoryBackendProxy.cpp
1 /*
2  * Copyright (C) 2011 Google 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 "IDBFactoryBackendProxy.h"
31
32 #if ENABLE(INDEXED_DATABASE)
33
34 #include "CrossThreadTask.h"
35 #include "DOMStringList.h"
36 #include "IDBDatabaseBackendProxy.h"
37 #include "IDBDatabaseCallbacks.h"
38 #include "IDBDatabaseError.h"
39 #include "ScriptExecutionContext.h"
40 #include "SecurityOrigin.h"
41 #include "WebFrameImpl.h"
42 #include "WebIDBCallbacksImpl.h"
43 #include "WebIDBDatabase.h"
44 #include "WebIDBDatabaseCallbacksImpl.h"
45 #include "WebIDBDatabaseError.h"
46 #include "WebIDBFactory.h"
47 #include "WebKit.h"
48 #include "WebPermissionClient.h"
49 #include "WebViewImpl.h"
50 #include "WebWorkerBase.h"
51 #include "WebWorkerClientImpl.h"
52 #include "WorkerContext.h"
53 #include "WorkerLoaderProxy.h"
54 #include "WorkerScriptController.h"
55 #include "WorkerThread.h"
56 #include <public/WebVector.h>
57
58
59 using namespace WebCore;
60
61 namespace WebKit {
62
63 static WebIDBFactory* s_webIDBFactory = 0;
64
65 void setIDBFactory(WebIDBFactory* factory)
66 {
67     s_webIDBFactory = factory;
68 }
69
70 PassRefPtr<IDBFactoryBackendInterface> IDBFactoryBackendProxy::create()
71 {
72     return adoptRef(new IDBFactoryBackendProxy());
73 }
74
75 IDBFactoryBackendProxy::IDBFactoryBackendProxy()
76 {
77     ASSERT(s_webIDBFactory);
78     m_webIDBFactory = s_webIDBFactory;
79 }
80
81 IDBFactoryBackendProxy::~IDBFactoryBackendProxy()
82 {
83 }
84
85 static const char allowIndexedDBMode[] = "allowIndexedDBMode";
86
87 class AllowIndexedDBMainThreadBridge : public ThreadSafeRefCounted<AllowIndexedDBMainThreadBridge> {
88 public:
89     static PassRefPtr<AllowIndexedDBMainThreadBridge> create(WebWorkerBase* webWorkerBase, const String& mode, const String& name)
90     {
91         return adoptRef(new AllowIndexedDBMainThreadBridge(webWorkerBase, mode, name));
92     }
93
94     // These methods are invoked on the worker context.
95     void cancel()
96     {
97         MutexLocker locker(m_mutex);
98         m_webWorkerBase = 0;
99     }
100
101     bool result()
102     {
103         return m_result;
104     }
105
106     // This method is invoked on the main thread.
107     void signalCompleted(bool result, const String& mode)
108     {
109         MutexLocker locker(m_mutex);
110         if (m_webWorkerBase)
111             m_webWorkerBase->workerLoaderProxy()->postTaskForModeToWorkerContext(createCallbackTask(&didComplete, this, result), mode);
112     }
113
114 private:
115     AllowIndexedDBMainThreadBridge(WebWorkerBase* webWorkerBase, const String& mode, const String& name)
116         : m_result(false)
117         , m_webWorkerBase(webWorkerBase)
118     {
119         WebCommonWorkerClient* commonClient = webWorkerBase->commonClient();
120         // See note about thread-safety below.
121         WebWorkerBase::dispatchTaskToMainThread(
122             createCallbackTask(&allowIndexedDBTask, this, WebCore::AllowCrossThreadAccess(commonClient), name, mode));
123     }
124
125     static void allowIndexedDBTask(ScriptExecutionContext*, PassRefPtr<AllowIndexedDBMainThreadBridge> bridge, WebCommonWorkerClient* commonClient, const String& name, const String& mode)
126     {
127         if (!commonClient) {
128             bridge->signalCompleted(false, mode);
129             return;
130         }
131         bool allowed = commonClient->allowIndexedDB(name);
132         bridge->signalCompleted(allowed, mode);
133     }
134
135     static void didComplete(ScriptExecutionContext* context, PassRefPtr<AllowIndexedDBMainThreadBridge> bridge, bool result)
136     {
137         bridge->m_result = result;
138     }
139
140     bool m_result;
141     Mutex m_mutex;
142     // AllowIndexedDBMainThreadBridge uses two non-threadsafe classes across
143     // threads: WebWorkerBase and WebCommonWorkerClient.
144     // In the dedicated worker case, these are both the same object of type
145     // WebWorkerClientImpl, which isn't deleted for the life of the renderer
146     // process so we don't have to worry about use-after-frees.
147     // In the shared worker case, these are of type WebSharedWorkerImpl and
148     // chromium's WebSharedWorkerClientProxy, respectively. These are both
149     // deleted on the main thread in response to a request on the worker thread,
150     // but only after the worker run loop stops processing tasks. So even in
151     // the most interleaved case, we have:
152     // W AllowIndexedDBMainThreadBridge schedules allowIndexedDBTask
153     // M workerRunLoop marked as killed
154     // W runLoop stops and schedules object deletion on main thread
155     // M allowIndexedDBTask calls commonClient->allowIndexedDB()
156     // M WebWorkerBase and WebCommonWorkerClient are deleted
157     WebWorkerBase* m_webWorkerBase;
158 };
159
160 bool IDBFactoryBackendProxy::allowIndexedDB(ScriptExecutionContext* context, const String& name, const WebSecurityOrigin& origin, PassRefPtr<IDBCallbacks> callbacks)
161 {
162     bool allowed;
163     ASSERT_WITH_SECURITY_IMPLICATION(context->isDocument() || context->isWorkerContext());
164     if (context->isDocument()) {
165         Document* document = static_cast<Document*>(context);
166         WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame());
167         WebViewImpl* webView = webFrame->viewImpl();
168         // FIXME: webView->permissionClient() returns 0 in test_shell and content_shell http://crbug.com/137269
169         allowed = !webView->permissionClient() || webView->permissionClient()->allowIndexedDB(webFrame, name, origin);
170     } else {
171         WorkerContext* workerContext = static_cast<WorkerContext*>(context);
172         WebWorkerBase* webWorkerBase = static_cast<WebWorkerBase*>(workerContext->thread()->workerLoaderProxy().toWebWorkerBase());
173         WorkerRunLoop& runLoop = workerContext->thread()->runLoop();
174
175         String mode = allowIndexedDBMode;
176         mode.append(String::number(runLoop.createUniqueId()));
177         RefPtr<AllowIndexedDBMainThreadBridge> bridge = AllowIndexedDBMainThreadBridge::create(webWorkerBase, mode, name);
178
179         // Either the bridge returns, or the queue gets terminated.
180         if (runLoop.runInMode(workerContext, mode) == MessageQueueTerminated) {
181             bridge->cancel();
182             return false;
183         }
184         allowed = bridge->result();
185     }
186
187     if (!allowed)
188         callbacks->onError(WebIDBDatabaseError(IDBDatabaseException::UnknownError, "The user denied permission to access the database."));
189
190     return allowed;
191 }
192
193 static WebFrameImpl* getWebFrame(ScriptExecutionContext* context)
194 {
195     ASSERT_WITH_SECURITY_IMPLICATION(context->isDocument() || context->isWorkerContext());
196     if (context->isDocument()) {
197         Document* document = static_cast<Document*>(context);
198         return WebFrameImpl::fromFrame(document->frame());
199     }
200     return 0;
201 }
202
203 void IDBFactoryBackendProxy::getDatabaseNames(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext* context, const String& dataDir)
204 {
205     RefPtr<IDBCallbacks> callbacks(prpCallbacks);
206     WebSecurityOrigin origin(securityOrigin);
207     if (!allowIndexedDB(context, "Database Listing", origin, callbacks))
208         return;
209
210     WebFrameImpl* webFrame = getWebFrame(context);
211     m_webIDBFactory->getDatabaseNames(new WebIDBCallbacksImpl(callbacks), origin, webFrame, dataDir);
212 }
213
214 void IDBFactoryBackendProxy::open(const String& name, int64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext* context, const String& dataDir)
215 {
216     RefPtr<IDBCallbacks> callbacks(prpCallbacks);
217     RefPtr<IDBDatabaseCallbacks> databaseCallbacks(prpDatabaseCallbacks);
218     WebSecurityOrigin origin(securityOrigin);
219     if (!allowIndexedDB(context, name, origin, callbacks))
220         return;
221
222     WebFrameImpl* webFrame = getWebFrame(context);
223     m_webIDBFactory->open(name, version, transactionId, new WebIDBCallbacksImpl(callbacks), new WebIDBDatabaseCallbacksImpl(databaseCallbacks), origin, webFrame, dataDir);
224 }
225
226 void IDBFactoryBackendProxy::deleteDatabase(const String& name, PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext* context, const String& dataDir)
227 {
228     RefPtr<IDBCallbacks> callbacks(prpCallbacks);
229     WebSecurityOrigin origin(securityOrigin);
230     if (!allowIndexedDB(context, name, origin, callbacks))
231         return;
232
233     WebFrameImpl* webFrame = getWebFrame(context);
234     m_webIDBFactory->deleteDatabase(name, new WebIDBCallbacksImpl(callbacks), origin, webFrame, dataDir);
235 }
236
237 } // namespace WebKit
238
239 #endif // ENABLE(INDEXED_DATABASE)