1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/indexed_db/indexed_db_callbacks.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/task/post_task.h"
17 #include "base/threading/sequenced_task_runner_handle.h"
18 #include "base/time/time.h"
19 #include "content/browser/indexed_db/cursor_impl.h"
20 #include "content/browser/indexed_db/database_impl.h"
21 #include "content/browser/indexed_db/indexed_db_connection.h"
22 #include "content/browser/indexed_db/indexed_db_context_impl.h"
23 #include "content/browser/indexed_db/indexed_db_cursor.h"
24 #include "content/browser/indexed_db/indexed_db_database_error.h"
25 #include "content/browser/indexed_db/indexed_db_return_value.h"
26 #include "content/browser/indexed_db/indexed_db_transaction.h"
27 #include "content/browser/indexed_db/indexed_db_value.h"
28 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
29 #include "storage/browser/quota/quota_manager.h"
30 #include "third_party/blink/public/common/indexeddb/indexeddb_metadata.h"
31
32 using blink::IndexedDBDatabaseMetadata;
33 using blink::IndexedDBKey;
34 using std::swap;
35
36 namespace content {
37
38 namespace {
39
40 // The following two objects protect the given objects from being destructed
41 // while the current transaction task queue is being processed.
42 class SafeConnectionWrapper {
43 public:
SafeConnectionWrapper(std::unique_ptr<IndexedDBConnection> connection)44 explicit SafeConnectionWrapper(
45 std::unique_ptr<IndexedDBConnection> connection)
46 : connection_(std::move(connection)),
47 idb_runner_(base::SequencedTaskRunnerHandle::Get()) {}
~SafeConnectionWrapper()48 ~SafeConnectionWrapper() {
49 if (connection_) {
50 idb_runner_->PostTask(
51 FROM_HERE, base::BindOnce(
52 [](std::unique_ptr<IndexedDBConnection> connection) {
53 connection->CloseAndReportForceClose();
54 },
55 std::move(connection_)));
56 }
57 }
58 SafeConnectionWrapper(SafeConnectionWrapper&& other) = default;
59
60 std::unique_ptr<IndexedDBConnection> connection_;
61 scoped_refptr<base::SequencedTaskRunner> idb_runner_;
62
63 private:
64 DISALLOW_COPY_AND_ASSIGN(SafeConnectionWrapper);
65 };
66
67 class SafeCursorWrapper {
68 public:
SafeCursorWrapper(std::unique_ptr<IndexedDBCursor> cursor)69 explicit SafeCursorWrapper(std::unique_ptr<IndexedDBCursor> cursor)
70 : cursor_(std::move(cursor)),
71 idb_runner_(base::SequencedTaskRunnerHandle::Get()) {}
~SafeCursorWrapper()72 ~SafeCursorWrapper() {
73 if (cursor_)
74 idb_runner_->DeleteSoon(FROM_HERE, cursor_.release());
75 }
76 SafeCursorWrapper(SafeCursorWrapper&& other) = default;
77
78 std::unique_ptr<IndexedDBCursor> cursor_;
79 scoped_refptr<base::SequencedTaskRunner> idb_runner_;
80
81 private:
82 DISALLOW_COPY_AND_ASSIGN(SafeCursorWrapper);
83 };
84
85 } // namespace
86
IndexedDBCallbacks(base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,const url::Origin & origin,mojo::PendingAssociatedRemote<blink::mojom::IDBCallbacks> pending_callbacks,scoped_refptr<base::SequencedTaskRunner> idb_runner)87 IndexedDBCallbacks::IndexedDBCallbacks(
88 base::WeakPtr<IndexedDBDispatcherHost> dispatcher_host,
89 const url::Origin& origin,
90 mojo::PendingAssociatedRemote<blink::mojom::IDBCallbacks> pending_callbacks,
91 scoped_refptr<base::SequencedTaskRunner> idb_runner)
92 : data_loss_(blink::mojom::IDBDataLoss::None),
93 dispatcher_host_(std::move(dispatcher_host)),
94 origin_(origin),
95 idb_runner_(std::move(idb_runner)) {
96 DCHECK(idb_runner_->RunsTasksInCurrentSequence());
97 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
98 if (pending_callbacks.is_valid()) {
99 callbacks_.Bind(std::move(pending_callbacks));
100 // |callbacks_| is owned by |this|, so if |this| is destroyed, then
101 // |callbacks_| will also be destroyed. While |callbacks_| is otherwise
102 // alive, |this| will always be valid.
103 callbacks_.set_disconnect_handler(base::BindOnce(
104 &IndexedDBCallbacks::OnConnectionError, base::Unretained(this)));
105 }
106 }
107
~IndexedDBCallbacks()108 IndexedDBCallbacks::~IndexedDBCallbacks() {
109 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
110 }
111
OnError(const IndexedDBDatabaseError & error)112 void IndexedDBCallbacks::OnError(const IndexedDBDatabaseError& error) {
113 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
114 DCHECK(!complete_);
115
116 if (!callbacks_)
117 return;
118 if (!dispatcher_host_) {
119 OnConnectionError();
120 return;
121 }
122 callbacks_->Error(error.code(), error.message());
123 complete_ = true;
124 }
125
OnSuccess(std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions)126 void IndexedDBCallbacks::OnSuccess(
127 std::vector<blink::mojom::IDBNameAndVersionPtr> names_and_versions) {
128 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
129 DCHECK(!complete_);
130
131 if (!callbacks_)
132 return;
133 if (!dispatcher_host_) {
134 OnConnectionError();
135 return;
136 }
137 callbacks_->SuccessNamesAndVersionsList(std::move(names_and_versions));
138 complete_ = true;
139 }
140
OnSuccess(const std::vector<base::string16> & value)141 void IndexedDBCallbacks::OnSuccess(const std::vector<base::string16>& value) {
142 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
143 DCHECK(!complete_);
144
145 if (!callbacks_)
146 return;
147 if (!dispatcher_host_) {
148 OnConnectionError();
149 return;
150 }
151 callbacks_->SuccessStringList(value);
152 complete_ = true;
153 }
154
OnBlocked(int64_t existing_version)155 void IndexedDBCallbacks::OnBlocked(int64_t existing_version) {
156 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
157 DCHECK(!complete_);
158
159 if (sent_blocked_)
160 return;
161
162 sent_blocked_ = true;
163
164 if (!dispatcher_host_) {
165 OnConnectionError();
166 return;
167 }
168 if (callbacks_)
169 callbacks_->Blocked(existing_version);
170 }
171
OnUpgradeNeeded(int64_t old_version,std::unique_ptr<IndexedDBConnection> connection,const IndexedDBDatabaseMetadata & metadata,const IndexedDBDataLossInfo & data_loss_info)172 void IndexedDBCallbacks::OnUpgradeNeeded(
173 int64_t old_version,
174 std::unique_ptr<IndexedDBConnection> connection,
175 const IndexedDBDatabaseMetadata& metadata,
176 const IndexedDBDataLossInfo& data_loss_info) {
177 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
178 DCHECK(!complete_);
179
180 DCHECK(!connection_created_);
181
182 data_loss_ = data_loss_info.status;
183 connection_created_ = true;
184
185 SafeConnectionWrapper wrapper(std::move(connection));
186 if (!callbacks_)
187 return;
188 if (!dispatcher_host_) {
189 OnConnectionError();
190 return;
191 }
192
193 auto database =
194 std::make_unique<DatabaseImpl>(std::move(wrapper.connection_), origin_,
195 dispatcher_host_.get(), idb_runner_);
196
197 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_remote;
198 dispatcher_host_->AddDatabaseBinding(
199 std::move(database), pending_remote.InitWithNewEndpointAndPassReceiver());
200 callbacks_->UpgradeNeeded(std::move(pending_remote), old_version,
201 data_loss_info.status, data_loss_info.message,
202 metadata);
203 }
204
OnSuccess(std::unique_ptr<IndexedDBConnection> connection,const IndexedDBDatabaseMetadata & metadata)205 void IndexedDBCallbacks::OnSuccess(
206 std::unique_ptr<IndexedDBConnection> connection,
207 const IndexedDBDatabaseMetadata& metadata) {
208 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
209 DCHECK(!complete_);
210
211 DCHECK_EQ(connection_created_, !connection);
212
213 scoped_refptr<IndexedDBCallbacks> self(this);
214
215 // Only create a new connection if one was not previously sent in
216 // OnUpgradeNeeded.
217 std::unique_ptr<IndexedDBConnection> database_connection;
218 if (!connection_created_)
219 database_connection = std::move(connection);
220
221 SafeConnectionWrapper wrapper(std::move(database_connection));
222 if (!callbacks_)
223 return;
224 if (!dispatcher_host_) {
225 OnConnectionError();
226 return;
227 }
228
229 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_remote;
230 if (wrapper.connection_) {
231 auto database =
232 std::make_unique<DatabaseImpl>(std::move(wrapper.connection_), origin_,
233 dispatcher_host_.get(), idb_runner_);
234 dispatcher_host_->AddDatabaseBinding(
235 std::move(database),
236 pending_remote.InitWithNewEndpointAndPassReceiver());
237 }
238 callbacks_->SuccessDatabase(std::move(pending_remote), metadata);
239 complete_ = true;
240 }
241
OnSuccess(int64_t value)242 void IndexedDBCallbacks::OnSuccess(int64_t value) {
243 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
244 DCHECK(!complete_);
245
246 if (!callbacks_)
247 return;
248 if (!dispatcher_host_) {
249 OnConnectionError();
250 return;
251 }
252 callbacks_->SuccessInteger(value);
253 complete_ = true;
254 }
255
OnSuccess()256 void IndexedDBCallbacks::OnSuccess() {
257 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
258 DCHECK(!complete_);
259
260 DCHECK_EQ(blink::mojom::IDBDataLoss::None, data_loss_);
261
262 if (!callbacks_)
263 return;
264 if (!dispatcher_host_) {
265 OnConnectionError();
266 return;
267 }
268 callbacks_->Success();
269 complete_ = true;
270 }
271
OnConnectionError()272 void IndexedDBCallbacks::OnConnectionError() {
273 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
274 callbacks_.reset();
275 dispatcher_host_ = nullptr;
276 }
277
278 } // namespace content
279