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