void CookieDatabaseBackingStore::invokeRemoveAll() { ASSERT(isCurrentThread()); if (!m_db.isOpen()) return; CookieLog("CookieBackingStore - remove All cookies from backingstore"); { MutexLocker lock(m_mutex); m_changedCookies.clear(); } String deleteQuery("DELETE FROM "); deleteQuery += m_tableName; deleteQuery += ";"; SQLiteStatement deleteStatement(m_db, deleteQuery); if (deleteStatement.prepare()) { LOG_ERROR("Could not prepare DELETE * statement"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); return; } if (!deleteStatement.executeCommand()) { LOG_ERROR("Cannot delete cookie from database"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); return; } }
void CookieDatabaseBackingStore::openAndLoadDatabaseSynchronously(const String& cookieJar) { CookieLog("CookieBackingStore - loading database into CookieManager immediately"); if (m_db.isOpen()) { if (isCurrentThread()) BlackBerry::Platform::webKitThreadMessageClient()->dispatchSyncMessage(createMethodCallMessage(&CookieManager::getBackingStoreCookies, &cookieManager())); else cookieManager().getBackingStoreCookies(); } else { if (isCurrentThread()) invokeOpen(cookieJar); else dispatchSyncMessage(createMethodCallMessage(&CookieDatabaseBackingStore::invokeOpen, this, cookieJar)); } }
void CookieDatabaseBackingStore::close() { ASSERT(isCurrentThread()); CookieLog("CookieBackingStore - Closing"); size_t changedCookiesSize; { MutexLocker lock(m_mutex); if (m_dbTimer.started()) m_dbTimer.stop(); changedCookiesSize = m_changedCookies.size(); } if (changedCookiesSize > 0) invokeSendChangesToDatabase(); delete m_insertStatement; m_insertStatement = 0; delete m_updateStatement; m_updateStatement = 0; delete m_deleteStatement; m_deleteStatement = 0; if (m_db.isOpen()) m_db.close(); }
//------------------------------------------------- void ofThread::waitForThread(bool callStopThread, long milliseconds){ if(thread.isRunning()){ threadBeingWaitedFor = true; // tell thread to stop if(callStopThread){ stopThread(); // signalled to stop } // wait for the thread to finish if(isCurrentThread()){ return; // waitForThread should only be called outside thread } try{ if (INFINITE_JOIN_TIMEOUT == milliseconds){ thread.join(); }else{ // Wait for "joinWaitMillis" milliseconds for thread to finish if(!thread.tryJoin(milliseconds)){ // unable to completely wait for thread } } }catch(...){ } } }
//------------------------------------------------- void ofThread::waitForThread(bool callStopThread, long milliseconds){ if(thread.isRunning()){ threadBeingWaitedFor = true; // tell thread to stop if(callStopThread){ stopThread(); ofLogVerbose("ofThread") << "- name: " << getThreadName() << " - Signaled to stop."; } // wait for the thread to finish ofLogVerbose("ofThread") << "- name: " << getThreadName() << " - waiting to stop"; if(isCurrentThread()){ ofLogWarning("ofThread") << "- name: " << getThreadName() << " - waitForThread should only be called from outside the this ofThread."; return; } if (INFINITE_JOIN_TIMEOUT == milliseconds){ thread.join(); }else{ // Wait for "joinWaitMillis" milliseconds for thread to finish if(!thread.tryJoin(milliseconds)){ ofLogError("ofThread") << "- name: " << getThreadName() << " - Unable to completely waitForThread."; } } } }
//------------------------------------------------- void ofThread::waitForThread(bool callStopThread, long milliseconds){ if(!threadDone){ // tell thread to stop if(callStopThread){ stopThread(); } // wait for the thread to finish if(isCurrentThread()){ return; // waitForThread should only be called outside thread } if (INFINITE_JOIN_TIMEOUT == milliseconds){ if(thread.joinable()){ try{ thread.join(); }catch(...){} } }else{ // Wait for "joinWaitMillis" milliseconds for thread to finish std::unique_lock<std::mutex> lck(mutex); if(!threadDone && condition.wait_for(lck,std::chrono::milliseconds(milliseconds))==std::cv_status::timeout){ // unable to completely wait for thread } } } }
//------------------------------------------------- void ofThread::unlock(){ mutex.unlock(); if(isCurrentThread()){ ofLogVerbose("ofThread") << "- name: " << getThreadName() << " - ofThread unlocked its own mutex."; } else { ofLogVerbose("ofThread") << "- name: " << getThreadName() << " - External thread unlocked the ofThread mutex."; } }
void CookieDatabaseBackingStore::sendChangesToDatabaseSynchronously() { CookieLog("CookieBackingStore - sending to database immediately"); { MutexLocker lock(m_mutex); if (m_dbTimer.started()) m_dbTimer.stop(); } if (isCurrentThread()) invokeSendChangesToDatabase(); else dispatchSyncMessage(createMethodCallMessage(&CookieDatabaseBackingStore::invokeSendChangesToDatabase, this)); }
void ScrollingThread::dispatchFunctionsFromScrollingThread() { ASSERT(isCurrentThread()); Vector<std::function<void ()>> functions; { std::lock_guard<std::mutex> lock(m_functionsMutex); functions = std::move(m_functions); } for (auto& function : functions) function(); }
//------------------------------------------------- bool ofThread::lock(){ if(_mutexBlocks){ if(isCurrentThread()){ ofLogVerbose("ofThread") << "- name: " << getThreadName() << " - ofThread waiting for its own mutex to be unlocked."; }else{ ofLogVerbose("ofThread") << "- name: " << getThreadName() << " - External thread waiting for ofThread mutex to be unlocked"; } mutex.lock(); }else{ if(!mutex.tryLock()){ ofLogVerbose("ofThread") << "- name: " << getThreadName() << " - Mutex is already locked, tryLock failed."; return false; } } if(isCurrentThread()){ ofLogVerbose("ofThread") << "- name: " << getThreadName() << " - ofThread locked its own mutex."; }else{ ofLogVerbose("ofThread") << "- name: " << getThreadName() << " - External thread locked the ofThread mutex."; } return true; }
Vector<ParsedCookie*>* CookieDatabaseBackingStore::invokeGetCookiesWithLimit(unsigned int limit) { ASSERT(isCurrentThread()); // Check that the table exists to avoid doing an unnecessary request. if (!m_db.isOpen()) return 0; StringBuilder selectQuery; selectQuery.append("SELECT name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly, creationTime, protocol FROM "); selectQuery.append(m_tableName); if (limit > 0) { selectQuery.append(" ORDER BY lastAccessed ASC"); selectQuery.append(" LIMIT " + String::number(limit)); } selectQuery.append(";"); CookieLog("CookieBackingStore - invokeGetAllCookies with select query %s", selectQuery.toString().utf8().data()); SQLiteStatement selectStatement(m_db, selectQuery.toString()); if (selectStatement.prepare()) { LOG_ERROR("Cannot retrieved cookies from the database"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); return 0; } Vector<ParsedCookie*>* cookies = new Vector<ParsedCookie*>; while (selectStatement.step() == SQLResultRow) { // There is a row to fetch String name = selectStatement.getColumnText(0); String value = selectStatement.getColumnText(1); String domain = selectStatement.getColumnText(2); String path = selectStatement.getColumnText(3); double expiry = selectStatement.getColumnDouble(4); double lastAccessed = selectStatement.getColumnDouble(5); bool isSecure = selectStatement.getColumnInt(6); bool isHttpOnly = selectStatement.getColumnInt(7); double creationTime = selectStatement.getColumnDouble(8); String protocol = selectStatement.getColumnText(9); cookies->append(new ParsedCookie(name, value, domain, protocol, path, expiry, lastAccessed, creationTime, isSecure, isHttpOnly)); } return cookies; }
void AbstractThread::waitForClose() { if (isActive()) { if (isCurrentThread() == false) { // flag that we want the thread to terminate m_terminateRequested = true; awaken(); // give the thread a chance to close on its own, and then // terminate anyway m_terminateEvent.wait(THREADJOIN_TIMEOUT); } terminate(false); } }
void AbstractThread::terminate(bool ended) { if( isActive() ) { bool wasCurrentThread = isCurrentThread(); if (ended == false) { g_Log.Event(LOGL_WARN, "Forcing thread '%s' to terminate...\n", getName()); // if the thread is current then terminating here will prevent cleanup from occurring if (wasCurrentThread == false) { #ifdef _WIN32 TerminateThread(m_handle, 0); CloseHandle(m_handle); #else pthread_cancel(m_handle); // IBM say it so #endif } } // Common things ThreadHolder::pop(this); m_id = 0; m_handle = 0; // let everyone know we have been terminated m_terminateEvent.set(); // current thread can be terminated now if (ended == false && wasCurrentThread) { #ifdef _WIN32 _endthreadex(0); #else pthread_exit(0); #endif } } }
void CookieDatabaseBackingStore::invokeOpen(const String& cookieJar) { ASSERT(isCurrentThread()); if (m_db.isOpen()) close(); if (!m_db.open(cookieJar)) { LOG_ERROR("Could not open the cookie database. No cookie will be stored!"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); return; } m_db.executeCommand("PRAGMA locking_mode=EXCLUSIVE;"); m_db.executeCommand("PRAGMA journal_mode=TRUNCATE;"); const String primaryKeyFields("PRIMARY KEY (protocol, host, path, name)"); const String databaseFields("name TEXT, value TEXT, host TEXT, path TEXT, expiry DOUBLE, lastAccessed DOUBLE, isSecure INTEGER, isHttpOnly INTEGER, creationTime DOUBLE, protocol TEXT"); // Update table to add the new column creationTime and protocol for backwards compatability. upgradeTableIfNeeded(databaseFields, primaryKeyFields); // Create table if not exsist in case that the upgradeTableIfNeeded() failed accidentally. String createTableQuery("CREATE TABLE IF NOT EXISTS "); createTableQuery += m_tableName; // This table schema is compliant with Mozilla's. createTableQuery += " (" + databaseFields + ", " + primaryKeyFields+");"; if (!m_db.executeCommand(createTableQuery)) { LOG_ERROR("Could not create the table to store the cookies into. No cookie will be stored!"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); close(); return; } String insertQuery("INSERT OR REPLACE INTO "); insertQuery += m_tableName; insertQuery += " (name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly, creationTime, protocol) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10);"; m_insertStatement = new SQLiteStatement(m_db, insertQuery); if (m_insertStatement->prepare()) { LOG_ERROR("Cannot save cookies"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); } String updateQuery("UPDATE "); updateQuery += m_tableName; // The where statement is chosen to match CookieMap key. updateQuery += " SET name = ?1, value = ?2, host = ?3, path = ?4, expiry = ?5, lastAccessed = ?6, isSecure = ?7, isHttpOnly = ?8, creationTime = ?9, protocol = ?10 where protocol = ?10 and name = ?1 and host = ?3 and path = ?4;"; m_updateStatement = new SQLiteStatement(m_db, updateQuery); if (m_updateStatement->prepare()) { LOG_ERROR("Cannot update cookies"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); } String deleteQuery("DELETE FROM "); deleteQuery += m_tableName; // The where statement is chosen to match CookieMap key. deleteQuery += " WHERE name=?1 and host=?2 and path=?3 and protocol=?4;"; m_deleteStatement = new SQLiteStatement(m_db, deleteQuery); if (m_deleteStatement->prepare()) { LOG_ERROR("Cannot delete cookies"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); } }
void CookieDatabaseBackingStore::invokeSendChangesToDatabase() { ASSERT(isCurrentThread()); if (!m_db.isOpen()) { LOG_ERROR("Timer Fired, but database is closed."); return; } Vector<CookieAction> changedCookies; { MutexLocker lock(m_mutex); changedCookies.swap(m_changedCookies); ASSERT(m_changedCookies.isEmpty()); } if (changedCookies.isEmpty()) { CookieLog("CookieBackingStore - Timer fired, but no cookies in changelist"); return; } CookieLog("CookieBackingStore - Timer fired, sending changes to database. We have %d changes", changedCookies.size()); SQLiteTransaction transaction(m_db, false); transaction.begin(); // Iterate through every element in the change list to make calls // If error occurs, ignore it and continue to the next statement size_t sizeOfChange = changedCookies.size(); for (size_t i = 0; i < sizeOfChange; i++) { SQLiteStatement* m_statement; const ParsedCookie cookie = changedCookies[i].first; UpdateParameter action = changedCookies[i].second; if (action == Delete) { m_statement = m_deleteStatement; CookieLog("CookieBackingStore - deleting cookie %s.", cookie.toString().utf8().data()); // Binds all the values if (m_statement->bindText(1, cookie.name()) || m_statement->bindText(2, cookie.domain()) || m_statement->bindText(3, cookie.path()) || m_statement->bindText(4, cookie.protocol())) { LOG_ERROR("Cannot bind cookie data to delete"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); ASSERT_NOT_REACHED(); continue; } } else { if (action == Update) { CookieLog("CookieBackingStore - updating cookie %s.", cookie.toString().utf8().data()); m_statement = m_updateStatement; } else { CookieLog("CookieBackingStore - inserting cookie %s.", cookie.toString().utf8().data()); m_statement = m_insertStatement; } // Binds all the values if (m_statement->bindText(1, cookie.name()) || m_statement->bindText(2, cookie.value()) || m_statement->bindText(3, cookie.domain()) || m_statement->bindText(4, cookie.path()) || m_statement->bindDouble(5, cookie.expiry()) || m_statement->bindDouble(6, cookie.lastAccessed()) || m_statement->bindInt64(7, cookie.isSecure()) || m_statement->bindInt64(8, cookie.isHttpOnly()) || m_statement->bindDouble(9, cookie.creationTime()) || m_statement->bindText(10, cookie.protocol())) { LOG_ERROR("Cannot bind cookie data to save"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); ASSERT_NOT_REACHED(); continue; } } int rc = m_statement->step(); m_statement->reset(); if (rc != SQLResultOk && rc != SQLResultDone) { LOG_ERROR("Cannot make call to the database"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); ASSERT_NOT_REACHED(); continue; } } transaction.commit(); CookieLog("CookieBackingStore - transaction complete"); }
void CookieDatabaseBackingStore::upgradeTableIfNeeded(const String& databaseFields, const String& primaryKeyFields) { ASSERT(isCurrentThread()); bool creationTimeExists = false; bool protocolExists = false; if (!m_db.tableExists(m_tableName)) return; // Check if the existing table has the required database fields { String query = "PRAGMA table_info(" + m_tableName + ");"; SQLiteStatement statement(m_db, query); if (statement.prepare()) { LOG_ERROR("Cannot prepare statement to query cookie table info. sql:%s", query.utf8().data()); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); return; } while (statement.step() == SQLResultRow) { DEFINE_STATIC_LOCAL(String, creationTime, ("creationTime")); DEFINE_STATIC_LOCAL(String, protocol, ("protocol")); String name = statement.getColumnText(1); if (name == creationTime) creationTimeExists = true; if (name == protocol) protocolExists = true; if (creationTimeExists && protocolExists) return; } LOG(Network, "Need to update cookie table schema."); } // Drop and recreate the cookie table to update to the latest database fields. // We do not use alter table - add column because that method cannot add primary keys. Vector<String> commands; // Backup existing table String renameQuery = "ALTER TABLE " + m_tableName + " RENAME TO Backup_" + m_tableName + ";"; commands.append(renameQuery); // Recreate the cookie table using the new database and primary key fields String createTableQuery("CREATE TABLE "); createTableQuery += m_tableName; createTableQuery += " (" + databaseFields + ", " + primaryKeyFields + ");"; commands.append(createTableQuery); // Copy the old data into the new table. If a column does not exists, // we have to put a '' in the select statement to make the number of columns // equal in the insert statement. String migrationQuery("INSERT OR REPLACE INTO "); migrationQuery += m_tableName; migrationQuery += " SELECT *"; if (!creationTimeExists) migrationQuery += ",''"; if (!protocolExists) migrationQuery += ",''"; migrationQuery += " FROM Backup_" + m_tableName; commands.append(migrationQuery); // The new columns will be blank, set the new values. if (!creationTimeExists) { String setCreationTimeQuery = "UPDATE " + m_tableName + " SET creationTime = lastAccessed;"; commands.append(setCreationTimeQuery); } if (!protocolExists) { String setProtocolQuery = "UPDATE " + m_tableName + " SET protocol = 'http' WHERE isSecure = '0';"; String setProtocolQuery2 = "UPDATE " + m_tableName + " SET protocol = 'https' WHERE isSecure = '1';"; commands.append(setProtocolQuery); commands.append(setProtocolQuery2); } // Drop the backup table String dropBackupQuery = "DROP TABLE IF EXISTS Backup_" + m_tableName + ";"; commands.append(dropBackupQuery); SQLiteTransaction transaction(m_db, false); transaction.begin(); size_t commandSize = commands.size(); for (size_t i = 0; i < commandSize; ++i) { if (!m_db.executeCommand(commands[i])) { LOG_ERROR("Failed to alter cookie table when executing sql:%s", commands[i].utf8().data()); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); transaction.rollback(); // We should never get here, but if we do, rename the current cookie table for future restoration. This has the side effect of // clearing the current cookie table, but that's better than continually hitting this case and hence never being able to use the // cookie table. ASSERT_NOT_REACHED(); String renameQuery = "ALTER TABLE " + m_tableName + " RENAME TO Backup2_" + m_tableName + ";"; if (!m_db.executeCommand(renameQuery)) { LOG_ERROR("Failed to backup existing cookie table."); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); } return; } } transaction.commit(); LOG(Network, "Successfully updated cookie table schema."); }
void CookieDatabaseBackingStore::invokeOpen(const String& cookieJar) { ASSERT(isCurrentThread()); if (m_db.isOpen()) close(); if (!m_db.open(cookieJar)) { LOG_ERROR("Could not open the cookie database. No cookie will be stored!"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); return; } m_db.executeCommand("PRAGMA locking_mode=EXCLUSIVE;"); m_db.executeCommand("PRAGMA journal_mode=WAL;"); const String primaryKeyFields("PRIMARY KEY (protocol, host, path, name)"); const String databaseFields("name TEXT, value TEXT, host TEXT, path TEXT, expiry DOUBLE, lastAccessed DOUBLE, isSecure INTEGER, isHttpOnly INTEGER, creationTime DOUBLE, protocol TEXT"); StringBuilder createTableQuery; createTableQuery.append("CREATE TABLE IF NOT EXISTS "); createTableQuery.append(m_tableName); // This table schema is compliant with Mozilla's. createTableQuery.append(" (" + databaseFields + ", " + primaryKeyFields+");"); m_db.setBusyTimeout(1000); if (!m_db.executeCommand(createTableQuery.toString())) { LOG_ERROR("Could not create the table to store the cookies into. No cookie will be stored!"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); close(); return; } StringBuilder insertQuery; insertQuery.append("INSERT OR REPLACE INTO "); insertQuery.append(m_tableName); insertQuery.append(" (name, value, host, path, expiry, lastAccessed, isSecure, isHttpOnly, creationTime, protocol) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10);"); m_insertStatement = new SQLiteStatement(m_db, insertQuery.toString()); if (m_insertStatement->prepare()) { LOG_ERROR("Cannot save cookies"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); } StringBuilder updateQuery; updateQuery.append("UPDATE "); updateQuery.append(m_tableName); // The where statement is chosen to match CookieMap key. updateQuery.append(" SET name = ?1, value = ?2, host = ?3, path = ?4, expiry = ?5, lastAccessed = ?6, isSecure = ?7, isHttpOnly = ?8, creationTime = ?9, protocol = ?10 where name = ?1 and host = ?3 and path = ?4;"); m_updateStatement = new SQLiteStatement(m_db, updateQuery.toString()); if (m_updateStatement->prepare()) { LOG_ERROR("Cannot update cookies"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); } StringBuilder deleteQuery; deleteQuery.append("DELETE FROM "); deleteQuery.append(m_tableName); // The where statement is chosen to match CookieMap key. deleteQuery.append(" WHERE name=?1 and host=?2 and path=?3 and protocol=?4;"); m_deleteStatement = new SQLiteStatement(m_db, deleteQuery.toString()); if (m_deleteStatement->prepare()) { LOG_ERROR("Cannot delete cookies"); LOG_ERROR("SQLite Error Message: %s", m_db.lastErrorMsg()); } BlackBerry::Platform::webKitThreadMessageClient()->dispatchMessage(createMethodCallMessage(&CookieManager::getBackingStoreCookies, &cookieManager())); }