1 | /* |
2 | * Copyright (C) 2015, 2016 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 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "IDBOpenDBRequest.h" |
28 | |
29 | #if ENABLE(INDEXED_DATABASE) |
30 | |
31 | #include "DOMException.h" |
32 | #include "EventNames.h" |
33 | #include "IDBConnectionProxy.h" |
34 | #include "IDBConnectionToServer.h" |
35 | #include "IDBDatabase.h" |
36 | #include "IDBError.h" |
37 | #include "IDBRequestCompletionEvent.h" |
38 | #include "IDBResultData.h" |
39 | #include "IDBTransaction.h" |
40 | #include "IDBVersionChangeEvent.h" |
41 | #include "Logging.h" |
42 | #include "ScriptExecutionContext.h" |
43 | #include <wtf/IsoMallocInlines.h> |
44 | |
45 | namespace WebCore { |
46 | |
47 | WTF_MAKE_ISO_ALLOCATED_IMPL(IDBOpenDBRequest); |
48 | |
49 | Ref<IDBOpenDBRequest> IDBOpenDBRequest::createDeleteRequest(ScriptExecutionContext& context, IDBClient::IDBConnectionProxy& connectionProxy, const IDBDatabaseIdentifier& databaseIdentifier) |
50 | { |
51 | return adoptRef(*new IDBOpenDBRequest(context, connectionProxy, databaseIdentifier, 0, IndexedDB::RequestType::Delete)); |
52 | } |
53 | |
54 | Ref<IDBOpenDBRequest> IDBOpenDBRequest::createOpenRequest(ScriptExecutionContext& context, IDBClient::IDBConnectionProxy& connectionProxy, const IDBDatabaseIdentifier& databaseIdentifier, uint64_t version) |
55 | { |
56 | return adoptRef(*new IDBOpenDBRequest(context, connectionProxy, databaseIdentifier, version, IndexedDB::RequestType::Open)); |
57 | } |
58 | |
59 | IDBOpenDBRequest::IDBOpenDBRequest(ScriptExecutionContext& context, IDBClient::IDBConnectionProxy& connectionProxy, const IDBDatabaseIdentifier& databaseIdentifier, uint64_t version, IndexedDB::RequestType requestType) |
60 | : IDBRequest(context, connectionProxy) |
61 | , m_databaseIdentifier(databaseIdentifier) |
62 | , m_version(version) |
63 | { |
64 | m_requestType = requestType; |
65 | } |
66 | |
67 | IDBOpenDBRequest::~IDBOpenDBRequest() |
68 | { |
69 | ASSERT(&originThread() == &Thread::current()); |
70 | } |
71 | |
72 | void IDBOpenDBRequest::onError(const IDBResultData& data) |
73 | { |
74 | ASSERT(&originThread() == &Thread::current()); |
75 | |
76 | m_domError = data.error().toDOMException(); |
77 | enqueueEvent(IDBRequestCompletionEvent::create(eventNames().errorEvent, Event::CanBubble::Yes, Event::IsCancelable::Yes, *this)); |
78 | } |
79 | |
80 | void IDBOpenDBRequest::versionChangeTransactionDidFinish() |
81 | { |
82 | ASSERT(&originThread() == &Thread::current()); |
83 | |
84 | // 3.3.7 "versionchange" transaction steps |
85 | // When the transaction is finished, after firing complete/abort on the transaction, immediately set request's transaction property to null. |
86 | m_shouldExposeTransactionToDOM = false; |
87 | } |
88 | |
89 | void IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit() |
90 | { |
91 | LOG(IndexedDB, "IDBOpenDBRequest::fireSuccessAfterVersionChangeCommit() - %s" , resourceIdentifier().loggingString().utf8().data()); |
92 | |
93 | ASSERT(&originThread() == &Thread::current()); |
94 | ASSERT(hasPendingActivity()); |
95 | m_transaction->addRequest(*this); |
96 | |
97 | auto event = IDBRequestCompletionEvent::create(eventNames().successEvent, Event::CanBubble::No, Event::IsCancelable::No, *this); |
98 | m_openDatabaseSuccessEvent = &event.get(); |
99 | |
100 | enqueueEvent(WTFMove(event)); |
101 | } |
102 | |
103 | void IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion() |
104 | { |
105 | LOG(IndexedDB, "IDBOpenDBRequest::fireErrorAfterVersionChangeCompletion() - %s" , resourceIdentifier().loggingString().utf8().data()); |
106 | |
107 | ASSERT(&originThread() == &Thread::current()); |
108 | ASSERT(hasPendingActivity()); |
109 | |
110 | IDBError idbError(AbortError); |
111 | m_domError = DOMException::create(AbortError); |
112 | setResultToUndefined(); |
113 | |
114 | m_transaction->addRequest(*this); |
115 | enqueueEvent(IDBRequestCompletionEvent::create(eventNames().errorEvent, Event::CanBubble::Yes, Event::IsCancelable::Yes, *this)); |
116 | } |
117 | |
118 | void IDBOpenDBRequest::cancelForStop() |
119 | { |
120 | connectionProxy().openDBRequestCancelled({ connectionProxy(), *this }); |
121 | |
122 | if (m_transaction && m_transaction->isVersionChange()) |
123 | m_transaction->removeRequest(*this); |
124 | } |
125 | |
126 | void IDBOpenDBRequest::dispatchEvent(Event& event) |
127 | { |
128 | ASSERT(&originThread() == &Thread::current()); |
129 | |
130 | auto protectedThis = makeRef(*this); |
131 | |
132 | IDBRequest::dispatchEvent(event); |
133 | |
134 | if (m_transaction && m_transaction->isVersionChange() && (event.type() == eventNames().errorEvent || event.type() == eventNames().successEvent)) |
135 | m_transaction->database().connectionProxy().didFinishHandlingVersionChangeTransaction(m_transaction->database().databaseConnectionIdentifier(), *m_transaction); |
136 | } |
137 | |
138 | void IDBOpenDBRequest::onSuccess(const IDBResultData& resultData) |
139 | { |
140 | LOG(IndexedDB, "IDBOpenDBRequest::onSuccess()" ); |
141 | |
142 | ASSERT(&originThread() == &Thread::current()); |
143 | |
144 | setResult(IDBDatabase::create(*scriptExecutionContext(), connectionProxy(), resultData)); |
145 | m_readyState = ReadyState::Done; |
146 | |
147 | enqueueEvent(IDBRequestCompletionEvent::create(eventNames().successEvent, Event::CanBubble::No, Event::IsCancelable::No, *this)); |
148 | } |
149 | |
150 | void IDBOpenDBRequest::onUpgradeNeeded(const IDBResultData& resultData) |
151 | { |
152 | ASSERT(&originThread() == &Thread::current()); |
153 | |
154 | Ref<IDBDatabase> database = IDBDatabase::create(*scriptExecutionContext(), connectionProxy(), resultData); |
155 | Ref<IDBTransaction> transaction = database->startVersionChangeTransaction(resultData.transactionInfo(), *this); |
156 | |
157 | ASSERT(transaction->info().mode() == IDBTransactionMode::Versionchange); |
158 | ASSERT(transaction->originalDatabaseInfo()); |
159 | |
160 | uint64_t oldVersion = transaction->originalDatabaseInfo()->version(); |
161 | uint64_t newVersion = transaction->info().newVersion(); |
162 | |
163 | LOG(IndexedDB, "IDBOpenDBRequest::onUpgradeNeeded() - current version is %" PRIu64 ", new is %" PRIu64, oldVersion, newVersion); |
164 | |
165 | setResult(WTFMove(database)); |
166 | m_readyState = ReadyState::Done; |
167 | m_transaction = WTFMove(transaction); |
168 | m_transaction->addRequest(*this); |
169 | |
170 | enqueueEvent(IDBVersionChangeEvent::create(oldVersion, newVersion, eventNames().upgradeneededEvent)); |
171 | } |
172 | |
173 | void IDBOpenDBRequest::onDeleteDatabaseSuccess(const IDBResultData& resultData) |
174 | { |
175 | ASSERT(&originThread() == &Thread::current()); |
176 | |
177 | uint64_t oldVersion = resultData.databaseInfo().version(); |
178 | |
179 | LOG(IndexedDB, "IDBOpenDBRequest::onDeleteDatabaseSuccess() - current version is %" PRIu64, oldVersion); |
180 | |
181 | m_readyState = ReadyState::Done; |
182 | setResultToUndefined(); |
183 | |
184 | enqueueEvent(IDBVersionChangeEvent::create(oldVersion, 0, eventNames().successEvent)); |
185 | } |
186 | |
187 | void IDBOpenDBRequest::requestCompleted(const IDBResultData& data) |
188 | { |
189 | LOG(IndexedDB, "IDBOpenDBRequest::requestCompleted" ); |
190 | |
191 | ASSERT(&originThread() == &Thread::current()); |
192 | |
193 | // If an Open request was completed after the page has navigated, leaving this request |
194 | // with a stopped script execution context, we need to message back to the server so it |
195 | // doesn't hang waiting on a database connection or transaction that will never exist. |
196 | if (m_contextStopped) { |
197 | switch (data.type()) { |
198 | case IDBResultType::OpenDatabaseSuccess: |
199 | connectionProxy().abortOpenAndUpgradeNeeded(data.databaseConnectionIdentifier(), IDBResourceIdentifier::emptyValue()); |
200 | break; |
201 | case IDBResultType::OpenDatabaseUpgradeNeeded: |
202 | connectionProxy().abortOpenAndUpgradeNeeded(data.databaseConnectionIdentifier(), data.transactionInfo().identifier()); |
203 | break; |
204 | default: |
205 | break; |
206 | } |
207 | |
208 | return; |
209 | } |
210 | |
211 | switch (data.type()) { |
212 | case IDBResultType::Error: |
213 | onError(data); |
214 | break; |
215 | case IDBResultType::OpenDatabaseSuccess: |
216 | onSuccess(data); |
217 | break; |
218 | case IDBResultType::OpenDatabaseUpgradeNeeded: |
219 | onUpgradeNeeded(data); |
220 | break; |
221 | case IDBResultType::DeleteDatabaseSuccess: |
222 | onDeleteDatabaseSuccess(data); |
223 | break; |
224 | default: |
225 | RELEASE_ASSERT_NOT_REACHED(); |
226 | } |
227 | } |
228 | |
229 | void IDBOpenDBRequest::requestBlocked(uint64_t oldVersion, uint64_t newVersion) |
230 | { |
231 | ASSERT(&originThread() == &Thread::current()); |
232 | |
233 | LOG(IndexedDB, "IDBOpenDBRequest::requestBlocked" ); |
234 | enqueueEvent(IDBVersionChangeEvent::create(oldVersion, newVersion, eventNames().blockedEvent)); |
235 | } |
236 | |
237 | } // namespace WebCore |
238 | |
239 | #endif // ENABLE(INDEXED_DATABASE) |
240 | |