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 "config.h" 30 #include "modules/webdatabase/InspectorDatabaseAgent.h" 31 32 #include "bindings/v8/ExceptionStatePlaceholder.h" 33 #include "core/frame/LocalFrame.h" 34 #include "core/html/VoidCallback.h" 35 #include "core/inspector/InspectorState.h" 36 #include "core/loader/DocumentLoader.h" 37 #include "core/page/Page.h" 38 #include "modules/webdatabase/Database.h" 39 #include "modules/webdatabase/InspectorDatabaseResource.h" 40 #include "modules/webdatabase/SQLError.h" 41 #include "modules/webdatabase/SQLResultSet.h" 42 #include "modules/webdatabase/SQLResultSetRowList.h" 43 #include "modules/webdatabase/SQLStatementCallback.h" 44 #include "modules/webdatabase/SQLStatementErrorCallback.h" 45 #include "modules/webdatabase/SQLTransaction.h" 46 #include "modules/webdatabase/SQLTransactionCallback.h" 47 #include "modules/webdatabase/SQLTransactionErrorCallback.h" 48 #include "modules/webdatabase/sqlite/SQLValue.h" 49 #include "platform/JSONValues.h" 50 #include "wtf/Vector.h" 51 52 typedef WebCore::InspectorBackendDispatcher::DatabaseCommandHandler::ExecuteSQLCallback ExecuteSQLCallback; 53 54 namespace WebCore { 55 56 namespace DatabaseAgentState { 57 static const char databaseAgentEnabled[] = "databaseAgentEnabled"; 58 }; 59 60 namespace { 61 62 void reportTransactionFailed(ExecuteSQLCallback* requestCallback, SQLError* error) 63 { 64 RefPtr<TypeBuilder::Database::Error> errorObject = TypeBuilder::Database::Error::create() 65 .setMessage(error->message()) 66 .setCode(error->code()); 67 requestCallback->sendSuccess(nullptr, nullptr, errorObject.release()); 68 } 69 70 class StatementCallback FINAL : public SQLStatementCallback { 71 public: 72 static PassOwnPtr<StatementCallback> create(PassRefPtr<ExecuteSQLCallback> requestCallback) 73 { 74 return adoptPtr(new StatementCallback(requestCallback)); 75 } 76 77 virtual ~StatementCallback() { } 78 79 virtual bool handleEvent(SQLTransaction*, SQLResultSet* resultSet) OVERRIDE 80 { 81 SQLResultSetRowList* rowList = resultSet->rows(); 82 83 RefPtr<TypeBuilder::Array<String> > columnNames = TypeBuilder::Array<String>::create(); 84 const Vector<String>& columns = rowList->columnNames(); 85 for (size_t i = 0; i < columns.size(); ++i) 86 columnNames->addItem(columns[i]); 87 88 RefPtr<TypeBuilder::Array<JSONValue> > values = TypeBuilder::Array<JSONValue>::create(); 89 const Vector<SQLValue>& data = rowList->values(); 90 for (size_t i = 0; i < data.size(); ++i) { 91 const SQLValue& value = rowList->values()[i]; 92 switch (value.type()) { 93 case SQLValue::StringValue: values->addItem(JSONString::create(value.string())); break; 94 case SQLValue::NumberValue: values->addItem(JSONBasicValue::create(value.number())); break; 95 case SQLValue::NullValue: values->addItem(JSONValue::null()); break; 96 } 97 } 98 m_requestCallback->sendSuccess(columnNames.release(), values.release(), nullptr); 99 return true; 100 } 101 102 private: 103 StatementCallback(PassRefPtr<ExecuteSQLCallback> requestCallback) 104 : m_requestCallback(requestCallback) { } 105 RefPtr<ExecuteSQLCallback> m_requestCallback; 106 }; 107 108 class StatementErrorCallback FINAL : public SQLStatementErrorCallback { 109 public: 110 static PassOwnPtr<StatementErrorCallback> create(PassRefPtr<ExecuteSQLCallback> requestCallback) 111 { 112 return adoptPtr(new StatementErrorCallback(requestCallback)); 113 } 114 115 virtual ~StatementErrorCallback() { } 116 117 virtual bool handleEvent(SQLTransaction*, SQLError* error) OVERRIDE 118 { 119 reportTransactionFailed(m_requestCallback.get(), error); 120 return true; 121 } 122 123 private: 124 StatementErrorCallback(PassRefPtr<ExecuteSQLCallback> requestCallback) 125 : m_requestCallback(requestCallback) { } 126 RefPtr<ExecuteSQLCallback> m_requestCallback; 127 }; 128 129 class TransactionCallback FINAL : public SQLTransactionCallback { 130 public: 131 static PassOwnPtr<TransactionCallback> create(const String& sqlStatement, PassRefPtr<ExecuteSQLCallback> requestCallback) 132 { 133 return adoptPtr(new TransactionCallback(sqlStatement, requestCallback)); 134 } 135 136 virtual ~TransactionCallback() { } 137 138 virtual bool handleEvent(SQLTransaction* transaction) OVERRIDE 139 { 140 if (!m_requestCallback->isActive()) 141 return true; 142 143 Vector<SQLValue> sqlValues; 144 OwnPtr<SQLStatementCallback> callback(StatementCallback::create(m_requestCallback.get())); 145 OwnPtr<SQLStatementErrorCallback> errorCallback(StatementErrorCallback::create(m_requestCallback.get())); 146 transaction->executeSQL(m_sqlStatement, sqlValues, callback.release(), errorCallback.release(), IGNORE_EXCEPTION); 147 return true; 148 } 149 private: 150 TransactionCallback(const String& sqlStatement, PassRefPtr<ExecuteSQLCallback> requestCallback) 151 : m_sqlStatement(sqlStatement) 152 , m_requestCallback(requestCallback) { } 153 String m_sqlStatement; 154 RefPtr<ExecuteSQLCallback> m_requestCallback; 155 }; 156 157 class TransactionErrorCallback FINAL : public SQLTransactionErrorCallback { 158 public: 159 static PassOwnPtr<TransactionErrorCallback> create(PassRefPtr<ExecuteSQLCallback> requestCallback) 160 { 161 return adoptPtr(new TransactionErrorCallback(requestCallback)); 162 } 163 164 virtual ~TransactionErrorCallback() { } 165 166 virtual bool handleEvent(SQLError* error) OVERRIDE 167 { 168 reportTransactionFailed(m_requestCallback.get(), error); 169 return true; 170 } 171 private: 172 TransactionErrorCallback(PassRefPtr<ExecuteSQLCallback> requestCallback) 173 : m_requestCallback(requestCallback) { } 174 RefPtr<ExecuteSQLCallback> m_requestCallback; 175 }; 176 177 class TransactionSuccessCallback FINAL : public VoidCallback { 178 public: 179 static PassOwnPtr<TransactionSuccessCallback> create() 180 { 181 return adoptPtr(new TransactionSuccessCallback()); 182 } 183 184 virtual ~TransactionSuccessCallback() { } 185 186 virtual void handleEvent() OVERRIDE { } 187 188 private: 189 TransactionSuccessCallback() { } 190 }; 191 192 } // namespace 193 194 void InspectorDatabaseAgent::didOpenDatabase(PassRefPtrWillBeRawPtr<Database> database, const String& domain, const String& name, const String& version) 195 { 196 if (InspectorDatabaseResource* resource = findByFileName(database->fileName())) { 197 resource->setDatabase(database); 198 return; 199 } 200 201 RefPtrWillBeRawPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version); 202 m_resources.set(resource->id(), resource); 203 // Resources are only bound while visible. 204 if (m_frontend && m_enabled) 205 resource->bind(m_frontend); 206 } 207 208 void InspectorDatabaseAgent::didCommitLoadForMainFrame() 209 { 210 m_resources.clear(); 211 } 212 213 InspectorDatabaseAgent::InspectorDatabaseAgent() 214 : InspectorBaseAgent<InspectorDatabaseAgent>("Database") 215 , m_frontend(0) 216 , m_enabled(false) 217 { 218 } 219 220 InspectorDatabaseAgent::~InspectorDatabaseAgent() 221 { 222 } 223 224 void InspectorDatabaseAgent::setFrontend(InspectorFrontend* frontend) 225 { 226 m_frontend = frontend->database(); 227 } 228 229 void InspectorDatabaseAgent::clearFrontend() 230 { 231 m_frontend = 0; 232 disable(0); 233 } 234 235 void InspectorDatabaseAgent::enable(ErrorString*) 236 { 237 if (m_enabled) 238 return; 239 m_enabled = true; 240 m_state->setBoolean(DatabaseAgentState::databaseAgentEnabled, m_enabled); 241 242 DatabaseResourcesHeapMap::iterator databasesEnd = m_resources.end(); 243 for (DatabaseResourcesHeapMap::iterator it = m_resources.begin(); it != databasesEnd; ++it) 244 it->value->bind(m_frontend); 245 } 246 247 void InspectorDatabaseAgent::disable(ErrorString*) 248 { 249 if (!m_enabled) 250 return; 251 m_enabled = false; 252 m_state->setBoolean(DatabaseAgentState::databaseAgentEnabled, m_enabled); 253 } 254 255 void InspectorDatabaseAgent::restore() 256 { 257 m_enabled = m_state->getBoolean(DatabaseAgentState::databaseAgentEnabled); 258 } 259 260 void InspectorDatabaseAgent::getDatabaseTableNames(ErrorString* error, const String& databaseId, RefPtr<TypeBuilder::Array<String> >& names) 261 { 262 if (!m_enabled) { 263 *error = "Database agent is not enabled"; 264 return; 265 } 266 267 names = TypeBuilder::Array<String>::create(); 268 269 Database* database = databaseForId(databaseId); 270 if (database) { 271 Vector<String> tableNames = database->tableNames(); 272 unsigned length = tableNames.size(); 273 for (unsigned i = 0; i < length; ++i) 274 names->addItem(tableNames[i]); 275 } 276 } 277 278 void InspectorDatabaseAgent::executeSQL(ErrorString*, const String& databaseId, const String& query, PassRefPtr<ExecuteSQLCallback> prpRequestCallback) 279 { 280 RefPtr<ExecuteSQLCallback> requestCallback = prpRequestCallback; 281 282 if (!m_enabled) { 283 requestCallback->sendFailure("Database agent is not enabled"); 284 return; 285 } 286 287 Database* database = databaseForId(databaseId); 288 if (!database) { 289 requestCallback->sendFailure("Database not found"); 290 return; 291 } 292 293 OwnPtr<SQLTransactionCallback> callback(TransactionCallback::create(query, requestCallback.get())); 294 OwnPtr<SQLTransactionErrorCallback> errorCallback(TransactionErrorCallback::create(requestCallback.get())); 295 OwnPtr<VoidCallback> successCallback(TransactionSuccessCallback::create()); 296 database->transaction(callback.release(), errorCallback.release(), successCallback.release()); 297 } 298 299 InspectorDatabaseResource* InspectorDatabaseAgent::findByFileName(const String& fileName) 300 { 301 for (DatabaseResourcesHeapMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) { 302 if (it->value->database()->fileName() == fileName) 303 return it->value.get(); 304 } 305 return 0; 306 } 307 308 Database* InspectorDatabaseAgent::databaseForId(const String& databaseId) 309 { 310 DatabaseResourcesHeapMap::iterator it = m_resources.find(databaseId); 311 if (it == m_resources.end()) 312 return 0; 313 return it->value->database(); 314 } 315 316 } // namespace WebCore 317