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