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 "third_party/blink/renderer/modules/webdatabase/inspector_database_agent.h"
30
31 #include "third_party/blink/renderer/core/frame/local_frame.h"
32 #include "third_party/blink/renderer/core/loader/document_loader.h"
33 #include "third_party/blink/renderer/core/page/page.h"
34 #include "third_party/blink/renderer/modules/webdatabase/database.h"
35 #include "third_party/blink/renderer/modules/webdatabase/database_client.h"
36 #include "third_party/blink/renderer/modules/webdatabase/database_tracker.h"
37 #include "third_party/blink/renderer/modules/webdatabase/inspector_database_resource.h"
38 #include "third_party/blink/renderer/modules/webdatabase/sql_error.h"
39 #include "third_party/blink/renderer/modules/webdatabase/sql_result_set.h"
40 #include "third_party/blink/renderer/modules/webdatabase/sql_result_set_row_list.h"
41 #include "third_party/blink/renderer/modules/webdatabase/sql_transaction.h"
42 #include "third_party/blink/renderer/modules/webdatabase/sqlite/sql_value.h"
43 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
44 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
45 #include "third_party/blink/renderer/platform/wtf/vector.h"
46
47 typedef blink::protocol::Database::Backend::ExecuteSQLCallback
48 ExecuteSQLCallback;
49
50 namespace blink {
51 using protocol::Maybe;
52 using protocol::Response;
53
54 namespace {
55
56 class ExecuteSQLCallbackWrapper : public RefCounted<ExecuteSQLCallbackWrapper> {
57 public:
Create(std::unique_ptr<ExecuteSQLCallback> callback)58 static scoped_refptr<ExecuteSQLCallbackWrapper> Create(
59 std::unique_ptr<ExecuteSQLCallback> callback) {
60 return base::AdoptRef(new ExecuteSQLCallbackWrapper(std::move(callback)));
61 }
62 ~ExecuteSQLCallbackWrapper() = default;
Get()63 ExecuteSQLCallback* Get() { return callback_.get(); }
64
ReportTransactionFailed(SQLError * error)65 void ReportTransactionFailed(SQLError* error) {
66 std::unique_ptr<protocol::Database::Error> error_object =
67 protocol::Database::Error::create()
68 .setMessage(error->message())
69 .setCode(error->code())
70 .build();
71 callback_->sendSuccess(Maybe<protocol::Array<String>>(),
72 Maybe<protocol::Array<protocol::Value>>(),
73 std::move(error_object));
74 }
75
76 private:
ExecuteSQLCallbackWrapper(std::unique_ptr<ExecuteSQLCallback> callback)77 explicit ExecuteSQLCallbackWrapper(
78 std::unique_ptr<ExecuteSQLCallback> callback)
79 : callback_(std::move(callback)) {}
80 std::unique_ptr<ExecuteSQLCallback> callback_;
81 };
82
83 class StatementCallback final : public SQLStatement::OnSuccessCallback {
84 public:
StatementCallback(scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)85 explicit StatementCallback(
86 scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
87 : request_callback_(std::move(request_callback)) {}
88 ~StatementCallback() override = default;
89
OnSuccess(SQLTransaction *,SQLResultSet * result_set)90 bool OnSuccess(SQLTransaction*, SQLResultSet* result_set) override {
91 SQLResultSetRowList* row_list = result_set->rows();
92
93 const Vector<String>& columns = row_list->ColumnNames();
94 auto column_names = std::make_unique<protocol::Array<String>>(
95 columns.begin(), columns.end());
96
97 auto values = std::make_unique<protocol::Array<protocol::Value>>();
98 const Vector<SQLValue>& data = row_list->Values();
99 for (wtf_size_t i = 0; i < data.size(); ++i) {
100 const SQLValue& value = row_list->Values()[i];
101 switch (value.GetType()) {
102 case SQLValue::kStringValue:
103 values->emplace_back(
104 protocol::StringValue::create(value.GetString()));
105 break;
106 case SQLValue::kNumberValue:
107 values->emplace_back(
108 protocol::FundamentalValue::create(value.Number()));
109 break;
110 case SQLValue::kNullValue:
111 values->emplace_back(protocol::Value::null());
112 break;
113 }
114 }
115 request_callback_->Get()->sendSuccess(std::move(column_names),
116 std::move(values),
117 Maybe<protocol::Database::Error>());
118 return true;
119 }
120
121 private:
122 scoped_refptr<ExecuteSQLCallbackWrapper> request_callback_;
123 };
124
125 class StatementErrorCallback final : public SQLStatement::OnErrorCallback {
126 public:
StatementErrorCallback(scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)127 explicit StatementErrorCallback(
128 scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
129 : request_callback_(std::move(request_callback)) {}
130 ~StatementErrorCallback() override = default;
131
OnError(SQLTransaction *,SQLError * error)132 bool OnError(SQLTransaction*, SQLError* error) override {
133 request_callback_->ReportTransactionFailed(error);
134 return true;
135 }
136
137 private:
138 scoped_refptr<ExecuteSQLCallbackWrapper> request_callback_;
139 };
140
141 class TransactionCallback final : public SQLTransaction::OnProcessCallback {
142 public:
TransactionCallback(const String & sql_statement,scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)143 explicit TransactionCallback(
144 const String& sql_statement,
145 scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
146 : sql_statement_(sql_statement),
147 request_callback_(std::move(request_callback)) {}
148 ~TransactionCallback() override = default;
149
OnProcess(SQLTransaction * transaction)150 bool OnProcess(SQLTransaction* transaction) override {
151 Vector<SQLValue> sql_values;
152 transaction->ExecuteSQL(
153 sql_statement_, sql_values,
154 MakeGarbageCollected<StatementCallback>(request_callback_),
155 MakeGarbageCollected<StatementErrorCallback>(request_callback_),
156 IGNORE_EXCEPTION_FOR_TESTING);
157 return true;
158 }
159
160 private:
161 String sql_statement_;
162 scoped_refptr<ExecuteSQLCallbackWrapper> request_callback_;
163 };
164
165 class TransactionErrorCallback final : public SQLTransaction::OnErrorCallback {
166 public:
Create(scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)167 static TransactionErrorCallback* Create(
168 scoped_refptr<ExecuteSQLCallbackWrapper> request_callback) {
169 return MakeGarbageCollected<TransactionErrorCallback>(
170 std::move(request_callback));
171 }
172
TransactionErrorCallback(scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)173 explicit TransactionErrorCallback(
174 scoped_refptr<ExecuteSQLCallbackWrapper> request_callback)
175 : request_callback_(std::move(request_callback)) {}
176 ~TransactionErrorCallback() override = default;
177
OnError(SQLError * error)178 bool OnError(SQLError* error) override {
179 request_callback_->ReportTransactionFailed(error);
180 return true;
181 }
182
183 private:
184 scoped_refptr<ExecuteSQLCallbackWrapper> request_callback_;
185 };
186
187 } // namespace
188
RegisterDatabaseOnCreation(blink::Database * database)189 void InspectorDatabaseAgent::RegisterDatabaseOnCreation(
190 blink::Database* database) {
191 DidOpenDatabase(database, database->GetSecurityOrigin()->Host(),
192 database->StringIdentifier(), database->version());
193 }
194
DidOpenDatabase(blink::Database * database,const String & domain,const String & name,const String & version)195 void InspectorDatabaseAgent::DidOpenDatabase(blink::Database* database,
196 const String& domain,
197 const String& name,
198 const String& version) {
199 if (InspectorDatabaseResource* resource =
200 FindByFileName(database->FileName())) {
201 resource->SetDatabase(database);
202 return;
203 }
204
205 auto* resource = MakeGarbageCollected<InspectorDatabaseResource>(
206 database, domain, name, version);
207 resources_.Set(resource->Id(), resource);
208 // Resources are only bound while visible.
209 DCHECK(enabled_.Get());
210 DCHECK(GetFrontend());
211 resource->Bind(GetFrontend());
212 }
213
DidCommitLoadForLocalFrame(LocalFrame * frame)214 void InspectorDatabaseAgent::DidCommitLoadForLocalFrame(LocalFrame* frame) {
215 // FIXME(dgozman): adapt this for out-of-process iframes.
216 if (frame != page_->MainFrame())
217 return;
218
219 resources_.clear();
220 }
221
InspectorDatabaseAgent(Page * page)222 InspectorDatabaseAgent::InspectorDatabaseAgent(Page* page)
223 : page_(page), enabled_(&agent_state_, /*default_value=*/false) {}
224
225 InspectorDatabaseAgent::~InspectorDatabaseAgent() = default;
226
InnerEnable()227 void InspectorDatabaseAgent::InnerEnable() {
228 if (DatabaseClient* client = DatabaseClient::FromPage(page_))
229 client->SetInspectorAgent(this);
230 DatabaseTracker::Tracker().ForEachOpenDatabaseInPage(
231 page_,
232 WTF::BindRepeating(&InspectorDatabaseAgent::RegisterDatabaseOnCreation,
233 WrapPersistent(this)));
234 }
235
enable()236 Response InspectorDatabaseAgent::enable() {
237 if (enabled_.Get())
238 return Response::Success();
239 enabled_.Set(true);
240 InnerEnable();
241 return Response::Success();
242 }
243
disable()244 Response InspectorDatabaseAgent::disable() {
245 if (!enabled_.Get())
246 return Response::Success();
247 enabled_.Set(false);
248 if (DatabaseClient* client = DatabaseClient::FromPage(page_))
249 client->SetInspectorAgent(nullptr);
250 resources_.clear();
251 return Response::Success();
252 }
253
Restore()254 void InspectorDatabaseAgent::Restore() {
255 if (enabled_.Get())
256 InnerEnable();
257 }
258
getDatabaseTableNames(const String & database_id,std::unique_ptr<protocol::Array<String>> * names)259 Response InspectorDatabaseAgent::getDatabaseTableNames(
260 const String& database_id,
261 std::unique_ptr<protocol::Array<String>>* names) {
262 if (!enabled_.Get())
263 return Response::ServerError("Database agent is not enabled");
264
265 blink::Database* database = DatabaseForId(database_id);
266 if (database) {
267 Vector<String> table_names = database->TableNames();
268 *names = std::make_unique<protocol::Array<String>>(table_names.begin(),
269 table_names.end());
270 } else {
271 *names = std::make_unique<protocol::Array<String>>();
272 }
273 return Response::Success();
274 }
275
executeSQL(const String & database_id,const String & query,std::unique_ptr<ExecuteSQLCallback> prp_request_callback)276 void InspectorDatabaseAgent::executeSQL(
277 const String& database_id,
278 const String& query,
279 std::unique_ptr<ExecuteSQLCallback> prp_request_callback) {
280 std::unique_ptr<ExecuteSQLCallback> request_callback =
281 std::move(prp_request_callback);
282
283 if (!enabled_.Get()) {
284 request_callback->sendFailure(
285 Response::ServerError("Database agent is not enabled"));
286 return;
287 }
288
289 blink::Database* database = DatabaseForId(database_id);
290 if (!database) {
291 request_callback->sendFailure(Response::ServerError("Database not found"));
292 return;
293 }
294
295 scoped_refptr<ExecuteSQLCallbackWrapper> wrapper =
296 ExecuteSQLCallbackWrapper::Create(std::move(request_callback));
297 auto* callback = MakeGarbageCollected<TransactionCallback>(query, wrapper);
298 TransactionErrorCallback* error_callback =
299 TransactionErrorCallback::Create(wrapper);
300 SQLTransaction::OnSuccessCallback* success_callback = nullptr;
301 database->PerformTransaction(callback, error_callback, success_callback);
302 }
303
FindByFileName(const String & file_name)304 InspectorDatabaseResource* InspectorDatabaseAgent::FindByFileName(
305 const String& file_name) {
306 for (DatabaseResourcesHeapMap::iterator it = resources_.begin();
307 it != resources_.end(); ++it) {
308 if (it->value->GetDatabase()->FileName() == file_name)
309 return it->value.Get();
310 }
311 return nullptr;
312 }
313
DatabaseForId(const String & database_id)314 blink::Database* InspectorDatabaseAgent::DatabaseForId(
315 const String& database_id) {
316 DatabaseResourcesHeapMap::iterator it = resources_.find(database_id);
317 if (it == resources_.end())
318 return nullptr;
319 return it->value->GetDatabase();
320 }
321
Trace(Visitor * visitor)322 void InspectorDatabaseAgent::Trace(Visitor* visitor) {
323 visitor->Trace(page_);
324 visitor->Trace(resources_);
325 InspectorBaseAgent::Trace(visitor);
326 }
327
328 } // namespace blink
329