String CookieManager::generateHtmlFragmentForCookies() { CookieLog("CookieManager - generateHtmlFragmentForCookies\n"); Vector<ParsedCookie*> cookieCandidates; for (HashMap<String, CookieMap*>::iterator it = m_managerMap.begin(); it != m_managerMap.end(); ++it) it->second->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; }
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 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); }
String CookieManager::getCookie(const KURL& url, HttpOnlyCookieFiltering filter) { bool isConnectionSecure = false; static String httpsPrefix("https:"); if (url.string().startsWith(httpsPrefix, false)) isConnectionSecure = true; // The max size is the number of cookie per host multiplied by the maximum length of a cookie. We add 1 for the final '\0'. static const size_t cookiesMaxLength = s_maxCookieLength * s_maxCookieCountPerHost + 1; Vector<UChar> cookiePairs; cookiePairs.reserveInitialCapacity(cookiesMaxLength); for (HashMap<String, CookieMap*>::iterator it = m_managerMap.begin(); it != m_managerMap.end(); ++it) { // Handle sub-domain by only looking at the end of the host. if (it->first.endsWith(url.host()) || (it->first.startsWith(".", false) && ("." + url.host()).endsWith(it->first, false))) { // Get CookieMap to check for expired cookies. Vector<ParsedCookie*> cookies = it->second->getCookies(); for (size_t i = 0; i < cookies.size(); ++i) { ParsedCookie* cookie = cookies[i]; // Get the cookies filtering out the secure cookies on an unsecure connection and HttpOnly cookies if requested. if (url.path().startsWith(cookie->path(), false) && (isConnectionSecure || !cookie->isSecure()) && (filter == WithHttpOnlyCookies || !cookie->isHttpOnly())) { String nameValuePair = cookie->toNameValuePair(); append(cookiePairs, nameValuePair); } } } } // Per construction of our cookies, we should not grow our vector. ASSERT(cookiePairs.capacity() == cookiesMaxLength); // Append the final '\0'. static const String nullTerminator("\0"); append(cookiePairs, nullTerminator); return String::adopt(cookiePairs); }