void CookieManager::setCookies(const KURL& url, const String& value, CookieFilter filter) { CookieLog("CookieManager - Setting cookies"); CookieParser parser(url); Vector<ParsedCookie*> cookies = parser.parse(value); for (size_t i = 0; i < cookies.size(); ++i) { BackingStoreRemovalPolicy treatment = m_privateMode ? DoNotRemoveFromBackingStore : RemoveFromBackingStore; checkAndTreatCookie(cookies[i], treatment, filter); } }
void CookieMap::getAllCookies(Vector<RefPtr<ParsedCookie> >* stackOfCookies) { CookieLog("CookieMap - Attempting to copy Map:%s cookies with %d cookies into vectors", m_name.utf8().data(), m_cookieVector.size()); stackOfCookies->reserveCapacity(stackOfCookies->size() + m_cookieVector.size()); size_t position = 0; while (position < m_cookieVector.size()) { RefPtr<ParsedCookie> newCookie = m_cookieVector[position]; if (newCookie->hasExpired()) { // Notice that we don't delete from backingstore. These expired cookies will be // deleted when manager loads the backingstore again. removeCookieAtIndex(position, newCookie); } else { stackOfCookies->append(newCookie); position++; } } CookieLog("CookieMap - stack of cookies now have %d cookies in it", (*stackOfCookies).size()); }
void CookieManager::getBackingStoreCookies() { // Make sure private mode is off when the database thread calls this method if (m_privateMode) return; // This method should be called just after having created the cookieManager // NEVER afterwards! ASSERT(!m_count); Vector<ParsedCookie*> cookies; m_cookieBackingStore->getCookiesFromDatabase(cookies); CookieLog("CookieManager - Backingstore has %d cookies, loading them in memory now", cookies.size()); for (size_t i = 0; i < cookies.size(); ++i) { ParsedCookie* newCookie = cookies[i]; checkAndTreatCookie(newCookie, BackingStoreCookieEntry); } CookieLog("CookieManager - Backingstore loading complete."); m_syncedWithDatabase = true; }
void CookieDatabaseBackingStore::addToChangeQueue(const ParsedCookie* changedCookie, UpdateParameter actionParam) { ASSERT(!changedCookie->isSession()); ParsedCookie cookieCopy(changedCookie); CookieAction action(cookieCopy, actionParam); { MutexLocker lock(m_mutex); m_changedCookies.append(action); CookieLog("CookieBackingStore - m_changedcookies has %d.", m_changedCookies.size()); } sendChangesToDatabase(s_databaseTimerInterval); }
CookieManager& cookieManager() { static CookieManager *cookieManager = 0; if (!cookieManager) { // Open the cookieJar now and get the backing store cookies to fill the manager. cookieManager = new CookieManager; cookieManager->m_cookieBackingStore->open(cookieManager->cookieJar()); cookieManager->getBackingStoreCookies(); CookieLog("CookieManager - Backingstore load complete.\n"); } return *cookieManager; }
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)); }
CookieDatabaseBackingStore::~CookieDatabaseBackingStore() { delete m_dbTimerClient; m_dbTimerClient = 0; // FIXME: This object will never be deleted due to the set up of CookieManager (it's a singleton) CookieLog("CookieBackingStore - Destructing"); #ifndef NDEBUG { MutexLocker lock(m_mutex); ASSERT(m_changedCookies.isEmpty()); } #endif }
void CookieManager::addCookieToMap(CookieMap* targetMap, ParsedCookie* candidateCookie, BackingStoreRemovalPolicy postToBackingStore) { ParsedCookie* oldestCookie = 0; // Check if we have not reached the per cookie domain limit. // If that is not true, we check if the global limit has been reached if backingstore mode is on // Two points: // 1) We only do a global check if backingstore mode is on because the global cookie limit only // counts session cookies that are saved in the database. If the user goes over the limit // when they are in private mode, we know that the total cookie limit will be under the limit // once the user goes back to normal mode (memory deleted and reloaded from the database) // 2) We use else if for this statement because if we remove a cookie in the 1st statement // then it means the global count will never exceed the limit CookieLimitLog("CookieManager - local count: %d global count: %d", targetMap->count(), m_count); if (targetMap->count() >= s_maxCookieCountPerHost) { CookieLog("CookieManager - deleting oldest cookie from this map due to domain count.\n"); oldestCookie = targetMap->removeOldestCookie(); } else if (m_count >= s_globalMaxCookieCount && (postToBackingStore != DoNotRemoveFromBackingStore)) { CookieLimitLog("CookieManager - Global limit reached, initiate cookie limit clean up."); initiateCookieLimitCleanUp(); } CookieLog("CookieManager - adding new cookie - %s.\n", candidateCookie->toString().utf8().data()); targetMap->addCookie(candidateCookie); // Only add non session cookie to the backing store. if (postToBackingStore == RemoveFromBackingStore) { if (oldestCookie && !oldestCookie->isSession()) { CookieLog("CookieManager - oldestCookie exists, deleting it from backingstore and destructing.\n"); m_cookieBackingStore->remove(oldestCookie); } if (!candidateCookie->isSession()) m_cookieBackingStore->insert(candidateCookie); } if (oldestCookie) delete oldestCookie; }
void CookieManager::setCookies(const KURL& url, const Vector<String>& cookies, CookieFilter filter) { // If the database hasn't been sync-ed at this point, force a sync load if (!m_syncedWithDatabase && !m_privateMode) m_cookieBackingStore->openAndLoadDatabaseSynchronously(cookieJar()); CookieLog("CookieManager - Setting cookies"); CookieParser parser(url); for (size_t i = 0; i < cookies.size(); ++i) { BackingStoreRemovalPolicy treatment = m_privateMode ? DoNotRemoveFromBackingStore : RemoveFromBackingStore; if (RefPtr<ParsedCookie> parsedCookie = parser.parseOneCookie(cookies[i])) checkAndTreatCookie(parsedCookie, treatment, filter); } }
void CookieManager::getBackingStoreCookies() { // This method should be called just after having created the cookieManager // NEVER afterwards! ASSERT(!m_count); Vector<ParsedCookie*> cookies; m_cookieBackingStore->getCookiesFromDatabase(cookies); CookieLog("CookieManager - Backingstore has %d cookies, loading them in memory now", cookies.size()); for (size_t i = 0; i < cookies.size(); ++i) { ParsedCookie* newCookie = cookies[i]; checkAndTreatCookie(newCookie, BackingStoreCookieEntry); } }
String CookieManager::getCookie(const KURL& url, CookieFilter filter) const { Vector<ParsedCookie*> rawCookies; rawCookies.reserveInitialCapacity(s_maxCookieCountPerHost); // Retrieve cookies related to this url getRawCookies(rawCookies, url, filter); CookieLog("CookieManager - there are %d cookies in raw cookies\n", rawCookies.size()); // Generate the cookie header string using the retrieved cookies StringBuilder cookieStringBuilder; cookieStringBuilder.reserveCapacity(512); size_t cookieSize = rawCookies.size(); for (size_t i = 0; i < cookieSize; i++) { cookieStringBuilder.append(rawCookies[i]->toNameValuePair()); if (i != cookieSize-1) cookieStringBuilder.append("; "); } CookieLog("CookieManager - cookieString is - %s\n", cookieStringBuilder.toString().utf8().data()); return cookieStringBuilder.toString(); }
void CookieManager::setCookies(const KURL& url, const String& value) { CookieLog("CookieManager - Setting cookies"); CookieParser parser(url); Vector<ParsedCookie*> cookies = parser.parse(value); for (size_t i = 0; i < cookies.size(); ++i) { ParsedCookie* cookie = cookies[i]; if (!shouldRejectForSecurityReason(cookie, url)) { BackingStoreRemovalPolicy treatment = m_privateMode ? DoNotRemoveFromBackingStore : RemoveFromBackingStore; checkAndTreatCookie(cookie, treatment); } else delete cookie; } }
CookieMap* CookieManager::findOrCreateCookieMap(CookieMap* protocolMap, const ParsedCookie& candidateCookie) { // Explode the domain with the '.' delimiter Vector<String> delimitedHost; // If the domain is an IP address, don't split it. if (candidateCookie.domainIsIPAddress()) delimitedHost.append(candidateCookie.domain()); else candidateCookie.domain().split(".", delimitedHost); CookieMap* curMap = protocolMap; size_t hostSize = delimitedHost.size(); CookieLog("CookieManager - looking at protocol map %s \n", protocolMap->getName().utf8().data()); // Find & create necessary CookieMaps by traversing down the domain tree // Each CookieMap represent a subsection of the domain, delimited by "." int i = hostSize - 1; while (i >= 0) { CookieLog("CookieManager - finding %s in currentmap\n", delimitedHost[i].utf8().data()); CookieMap* nextMap = curMap->getSubdomainMap(delimitedHost[i]); if (!nextMap) { CookieLog("CookieManager - cannot find map\n"); if (candidateCookie.hasExpired()) return 0; CookieLog("CookieManager - creating %s in currentmap %s\n", delimitedHost[i].utf8().data(), curMap->getName().utf8().data()); nextMap = new CookieMap(delimitedHost[i]); CookieLog("CookieManager - adding subdomain to map\n"); curMap->addSubdomainMap(delimitedHost[i], nextMap); } curMap = nextMap; i--; } return curMap; }
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)); } }
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 CookieManager::setCookies(const KURL& url, const Vector<String>& cookies, CookieFilter filter) { // Dispatch the message because the database cookies are not loaded in memory yet. if (!m_syncedWithDatabase && !m_privateMode) { typedef void (WebCore::CookieManager::*FunctionType)(const KURL&, const Vector<String>&, CookieFilter); BlackBerry::Platform::webKitThreadMessageClient()->dispatchMessage( BlackBerry::Platform::createMethodCallMessage<FunctionType, CookieManager, const KURL, const Vector<String>, CookieFilter>( &CookieManager::setCookies, this, url, cookies, filter)); return; } CookieLog("CookieManager - Setting cookies"); CookieParser parser(url); for (size_t i = 0; i < cookies.size(); ++i) { BackingStoreRemovalPolicy treatment = m_privateMode ? DoNotRemoveFromBackingStore : RemoveFromBackingStore; if (ParsedCookie* parsedCookie = parser.parseOneCookie(cookies[i])) checkAndTreatCookie(parsedCookie, treatment, filter); } }
String CookieManager::generateHtmlFragmentForCookies() { if (!m_syncedWithDatabase && !m_privateMode) { LOG_ERROR("CookieManager is calling generateHtmlFragmentForCookies before database values are loaded."); return String(); } CookieLog("CookieManager - generateHtmlFragmentForCookies\n"); Vector<ParsedCookie*> cookieCandidates; for (HashMap<String, CookieMap*>::iterator it = m_managerMap.begin(); it != m_managerMap.end(); ++it) it->value->getAllChildCookies(&cookieCandidates); String result; ParsedCookie* cookie = 0; result.append(String("<table style=\"word-wrap:break-word\" cellSpacing=\"0\" cellPadding=\"0\" border=\"1\"><tr><th>Domain</th><th>Path</th><th>Protocol</th><th>Name</th><th>Value</th><th>Secure</th><th>HttpOnly</th><th>Session</th></tr>")); for (size_t i = 0; i < cookieCandidates.size(); ++i) { cookie = cookieCandidates[i]; result.append(String("<tr><td align=\"center\">")); result.append(cookie->domain()); result.append(String("<td align=\"center\">")); result.append(cookie->path()); result.append(String("<td align=\"center\">")); result.append(cookie->protocol()); result.append(String("<td align=\"center\">")); result.append(cookie->name()); result.append(String("<td align=\"center\" style= \"word-break:break-all\">")); result.append(cookie->value()); result.append(String("<td align=\"center\">")); result.append(String(cookie->isSecure() ? "Yes" : "No")); result.append(String("<td align=\"center\">")); result.append(String(cookie->isHttpOnly() ? "Yes" : "No")); result.append(String("<td align=\"center\">")); result.append(String(cookie->isSession() ? "Yes" : "No")); result.append(String("</td></tr>")); } result.append(String("</table>")); return result; }
String CookieManager::generateHtmlFragmentForCookies() { // If the database hasn't been sync-ed at this point, force a sync load if (!m_syncedWithDatabase && !m_privateMode) m_cookieBackingStore->openAndLoadDatabaseSynchronously(cookieJar()); CookieLog("CookieManager - generateHtmlFragmentForCookies\n"); Vector<RefPtr<ParsedCookie> > cookieCandidates; for (HashMap<String, CookieMap*>::iterator it = m_managerMap.begin(); it != m_managerMap.end(); ++it) it->value->getAllChildCookies(&cookieCandidates); String result; RefPtr<ParsedCookie> cookie = 0; result.append(String("<table style=\"word-wrap:break-word\" cellSpacing=\"0\" cellPadding=\"0\" border=\"1\"><tr><th>Domain</th><th>Path</th><th>Protocol</th><th>Name</th><th>Value</th><th>Secure</th><th>HttpOnly</th><th>Session</th></tr>")); for (size_t i = 0; i < cookieCandidates.size(); ++i) { cookie = cookieCandidates[i]; result.append(String("<tr><td align=\"center\">")); result.append(cookie->domain()); result.append(String("<td align=\"center\">")); result.append(cookie->path()); result.append(String("<td align=\"center\">")); result.append(cookie->protocol()); result.append(String("<td align=\"center\">")); result.append(cookie->name()); result.append(String("<td align=\"center\" style= \"word-break:break-all\">")); result.append(cookie->value()); result.append(String("<td align=\"center\">")); result.append(String(cookie->isSecure() ? "Yes" : "No")); result.append(String("<td align=\"center\">")); result.append(String(cookie->isHttpOnly() ? "Yes" : "No")); result.append(String("<td align=\"center\">")); result.append(String(cookie->isSession() ? "Yes" : "No")); result.append(String("</td></tr>")); } result.append(String("</table>")); return result; }
void CookieDatabaseBackingStore::remove(const ParsedCookie* cookie) { CookieLog("CookieBackingStore - adding deleting cookie %s to queue.", cookie->toString().utf8().data()); addToChangeQueue(cookie, Delete); }
void CookieDatabaseBackingStore::insert(const ParsedCookie* cookie) { CookieLog("CookieBackingStore - adding inserting cookie %s to queue.", cookie->toString().utf8().data()); addToChangeQueue(cookie, Insert); }
void CookieManager::checkAndTreatCookie(ParsedCookie* candidateCookie, BackingStoreRemovalPolicy postToBackingStore) { CookieLog("CookieManager - checkAndTreatCookie - processing url with domain - %s & protocol %s\n", candidateCookie->domain().utf8().data(), candidateCookie->protocol().utf8().data()); const bool ignoreDomain = shouldIgnoreDomain(candidateCookie->protocol()); // Determine which protocol tree to add the cookie to. Create one if necessary. CookieMap* curMap = 0; if (m_managerMap.contains(candidateCookie->protocol())) curMap = m_managerMap.get(candidateCookie->protocol()); else { // Check if it is a secure version, if it is, link it to the non-secure version // Link curMap to the new protocol as well as the old one if it doesn't exist if (candidateCookie->protocol() == "https") { curMap = m_managerMap.get("http"); if (!curMap) { curMap = new CookieMap("http"); m_managerMap.add("http", curMap); } } else if (candidateCookie->protocol() == "wss") { curMap = m_managerMap.get("ws"); if (!curMap) { curMap = new CookieMap("ws"); m_managerMap.add("ws", curMap); } } else curMap = new CookieMap(candidateCookie->protocol()); CookieLog("CookieManager - adding protocol cookiemap - %s\n", curMap->getName().utf8().data()); m_managerMap.add(candidateCookie->protocol(), curMap); } // If protocol support domain, we have to traverse the domain tree to find the right // cookieMap to handle with if (!ignoreDomain) curMap = findOrCreateCookieMap(curMap, candidateCookie->domain(), candidateCookie->hasExpired()); // Now that we have the proper map for this cookie, we can modify it // If cookie does not exist and has expired, delete it // If cookie exists and it has expired, so we must remove it from the map, if not update it // If cookie expired and came from the BackingStore (therefore does not exist), we have to remove from database // If cookie does not exist & it's valid, add it to the current map if (candidateCookie->hasExpired() || candidateCookie->isForceExpired()) { // Special case for getBackingStoreCookies() to catch expired cookies if (postToBackingStore == BackingStoreCookieEntry) m_cookieBackingStore->remove(candidateCookie); else if (curMap) { bool cookieAlreadyExists = curMap->existsCookie(candidateCookie); if (cookieAlreadyExists) { CookieLog("CookieManager - expired cookie exists in memory"); ParsedCookie* expired = curMap->removeCookie(candidateCookie); // Cookie is useless, Remove the cookie from the backingstore if it exists // Backup check for BackingStoreCookieEntry incase someone incorrectly uses this enum if (postToBackingStore != BackingStoreCookieEntry && !expired->isSession()) { CookieLog("CookieManager - expired cookie is nonsession, deleting from db"); m_cookieBackingStore->remove(expired); } delete expired; } } else delete candidateCookie; } else { ASSERT(curMap); bool cookieAlreadyExists = curMap->existsCookie(candidateCookie); if (cookieAlreadyExists) update(curMap, candidateCookie, postToBackingStore); else addCookieToMap(curMap, candidateCookie, postToBackingStore); } }
void CookieDatabaseBackingStore::update(const PassRefPtr<ParsedCookie> cookie) { CookieLog("CookieBackingStore - adding updating cookie %s to queue.", cookie->toString().utf8().data()); addToChangeQueue(cookie, Update); }
void CookieManager::addCookieToMap(CookieMap* targetMap, ParsedCookie* candidateCookie, BackingStoreRemovalPolicy postToBackingStore, CookieFilter filter) { ParsedCookie* replacedCookie = 0; if (!targetMap->addOrReplaceCookie(candidateCookie, &replacedCookie, filter)) { CookieLog("CookieManager - rejecting new cookie - %s.\n", candidateCookie->toString().utf8().data()); delete candidateCookie; return; } if (replacedCookie) { CookieLog("CookieManager - updating new cookie - %s.\n", candidateCookie->toString().utf8().data()); // A cookie was replaced in targetMap. // If old cookie is non-session and new one is, we have to delete it from backingstore // If new cookie is non-session and old one is, we have to add it to backingstore // If both sessions are non-session, then we update it in the backingstore bool newIsSession = candidateCookie->isSession(); bool oldIsSession = replacedCookie->isSession(); if (postToBackingStore == RemoveFromBackingStore) { if (!newIsSession && !oldIsSession) m_cookieBackingStore->update(candidateCookie); else if (newIsSession && !oldIsSession) { // Must manually decrease the counter because it was not counted when // the cookie was removed in cookieVector. removedCookie(); m_cookieBackingStore->remove(replacedCookie); } else if (!newIsSession && oldIsSession) { // Must manually increase the counter because it was not counted when // the cookie was added in cookieVector. addedCookie(); m_cookieBackingStore->insert(candidateCookie); } } delete replacedCookie; return; } CookieLog("CookieManager - adding new cookie - %s.\n", candidateCookie->toString().utf8().data()); ParsedCookie* oldestCookie = 0; // Check if we have not reached the per cookie domain limit. // If that is not true, we check if the global limit has been reached if backingstore mode is on // Two points: // 1) We only do a global check if backingstore mode is on because the global cookie limit only // counts session cookies that are saved in the database. If the user goes over the limit // when they are in private mode, we know that the total cookie limit will be under the limit // once the user goes back to normal mode (memory deleted and reloaded from the database) // 2) We use else if for this statement because if we remove a cookie in the 1st statement // then it means the global count will never exceed the limit CookieLimitLog("CookieManager - local count: %d global count: %d", targetMap->count(), m_count); if (targetMap->count() > s_maxCookieCountPerHost) { CookieLog("CookieManager - deleting oldest cookie from this map due to domain count.\n"); oldestCookie = targetMap->removeOldestCookie(); } else if (m_count > s_globalMaxCookieCount && (postToBackingStore != DoNotRemoveFromBackingStore)) { CookieLimitLog("CookieManager - Global limit reached, initiate cookie limit clean up."); initiateCookieLimitCleanUp(); } // Only add non session cookie to the backing store. if (postToBackingStore == RemoveFromBackingStore) { if (oldestCookie && !oldestCookie->isSession()) { CookieLog("CookieManager - oldestCookie exists, deleting it from backingstore and destructing.\n"); m_cookieBackingStore->remove(oldestCookie); } if (!candidateCookie->isSession()) m_cookieBackingStore->insert(candidateCookie); } if (oldestCookie) delete oldestCookie; }
void CookieManager::checkAndTreatCookie(ParsedCookie* candidateCookie, BackingStoreRemovalPolicy postToBackingStore, CookieFilter filter) { CookieLog("CookieManager - checkAndTreatCookie - processing url with domain - %s & protocol %s\n", candidateCookie->domain().utf8().data(), candidateCookie->protocol().utf8().data()); // Delete invalid cookies: // 1) A cookie which is not from http shouldn't have a httpOnly property. // 2) Cookies coming from schemes that we do not support and the special flag isn't on if ((filter == NoHttpOnlyCookie && candidateCookie->isHttpOnly()) || (shouldIgnoreScheme(candidateCookie->protocol()) && !m_shouldDumpAllCookies)) { delete candidateCookie; return; } const bool ignoreDomain = (candidateCookie->protocol() == "file" || candidateCookie->protocol() == "local"); // Determine which protocol tree to add the cookie to. Create one if necessary. CookieMap* curMap = 0; if (m_managerMap.contains(candidateCookie->protocol())) curMap = m_managerMap.get(candidateCookie->protocol()); else { // Check if it is a secure version, if it is, link it to the non-secure version // Link curMap to the new protocol as well as the old one if it doesn't exist if (candidateCookie->protocol() == "https") { curMap = m_managerMap.get("http"); if (!curMap) { curMap = new CookieMap("http"); m_managerMap.add("http", curMap); } } else if (candidateCookie->protocol() == "wss") { curMap = m_managerMap.get("ws"); if (!curMap) { curMap = new CookieMap("ws"); m_managerMap.add("ws", curMap); } } else curMap = new CookieMap(candidateCookie->protocol()); CookieLog("CookieManager - adding protocol cookiemap - %s\n", curMap->getName().utf8().data()); m_managerMap.add(candidateCookie->protocol(), curMap); } // If protocol support domain, we have to traverse the domain tree to find the right // cookieMap to handle with if (!ignoreDomain) curMap = findOrCreateCookieMap(curMap, *candidateCookie); // Now that we have the proper map for this cookie, we can modify it // If cookie does not exist and has expired, delete it // If cookie exists and it has expired, so we must remove it from the map, if not update it // If cookie expired and came from the BackingStore (therefore does not exist), we have to remove from database // If cookie does not exist & it's valid, add it to the current map if (candidateCookie->hasExpired() || candidateCookie->isForceExpired()) { // Special case for getBackingStoreCookies() to catch expired cookies if (postToBackingStore == BackingStoreCookieEntry) m_cookieBackingStore->remove(candidateCookie); else if (curMap) { // RemoveCookie will return 0 if the cookie doesn't exist. ParsedCookie* expired = curMap->removeCookie(candidateCookie, filter); // Cookie is useless, Remove the cookie from the backingstore if it exists. // Backup check for BackingStoreCookieEntry incase someone incorrectly uses this enum. if (expired && postToBackingStore != BackingStoreCookieEntry && !expired->isSession()) { CookieLog("CookieManager - expired cookie is nonsession, deleting from db"); m_cookieBackingStore->remove(expired); } delete expired; } else delete candidateCookie; } else { ASSERT(curMap); addCookieToMap(curMap, candidateCookie, postToBackingStore, filter); } }
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 CookieMap::addSubdomainMap(const String& subdomain, CookieMap* newDomain) { CookieLog("CookieMap - Attempting to add subdomain - %s", subdomain.utf8().data()); m_subdomains.add(subdomain, newDomain); }
void CookieManager::getRawCookies(Vector<ParsedCookie*> &stackOfCookies, const KURL& requestURL, CookieFilter filter) const { if (!m_syncedWithDatabase && !m_privateMode) { LOG_ERROR("CookieManager is calling getRawCookies before database values are loaded."); return; } CookieLog("CookieManager - getRawCookies - processing url with domain - %s & protocol: %s & path: %s\n", requestURL.host().utf8().data(), requestURL.protocol().utf8().data(), requestURL.path().utf8().data()); const bool invalidScheme = shouldIgnoreScheme(requestURL.protocol()); const bool specialCaseForWebWorks = invalidScheme && m_shouldDumpAllCookies; const bool isConnectionSecure = requestURL.protocolIs("https") || requestURL.protocolIs("wss") || specialCaseForWebWorks; Vector<ParsedCookie*> cookieCandidates; Vector<CookieMap*> protocolsToSearch; // Special Case: If a server sets a "secure" cookie over a non-secure channel and tries to access the cookie // over a secure channel, it will not succeed because the secure protocol isn't mapped to the insecure protocol yet. // Set the map to the non-secure version, so it'll search the mapping for a secure cookie. CookieMap* targetMap = m_managerMap.get(requestURL.protocol()); if (!targetMap && isConnectionSecure) { CookieLog("CookieManager - special case: secure protocol are not linked yet."); if (requestURL.protocolIs("https")) targetMap = m_managerMap.get("http"); else if (requestURL.protocolIs("wss")) targetMap = m_managerMap.get("ws"); } // Decide which scheme tree we should look at. // Return on invalid schemes. cookies are currently disabled on file and local. // We only want to enable them for WebWorks that enabled a special flag. if (specialCaseForWebWorks) copyValuesToVector(m_managerMap, protocolsToSearch); else if (invalidScheme) return; else { protocolsToSearch.append(targetMap); // FIXME: this is a hack for webworks apps; RFC 6265 says "Cookies do not provide isolation by scheme" // so we should not be checking protocols at all. See PR 135595 if (m_shouldDumpAllCookies) { protocolsToSearch.append(m_managerMap.get("file")); protocolsToSearch.append(m_managerMap.get("local")); } } Vector<String> delimitedHost; // IP addresses are stored in a particular format (due to ipv6). Reduce the ip address so we can match // it with the one in memory. string canonicalIP = BlackBerry::Platform::getCanonicalIPFormat(requestURL.host().utf8().data()); if (!canonicalIP.empty()) delimitedHost.append(String(canonicalIP.c_str())); else requestURL.host().lower().split(".", true, delimitedHost); // Go through all the protocol trees that we need to search for // and get all cookies that are valid for this domain for (size_t k = 0; k < protocolsToSearch.size(); k++) { CookieMap* currentMap = protocolsToSearch[k]; // if no cookies exist for this protocol, break right away if (!currentMap) continue; CookieLog("CookieManager - looking at protocol map %s \n", currentMap->getName().utf8().data()); // Special case for local and files - because WebApps expect to get ALL cookies from the backing-store on local protocol if (specialCaseForWebWorks) { CookieLog("CookieManager - special case find in protocol map - %s\n", currentMap->getName().utf8().data()); currentMap->getAllChildCookies(&cookieCandidates); } else { // Get cookies from the null domain map currentMap->getAllCookies(&cookieCandidates); // Get cookies from the valid domain maps int i = delimitedHost.size() - 1; while (i >= 0) { CookieLog("CookieManager - finding %s in currentmap\n", delimitedHost[i].utf8().data()); currentMap = currentMap->getSubdomainMap(delimitedHost[i]); // if this subdomain/domain does not exist in our mapping then we simply exit if (!currentMap) { CookieLog("CookieManager - cannot find next map exiting the while loop.\n"); break; } CookieLog("CookieManager - found the map, grabbing cookies from this map\n"); currentMap->getAllCookies(&cookieCandidates); i--; } } } CookieLog("CookieManager - there are %d cookies in candidate\n", cookieCandidates.size()); for (size_t i = 0; i < cookieCandidates.size(); ++i) { ParsedCookie* cookie = cookieCandidates[i]; // According to the path-matches rules in RFC6265, section 5.1.4, // we should add a '/' at the end of cookie-path for comparison if the cookie-path is not end with '/'. String path = cookie->path(); CookieLog("CookieManager - comparing cookie path %s (len %d) to request path %s (len %d)", path.utf8().data(), path.length(), requestURL.path().utf8().data(), path.length()); if (!equalIgnoringCase(path, requestURL.path()) && !path.endsWith("/", false)) path = path + "/"; // Only secure connections have access to secure cookies. Unless specialCaseForWebWorks is true. // Get the cookies filtering out HttpOnly cookies if requested. if (requestURL.path().startsWith(path, false) && (isConnectionSecure || !cookie->isSecure()) && (filter == WithHttpOnlyCookies || !cookie->isHttpOnly())) { CookieLog("CookieManager - cookie chosen - %s\n", cookie->toString().utf8().data()); cookie->setLastAccessed(currentTime()); stackOfCookies.append(cookie); } } std::stable_sort(stackOfCookies.begin(), stackOfCookies.end(), cookieSorter); }
void CookieManager::getRawCookies(Vector<ParsedCookie*> &stackOfCookies, const KURL& requestURL, CookieFilter filter) const { CookieLog("CookieManager - getRawCookies - processing url with domain - %s & protocol: %s & path: %s\n", requestURL.host().utf8().data(), requestURL.protocol().utf8().data(), requestURL.path().utf8().data()); bool specialCaseForLocal = (requestURL.protocolIs("local") || requestURL.protocolIs("file")) && m_shouldDumpAllCookies; bool isConnectionSecure = requestURL.protocolIs("https") || requestURL.protocolIs("wss") || specialCaseForLocal; Vector<ParsedCookie*> cookieCandidates; Vector<CookieMap*> protocolsToSearch; if (specialCaseForLocal) copyValuesToVector(m_managerMap, protocolsToSearch); else { protocolsToSearch.append(m_managerMap.get(requestURL.protocol())); // FIXME: this is a hack for webworks apps; RFC 6265 says "Cookies do not provide isolation by scheme" // so we should not be checking protocols at all. See PR 135595 if (m_shouldDumpAllCookies) { protocolsToSearch.append(m_managerMap.get("file")); protocolsToSearch.append(m_managerMap.get("local")); } } Vector<String> delimitedHost; requestURL.host().lower().split(".", true, delimitedHost); // Go through all the protocol trees that we need to search for // and get all cookies that are valid for this domain for (size_t k = 0; k < protocolsToSearch.size(); k++) { CookieMap* currentMap = protocolsToSearch[k]; // if no cookies exist for this protocol, break right away if (!currentMap) continue; CookieLog("CookieManager - looking at protocol map %s \n", currentMap->getName().utf8().data()); // Special case for local and files - because WebApps expect to get ALL cookies from the backing-store on local protocol if (specialCaseForLocal) { CookieLog("CookieManager - special case find in protocol map - %s\n", currentMap->getName().utf8().data()); currentMap->getAllChildCookies(&cookieCandidates); } else { // Get cookies from the null domain map currentMap->getAllCookies(&cookieCandidates); // Get cookies from the valid domain maps int i = delimitedHost.size() - 1; while (i >= 0) { CookieLog("CookieManager - finding %s in currentmap\n", delimitedHost[i].utf8().data()); currentMap = currentMap->getSubdomainMap(delimitedHost[i]); // if this subdomain/domain does not exist in our mapping then we simply exit if (!currentMap) { CookieLog("CookieManager - cannot find next map exiting the while loop.\n"); break; } CookieLog("CookieManager - found the map, grabbing cookies from this map\n"); currentMap->getAllCookies(&cookieCandidates); i--; } } } CookieLog("CookieManager - there are %d cookies in candidate\n", cookieCandidates.size()); for (size_t i = 0; i < cookieCandidates.size(); ++i) { ParsedCookie* cookie = cookieCandidates[i]; // According to the path-matches rules in RFC6265, section 5.1.4, // we should add a '/' at the end of cookie-path for comparison if the cookie-path is not end with '/'. String path = cookie->path(); CookieLog("CookieManager - comparing cookie path %s (len %d) to request path %s (len %d)", path.utf8().data(), path.length(), requestURL.path().utf8().data(), path.length()); if (!equalIgnoringCase(path, requestURL.path()) && !path.endsWith("/", false)) path += "/"; // Only secure connections have access to secure cookies. Unless specialCaseForLocal is true // Get the cookies filtering out HttpOnly cookies if requested. if (requestURL.path().startsWith(path, false) && (isConnectionSecure || !cookie->isSecure()) && (filter == WithHttpOnlyCookies || !cookie->isHttpOnly())) { CookieLog("CookieManager - cookie chosen - %s\n", cookie->toString().utf8().data()); cookie->setLastAccessed(currentTime()); stackOfCookies.append(cookie); } } std::stable_sort(stackOfCookies.begin(), stackOfCookies.end(), cookieSorter); }