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