Allow blocking of IndexedDB in third-party contexts
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBFactory.cpp
1 /*
2  * Copyright (C) 2010 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 "IDBFactory.h"
31
32 #if ENABLE(INDEXED_DATABASE)
33
34 #include "Document.h"
35 #include "ExceptionCode.h"
36 #include "Frame.h"
37 #include "GroupSettings.h"
38 #include "IDBBindingUtilities.h"
39 #include "IDBDatabase.h"
40 #include "IDBDatabaseCallbacksImpl.h"
41 #include "IDBDatabaseException.h"
42 #include "IDBFactoryBackendInterface.h"
43 #include "IDBKey.h"
44 #include "IDBKeyRange.h"
45 #include "IDBOpenDBRequest.h"
46 #include "Page.h"
47 #include "PageGroup.h"
48 #include "SecurityOrigin.h"
49 #include "WorkerContext.h"
50 #include "WorkerLoaderProxy.h"
51 #include "WorkerThread.h"
52
53 namespace WebCore {
54
55 IDBFactory::IDBFactory(IDBFactoryBackendInterface* factory)
56     : m_backend(factory)
57 {
58     // We pass a reference to this object before it can be adopted.
59     relaxAdoptionRequirement();
60 }
61
62 IDBFactory::~IDBFactory()
63 {
64 }
65
66 namespace {
67 static bool isContextValid(ScriptExecutionContext* context)
68 {
69     ASSERT(context->isDocument() || context->isWorkerContext());
70     if (context->isDocument()) {
71         Document* document = static_cast<Document*>(context);
72         return document->frame() && document->page();
73     }
74 #if !ENABLE(WORKERS)
75     if (context->isWorkerContext())
76         return false;
77 #endif
78     return true;
79 }
80
81 static String getIndexedDBDatabasePath(ScriptExecutionContext* context)
82 {
83     ASSERT(isContextValid(context));
84     if (context->isDocument()) {
85         Document* document = static_cast<Document*>(context);
86         return document->page()->group().groupSettings()->indexedDBDatabasePath();
87     }
88 #if ENABLE(WORKERS)
89     WorkerContext* workerContext = static_cast<WorkerContext*>(context);
90     const GroupSettings* groupSettings = workerContext->groupSettings();
91     if (groupSettings)
92         return groupSettings->indexedDBDatabasePath();
93 #endif
94     return String();
95 }
96 }
97
98 PassRefPtr<IDBRequest> IDBFactory::getDatabaseNames(ScriptExecutionContext* context, ExceptionCode& ec)
99 {
100     if (!isContextValid(context))
101         return 0;
102     if (!context->securityOrigin()->canAccessDatabase(context->topOrigin())) {
103         ec = SECURITY_ERR;
104         return 0;
105     }
106
107     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), 0);
108     m_backend->getDatabaseNames(request, context->securityOrigin(), context, getIndexedDBDatabasePath(context));
109     return request;
110 }
111
112 PassRefPtr<IDBOpenDBRequest> IDBFactory::open(ScriptExecutionContext* context, const String& name, int64_t version, ExceptionCode& ec)
113 {
114     // FIXME: This should only need to check for 0 once webkit.org/b/96798 lands.
115     const int64_t maxECMAScriptInteger = 0x20000000000000LL - 1;
116     if (version < 1 || version > maxECMAScriptInteger) {
117         ec = TypeError;
118         return 0;
119     }
120     return openInternal(context, name, version, ec);
121 }
122
123 PassRefPtr<IDBOpenDBRequest> IDBFactory::openInternal(ScriptExecutionContext* context, const String& name, int64_t version, ExceptionCode& ec)
124 {
125     ASSERT(version >= 1 || version == IDBDatabaseMetadata::NoIntVersion);
126     if (name.isNull()) {
127         ec = TypeError;
128         return 0;
129     }
130     if (!isContextValid(context))
131         return 0;
132     if (!context->securityOrigin()->canAccessDatabase(context->topOrigin())) {
133         ec = SECURITY_ERR;
134         return 0;
135     }
136
137     RefPtr<IDBDatabaseCallbacksImpl> databaseCallbacks = IDBDatabaseCallbacksImpl::create();
138     int64_t transactionId = IDBDatabase::nextTransactionId();
139     RefPtr<IDBOpenDBRequest> request = IDBOpenDBRequest::create(context, databaseCallbacks, transactionId, version);
140     m_backend->open(name, version, transactionId, request, databaseCallbacks, context->securityOrigin(), context, getIndexedDBDatabasePath(context));
141     return request;
142 }
143
144 PassRefPtr<IDBOpenDBRequest> IDBFactory::open(ScriptExecutionContext* context, const String& name, ExceptionCode& ec)
145 {
146     return openInternal(context, name, IDBDatabaseMetadata::NoIntVersion, ec);
147 }
148
149 PassRefPtr<IDBOpenDBRequest> IDBFactory::deleteDatabase(ScriptExecutionContext* context, const String& name, ExceptionCode& ec)
150 {
151     if (name.isNull()) {
152         ec = TypeError;
153         return 0;
154     }
155     if (!isContextValid(context))
156         return 0;
157     if (!context->securityOrigin()->canAccessDatabase(context->topOrigin())) {
158         ec = SECURITY_ERR;
159         return 0;
160     }
161
162     RefPtr<IDBOpenDBRequest> request = IDBOpenDBRequest::create(context, 0, 0, IDBDatabaseMetadata::DefaultIntVersion);
163     m_backend->deleteDatabase(name, request, context->securityOrigin(), context, getIndexedDBDatabasePath(context));
164     return request;
165 }
166
167 short IDBFactory::cmp(ScriptExecutionContext* context, const ScriptValue& firstValue, const ScriptValue& secondValue, ExceptionCode& ec)
168 {
169     DOMRequestState requestState(context);
170     RefPtr<IDBKey> first = scriptValueToIDBKey(&requestState, firstValue);
171     RefPtr<IDBKey> second = scriptValueToIDBKey(&requestState, secondValue);
172
173     ASSERT(first);
174     ASSERT(second);
175
176     if (!first->isValid() || !second->isValid()) {
177         ec = IDBDatabaseException::DataError;
178         return 0;
179     }
180
181     return static_cast<short>(first->compare(second.get()));
182 }
183
184 } // namespace WebCore
185
186 #endif // ENABLE(INDEXED_DATABASE)