PageRenderTime 55ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/qt/qtwebkit/Source/WebCore/platform/blackberry/CookieManager.cpp

https://gitlab.com/x33n/phantomjs
C++ | 661 lines | 444 code | 98 blank | 119 comment | 134 complexity | 454f2770d661cc70c2a049b75004cdfa MD5 | raw file
  1. /*
  2. * Copyright (C) 2008, 2009 Julien Chaffraix <julien.chaffraix@gmail.com>
  3. * Copyright (C) 2010, 2011, 2012, 2013 Research In Motion Limited. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  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. *
  14. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  15. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
  18. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  21. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  22. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #define ENABLE_COOKIE_DEBUG 0
  27. #define ENABLE_COOKIE_SUPER_VERBOSE_DEBUG 0
  28. #define ENABLE_COOKIE_LIMIT_DEBUG 0
  29. #include "config.h"
  30. #include "CookieManager.h"
  31. #include "CookieDatabaseBackingStore.h"
  32. #include "CookieParser.h"
  33. #include "FileSystem.h"
  34. #include "Logging.h"
  35. #include "WebSettings.h"
  36. #include <BlackBerryPlatformExecutableMessage.h>
  37. #include <BlackBerryPlatformMessageClient.h>
  38. #include <BlackBerryPlatformNavigatorHandler.h>
  39. #include <BlackBerryPlatformSettings.h>
  40. #include <network/DomainTools.h>
  41. #include <stdlib.h>
  42. #include <wtf/CurrentTime.h>
  43. #include <wtf/text/CString.h>
  44. #include <wtf/text/StringBuilder.h>
  45. #include <wtf/text/WTFString.h>
  46. #if ENABLE_COOKIE_DEBUG
  47. #include <BlackBerryPlatformLog.h>
  48. #endif
  49. #if ENABLE_COOKIE_SUPER_VERBOSE_DEBUG
  50. #define CookieLog(format, ...) BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelInfo, format, ## __VA_ARGS__)
  51. #else
  52. #define CookieLog(format, ...)
  53. #endif // ENABLE_COOKIE_SUPER_VERBOSE_DEBUG
  54. #if ENABLE_COOKIE_LIMIT_DEBUG
  55. #define CookieLimitLog(format, ...) BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelInfo, format, ## __VA_ARGS__)
  56. #else
  57. #define CookieLimitLog(format, ...)
  58. #endif // ENABLE_COOKIE_LIMIT_DEBUG
  59. namespace WebCore {
  60. // Max count constants.
  61. static const unsigned s_globalMaxCookieCount = 6000;
  62. static const unsigned s_maxCookieCountPerHost = 60;
  63. static const unsigned s_cookiesToDeleteWhenLimitReached = 60;
  64. static const unsigned s_delayToStartCookieCleanup = 10;
  65. CookieManager& cookieManager()
  66. {
  67. static CookieManager *cookieManager = 0;
  68. if (!cookieManager) {
  69. // Open the cookieJar now and get the backing store cookies to fill the manager.
  70. cookieManager = new CookieManager;
  71. cookieManager->m_cookieBackingStore->open(cookieManager->cookieJar());
  72. }
  73. return *cookieManager;
  74. }
  75. CookieManager::CookieManager()
  76. : m_count(0)
  77. , m_privateMode(false)
  78. , m_shouldDumpAllCookies(false)
  79. , m_syncedWithDatabase(false)
  80. , m_cookieJarFileName(pathByAppendingComponent(BlackBerry::Platform::Settings::instance()->applicationDataDirectory().c_str(), "/cookieCollection.db"))
  81. , m_policy(CookieStorageAcceptPolicyAlways)
  82. , m_cookieBackingStore(CookieDatabaseBackingStore::create())
  83. , m_limitTimer(this, &CookieManager::cookieLimitCleanUp)
  84. {
  85. }
  86. CookieManager::~CookieManager()
  87. {
  88. removeAllCookies(DoNotRemoveFromBackingStore);
  89. // FIXME: m_managerMap and the top layer protocolMaps are not properly deleted.
  90. // Do not delete any protocol maps to avoid double-deletion of the maps that are
  91. // being used for both secure and non-secure protocols; this leak is OK since
  92. // there's nothing important in the hashtable destructors, and the memory will be reclaimed on exit
  93. // FIXME: CookieDatabaseBackingStore is not deleted, only flushed
  94. // (currently the destructor is never called since this class is a
  95. // singleton; on exit, the db is flushed manually. This call is only here
  96. // as a fallback in case this class is made a non-singleton.
  97. m_cookieBackingStore->sendChangesToDatabaseSynchronously();
  98. }
  99. // Sorting logic is based on Cookie Spec RFC6265, section 5.4.2
  100. static bool cookieSorter(PassRefPtr<ParsedCookie> a, PassRefPtr<ParsedCookie> b)
  101. {
  102. if (a->path().length() == b->path().length())
  103. return a->creationTime() < b->creationTime();
  104. return a->path().length() > b->path().length();
  105. }
  106. // Return whether we should ignore the scheme
  107. static bool shouldIgnoreScheme(const String& protocol)
  108. {
  109. // We want to ignore file and local schemes
  110. return protocol == "file" || protocol == "local";
  111. }
  112. void CookieManager::setCookies(const KURL& url, const String& value, CookieFilter filter)
  113. {
  114. // If the database hasn't been sync-ed at this point, force a sync load
  115. if (!m_syncedWithDatabase && !m_privateMode)
  116. m_cookieBackingStore->openAndLoadDatabaseSynchronously(cookieJar());
  117. CookieLog("CookieManager - Setting cookies");
  118. CookieParser parser(url);
  119. Vector<RefPtr<ParsedCookie> > cookies = parser.parse(value);
  120. for (size_t i = 0; i < cookies.size(); ++i) {
  121. BackingStoreRemovalPolicy treatment = m_privateMode ? DoNotRemoveFromBackingStore : RemoveFromBackingStore;
  122. checkAndTreatCookie(cookies[i], treatment, filter);
  123. }
  124. }
  125. void CookieManager::setCookies(const KURL& url, const Vector<String>& cookies, CookieFilter filter)
  126. {
  127. // If the database hasn't been sync-ed at this point, force a sync load
  128. if (!m_syncedWithDatabase && !m_privateMode)
  129. m_cookieBackingStore->openAndLoadDatabaseSynchronously(cookieJar());
  130. CookieLog("CookieManager - Setting cookies");
  131. CookieParser parser(url);
  132. for (size_t i = 0; i < cookies.size(); ++i) {
  133. BackingStoreRemovalPolicy treatment = m_privateMode ? DoNotRemoveFromBackingStore : RemoveFromBackingStore;
  134. if (RefPtr<ParsedCookie> parsedCookie = parser.parseOneCookie(cookies[i]))
  135. checkAndTreatCookie(parsedCookie, treatment, filter);
  136. }
  137. }
  138. String CookieManager::getCookie(const KURL& url, CookieFilter filter) const
  139. {
  140. // If the database hasn't been sync-ed at this point, force a sync load
  141. if (!m_syncedWithDatabase && !m_privateMode)
  142. m_cookieBackingStore->openAndLoadDatabaseSynchronously(cookieJar());
  143. Vector<RefPtr<ParsedCookie> > rawCookies;
  144. rawCookies.reserveInitialCapacity(s_maxCookieCountPerHost);
  145. // Retrieve cookies related to this url
  146. getRawCookies(rawCookies, url, filter);
  147. CookieLog("CookieManager - there are %d cookies in raw cookies\n", rawCookies.size());
  148. // Generate the cookie header string using the retrieved cookies
  149. StringBuilder cookieStringBuilder;
  150. cookieStringBuilder.reserveCapacity(512);
  151. size_t cookieSize = rawCookies.size();
  152. for (size_t i = 0; i < cookieSize; i++) {
  153. cookieStringBuilder.append(rawCookies[i]->toNameValuePair());
  154. if (i != cookieSize-1)
  155. cookieStringBuilder.append("; ");
  156. }
  157. CookieLog("CookieManager - cookieString is - %s\n", cookieStringBuilder.toString().utf8().data());
  158. return cookieStringBuilder.toString();
  159. }
  160. String CookieManager::generateHtmlFragmentForCookies()
  161. {
  162. // If the database hasn't been sync-ed at this point, force a sync load
  163. if (!m_syncedWithDatabase && !m_privateMode)
  164. m_cookieBackingStore->openAndLoadDatabaseSynchronously(cookieJar());
  165. CookieLog("CookieManager - generateHtmlFragmentForCookies\n");
  166. Vector<RefPtr<ParsedCookie> > cookieCandidates;
  167. for (HashMap<String, CookieMap*>::iterator it = m_managerMap.begin(); it != m_managerMap.end(); ++it)
  168. it->value->getAllChildCookies(&cookieCandidates);
  169. String result;
  170. RefPtr<ParsedCookie> cookie = 0;
  171. 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>"));
  172. for (size_t i = 0; i < cookieCandidates.size(); ++i) {
  173. cookie = cookieCandidates[i];
  174. result.append(String("<tr><td align=\"center\">"));
  175. result.append(cookie->domain());
  176. result.append(String("<td align=\"center\">"));
  177. result.append(cookie->path());
  178. result.append(String("<td align=\"center\">"));
  179. result.append(cookie->protocol());
  180. result.append(String("<td align=\"center\">"));
  181. result.append(cookie->name());
  182. result.append(String("<td align=\"center\" style= \"word-break:break-all\">"));
  183. result.append(cookie->value());
  184. result.append(String("<td align=\"center\">"));
  185. result.append(String(cookie->isSecure() ? "Yes" : "No"));
  186. result.append(String("<td align=\"center\">"));
  187. result.append(String(cookie->isHttpOnly() ? "Yes" : "No"));
  188. result.append(String("<td align=\"center\">"));
  189. result.append(String(cookie->isSession() ? "Yes" : "No"));
  190. result.append(String("</td></tr>"));
  191. }
  192. result.append(String("</table>"));
  193. return result;
  194. }
  195. void CookieManager::getRawCookies(Vector<RefPtr<ParsedCookie> > &stackOfCookies, const KURL& requestURL, CookieFilter filter) const
  196. {
  197. // Force a sync load of the database
  198. if (!m_syncedWithDatabase && !m_privateMode)
  199. m_cookieBackingStore->openAndLoadDatabaseSynchronously(cookieJar());
  200. 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());
  201. const bool invalidScheme = shouldIgnoreScheme(requestURL.protocol());
  202. const bool specialCaseForWebWorks = invalidScheme && m_shouldDumpAllCookies;
  203. const bool isConnectionSecure = requestURL.protocolIs("https") || requestURL.protocolIs("wss") || specialCaseForWebWorks;
  204. Vector<RefPtr<ParsedCookie> > cookieCandidates;
  205. Vector<CookieMap*> protocolsToSearch;
  206. // Special Case: If a server sets a "secure" cookie over a non-secure channel and tries to access the cookie
  207. // over a secure channel, it will not succeed because the secure protocol isn't mapped to the insecure protocol yet.
  208. // Set the map to the non-secure version, so it'll search the mapping for a secure cookie.
  209. CookieMap* targetMap = m_managerMap.get(requestURL.protocol());
  210. if (!targetMap && isConnectionSecure) {
  211. CookieLog("CookieManager - special case: secure protocol are not linked yet.");
  212. if (requestURL.protocolIs("https"))
  213. targetMap = m_managerMap.get("http");
  214. else if (requestURL.protocolIs("wss"))
  215. targetMap = m_managerMap.get("ws");
  216. }
  217. // Decide which scheme tree we should look at.
  218. // Return on invalid schemes. cookies are currently disabled on file and local.
  219. // We only want to enable them for WebWorks that enabled a special flag.
  220. if (specialCaseForWebWorks)
  221. copyValuesToVector(m_managerMap, protocolsToSearch);
  222. else if (invalidScheme)
  223. return;
  224. else {
  225. protocolsToSearch.append(targetMap);
  226. // FIXME: this is a hack for webworks apps; RFC 6265 says "Cookies do not provide isolation by scheme"
  227. // so we should not be checking protocols at all. See PR 135595
  228. if (m_shouldDumpAllCookies) {
  229. protocolsToSearch.append(m_managerMap.get("file"));
  230. protocolsToSearch.append(m_managerMap.get("local"));
  231. }
  232. }
  233. Vector<String> delimitedHost;
  234. // IP addresses are stored in a particular format (due to ipv6). Reduce the ip address so we can match
  235. // it with the one in memory.
  236. BlackBerry::Platform::String canonicalIP = BlackBerry::Platform::getCanonicalIPFormat(requestURL.host());
  237. if (!canonicalIP.empty())
  238. delimitedHost.append(String(canonicalIP.c_str()));
  239. else
  240. requestURL.host().lower().split(".", true, delimitedHost);
  241. // Go through all the protocol trees that we need to search for
  242. // and get all cookies that are valid for this domain
  243. for (size_t k = 0; k < protocolsToSearch.size(); k++) {
  244. CookieMap* currentMap = protocolsToSearch[k];
  245. // if no cookies exist for this protocol, break right away
  246. if (!currentMap)
  247. continue;
  248. CookieLog("CookieManager - looking at protocol map %s \n", currentMap->getName().utf8().data());
  249. // Special case for local and files - because WebApps expect to get ALL cookies from the backing-store on local protocol
  250. if (specialCaseForWebWorks) {
  251. CookieLog("CookieManager - special case find in protocol map - %s\n", currentMap->getName().utf8().data());
  252. currentMap->getAllChildCookies(&cookieCandidates);
  253. } else {
  254. // Get cookies from the null domain map
  255. currentMap->getAllCookies(&cookieCandidates);
  256. // Get cookies from Host-only cookies
  257. if (canonicalIP.empty()) {
  258. CookieLog("CookieManager - looking for host-only cookies for host - %s", requestURL.host().utf8().data());
  259. CookieMap* hostMap = currentMap->getSubdomainMap(requestURL.host());
  260. if (hostMap)
  261. hostMap->getAllCookies(&cookieCandidates);
  262. }
  263. // Get cookies from the valid domain maps
  264. int i = delimitedHost.size() - 1;
  265. while (i >= 0) {
  266. CookieLog("CookieManager - finding %s in currentmap\n", delimitedHost[i].utf8().data());
  267. currentMap = currentMap->getSubdomainMap(delimitedHost[i]);
  268. // if this subdomain/domain does not exist in our mapping then we simply exit
  269. if (!currentMap) {
  270. CookieLog("CookieManager - cannot find next map exiting the while loop.\n");
  271. break;
  272. }
  273. CookieLog("CookieManager - found the map, grabbing cookies from this map\n");
  274. currentMap->getAllCookies(&cookieCandidates);
  275. i--;
  276. }
  277. }
  278. }
  279. CookieLog("CookieManager - there are %d cookies in candidate\n", cookieCandidates.size());
  280. for (size_t i = 0; i < cookieCandidates.size(); ++i) {
  281. RefPtr<ParsedCookie> cookie = cookieCandidates[i];
  282. // According to the path-matches rules in RFC6265, section 5.1.4,
  283. // we should add a '/' at the end of cookie-path for comparison if the cookie-path is not end with '/'.
  284. String path = cookie->path();
  285. 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());
  286. if (!equalIgnoringCase(path, requestURL.path()) && !path.endsWith("/", false))
  287. path = path + "/";
  288. // Only secure connections have access to secure cookies. Unless specialCaseForWebWorks is true.
  289. // Get the cookies filtering out HttpOnly cookies if requested.
  290. if (requestURL.path().startsWith(path, false) && (isConnectionSecure || !cookie->isSecure()) && (filter == WithHttpOnlyCookies || !cookie->isHttpOnly())) {
  291. CookieLog("CookieManager - cookie chosen - %s\n", cookie->toString().utf8().data());
  292. cookie->setLastAccessed(currentTime());
  293. stackOfCookies.append(cookie);
  294. }
  295. }
  296. std::stable_sort(stackOfCookies.begin(), stackOfCookies.end(), cookieSorter);
  297. }
  298. void CookieManager::removeAllCookies(BackingStoreRemovalPolicy backingStoreRemoval)
  299. {
  300. HashMap<String, CookieMap*>::iterator first = m_managerMap.begin();
  301. HashMap<String, CookieMap*>::iterator end = m_managerMap.end();
  302. for (HashMap<String, CookieMap*>::iterator it = first; it != end; ++it)
  303. it->value->deleteAllCookiesAndDomains();
  304. if (backingStoreRemoval == RemoveFromBackingStore)
  305. m_cookieBackingStore->removeAll();
  306. m_count = 0;
  307. }
  308. void CookieManager::setCookieJar(const char* fileName)
  309. {
  310. m_cookieJarFileName = String(fileName);
  311. m_cookieBackingStore->open(m_cookieJarFileName);
  312. }
  313. void CookieManager::checkAndTreatCookie(PassRefPtr<ParsedCookie> prpCandidateCookie, BackingStoreRemovalPolicy postToBackingStore, CookieFilter filter)
  314. {
  315. RefPtr<ParsedCookie> candidateCookie = prpCandidateCookie;
  316. CookieLog("CookieManager - checkAndTreatCookie - processing url with domain - %s & protocol %s\n", candidateCookie->domain().utf8().data(), candidateCookie->protocol().utf8().data());
  317. // Delete invalid cookies:
  318. // 1) A cookie which is not from http shouldn't have a httpOnly property.
  319. // 2) Cookies coming from schemes that we do not support and the special flag isn't on
  320. if ((filter == NoHttpOnlyCookie && candidateCookie->isHttpOnly()) || (shouldIgnoreScheme(candidateCookie->protocol()) && !m_shouldDumpAllCookies))
  321. return;
  322. const bool ignoreDomain = (candidateCookie->protocol() == "file" || candidateCookie->protocol() == "local");
  323. // Determine which protocol tree to add the cookie to. Create one if necessary.
  324. CookieMap* curMap = 0;
  325. if (m_managerMap.contains(candidateCookie->protocol()))
  326. curMap = m_managerMap.get(candidateCookie->protocol());
  327. else {
  328. // Check if it is a secure version, if it is, link it to the non-secure version
  329. // Link curMap to the new protocol as well as the old one if it doesn't exist
  330. if (candidateCookie->protocol() == "https") {
  331. curMap = m_managerMap.get("http");
  332. if (!curMap) {
  333. curMap = new CookieMap("http");
  334. m_managerMap.add("http", curMap);
  335. }
  336. } else if (candidateCookie->protocol() == "wss") {
  337. curMap = m_managerMap.get("ws");
  338. if (!curMap) {
  339. curMap = new CookieMap("ws");
  340. m_managerMap.add("ws", curMap);
  341. }
  342. } else
  343. curMap = new CookieMap(candidateCookie->protocol());
  344. CookieLog("CookieManager - adding protocol cookiemap - %s\n", curMap->getName().utf8().data());
  345. m_managerMap.add(candidateCookie->protocol(), curMap);
  346. }
  347. // If protocol support domain, we have to traverse the domain tree to find the right
  348. // cookieMap to handle with
  349. if (!ignoreDomain)
  350. curMap = findOrCreateCookieMap(curMap, candidateCookie);
  351. // Now that we have the proper map for this cookie, we can modify it
  352. // If cookie does not exist and has expired, delete it
  353. // If cookie exists and it has expired, so we must remove it from the map, if not update it
  354. // If cookie expired and came from the BackingStore (therefore does not exist), we have to remove from database
  355. // If cookie does not exist & it's valid, add it to the current map
  356. if (candidateCookie->hasExpired() || candidateCookie->isForceExpired()) {
  357. // Special case for getBackingStoreCookies() to catch expired cookies
  358. if (postToBackingStore == BackingStoreCookieEntry)
  359. m_cookieBackingStore->remove(candidateCookie);
  360. else if (curMap) {
  361. // RemoveCookie will return 0 if the cookie doesn't exist.
  362. RefPtr<ParsedCookie> expired = curMap->removeCookie(candidateCookie, filter);
  363. // Cookie is useless, Remove the cookie from the backingstore if it exists.
  364. // Backup check for BackingStoreCookieEntry incase someone incorrectly uses this enum.
  365. if (expired && postToBackingStore != BackingStoreCookieEntry && !expired->isSession()) {
  366. CookieLog("CookieManager - expired cookie is nonsession, deleting from db");
  367. m_cookieBackingStore->remove(expired);
  368. }
  369. }
  370. } else {
  371. ASSERT(curMap);
  372. CookieLog("CookieManager - adding cookiemap - %s\n", curMap->getName().utf8().data());
  373. addCookieToMap(curMap, candidateCookie, postToBackingStore, filter);
  374. }
  375. }
  376. void CookieManager::addCookieToMap(CookieMap* targetMap, PassRefPtr<ParsedCookie> prpCandidateCookie, BackingStoreRemovalPolicy postToBackingStore, CookieFilter filter)
  377. {
  378. RefPtr<ParsedCookie> replacedCookie = 0;
  379. RefPtr<ParsedCookie> candidateCookie = prpCandidateCookie;
  380. if (!targetMap->addOrReplaceCookie(candidateCookie, replacedCookie, filter)) {
  381. CookieLog("CookieManager - rejecting new cookie - %s.\n", candidateCookie->toString().utf8().data());
  382. return;
  383. }
  384. if (replacedCookie) {
  385. CookieLog("CookieManager - updating new cookie - %s.\n", candidateCookie->toString().utf8().data());
  386. // A cookie was replaced in targetMap.
  387. // If old cookie is non-session and new one is, we have to delete it from backingstore
  388. // If new cookie is non-session and old one is, we have to add it to backingstore
  389. // If both sessions are non-session, then we update it in the backingstore
  390. bool newIsSession = candidateCookie->isSession();
  391. bool oldIsSession = replacedCookie->isSession();
  392. if (postToBackingStore == RemoveFromBackingStore) {
  393. if (!newIsSession && !oldIsSession)
  394. m_cookieBackingStore->update(candidateCookie);
  395. else if (newIsSession && !oldIsSession) {
  396. // Must manually decrease the counter because it was not counted when
  397. // the cookie was removed in cookieVector.
  398. removedCookie();
  399. m_cookieBackingStore->remove(replacedCookie);
  400. } else if (!newIsSession && oldIsSession) {
  401. // Must manually increase the counter because it was not counted when
  402. // the cookie was added in cookieVector.
  403. addedCookie();
  404. m_cookieBackingStore->insert(candidateCookie);
  405. }
  406. }
  407. return;
  408. }
  409. CookieLog("CookieManager - adding new cookie - %s.\n", candidateCookie->toString().utf8().data());
  410. RefPtr<ParsedCookie> oldestCookie = 0;
  411. // Check if we have not reached the per cookie domain limit.
  412. // If that is not true, we check if the global limit has been reached if backingstore mode is on
  413. // Two points:
  414. // 1) We only do a global check if backingstore mode is on because the global cookie limit only
  415. // counts session cookies that are saved in the database. If the user goes over the limit
  416. // when they are in private mode, we know that the total cookie limit will be under the limit
  417. // once the user goes back to normal mode (memory deleted and reloaded from the database)
  418. // 2) We use else if for this statement because if we remove a cookie in the 1st statement
  419. // then it means the global count will never exceed the limit
  420. CookieLimitLog("CookieManager - local count: %d global count: %d", targetMap->count(), m_count);
  421. if (targetMap->count() > s_maxCookieCountPerHost) {
  422. CookieLog("CookieManager - deleting oldest cookie from this map due to domain count.\n");
  423. oldestCookie = targetMap->removeOldestCookie();
  424. } else if (m_count > s_globalMaxCookieCount && (postToBackingStore != DoNotRemoveFromBackingStore)) {
  425. CookieLimitLog("CookieManager - Global limit reached, initiate cookie limit clean up.");
  426. initiateCookieLimitCleanUp();
  427. }
  428. // Only add non session cookie to the backing store.
  429. if (postToBackingStore == RemoveFromBackingStore) {
  430. if (oldestCookie && !oldestCookie->isSession()) {
  431. CookieLog("CookieManager - oldestCookie exists, deleting it from backingstore and destructing.\n");
  432. m_cookieBackingStore->remove(oldestCookie);
  433. }
  434. if (!candidateCookie->isSession())
  435. m_cookieBackingStore->insert(candidateCookie);
  436. }
  437. }
  438. void CookieManager::getBackingStoreCookies()
  439. {
  440. // Make sure private mode is off when the database thread calls this method
  441. if (m_privateMode)
  442. return;
  443. // If there exists cookies in memory, flush them out and we'll load everything from the database again
  444. if (m_count)
  445. removeAllCookies(DoNotRemoveFromBackingStore);
  446. Vector<RefPtr<ParsedCookie> > cookies;
  447. m_cookieBackingStore->getCookiesFromDatabase(cookies);
  448. CookieLog("CookieManager - Backingstore has %d cookies, loading them in memory now", cookies.size());
  449. for (size_t i = 0; i < cookies.size(); ++i) {
  450. RefPtr<ParsedCookie> newCookie = cookies[i];
  451. // The IP flag is not persisted in the database.
  452. if (BlackBerry::Platform::isIPAddress(newCookie->domain()))
  453. newCookie->setDomain(newCookie->domain(), true);
  454. checkAndTreatCookie(newCookie, BackingStoreCookieEntry);
  455. }
  456. CookieLog("CookieManager - Backingstore loading complete.");
  457. m_syncedWithDatabase = true;
  458. }
  459. void CookieManager::setPrivateMode(bool privateMode)
  460. {
  461. if (m_privateMode == privateMode)
  462. return;
  463. m_privateMode = privateMode;
  464. // If we switched to private mode when the database cookies haven't loaded into memory yet
  465. // we can return because there's nothing in memory anyway.
  466. if (m_privateMode && !m_syncedWithDatabase)
  467. return;
  468. removeAllCookies(DoNotRemoveFromBackingStore);
  469. // If we are switching back to public mode, reload the database to memory.
  470. if (!m_privateMode)
  471. getBackingStoreCookies();
  472. }
  473. CookieMap* CookieManager::findOrCreateCookieMap(CookieMap* protocolMap, const PassRefPtr<ParsedCookie> candidateCookie)
  474. {
  475. // Explode the domain with the '.' delimiter
  476. Vector<String> delimitedHost;
  477. // If the domain is an IP address or is a host-only domain, don't split it.
  478. if (candidateCookie->domainIsIPAddress() || candidateCookie->isHostOnly())
  479. delimitedHost.append(candidateCookie->domain());
  480. else
  481. candidateCookie->domain().split(".", delimitedHost);
  482. CookieMap* curMap = protocolMap;
  483. size_t hostSize = delimitedHost.size();
  484. CookieLog("CookieManager - looking at protocol map %s \n", protocolMap->getName().utf8().data());
  485. // Find & create necessary CookieMaps by traversing down the domain tree
  486. // Each CookieMap represent a subsection of the domain, delimited by "."
  487. int i = hostSize - 1;
  488. while (i >= 0) {
  489. CookieLog("CookieManager - finding %s in currentmap\n", delimitedHost[i].utf8().data());
  490. CookieMap* nextMap = curMap->getSubdomainMap(delimitedHost[i]);
  491. if (!nextMap) {
  492. CookieLog("CookieManager - cannot find map\n");
  493. if (candidateCookie->hasExpired())
  494. return 0;
  495. CookieLog("CookieManager - creating %s in currentmap %s\n", delimitedHost[i].utf8().data(), curMap->getName().utf8().data());
  496. nextMap = new CookieMap(delimitedHost[i]);
  497. CookieLog("CookieManager - adding subdomain to map\n");
  498. curMap->addSubdomainMap(delimitedHost[i], nextMap);
  499. }
  500. curMap = nextMap;
  501. i--;
  502. }
  503. return curMap;
  504. }
  505. void CookieManager::removeCookieWithName(const KURL& url, const String& cookieName)
  506. {
  507. // Dispatch the message because the database cookies are not loaded in memory yet.
  508. if (!m_syncedWithDatabase && !m_privateMode) {
  509. typedef void (WebCore::CookieManager::*FunctionType)(const KURL&, const String&);
  510. BlackBerry::Platform::webKitThreadMessageClient()->dispatchMessage(
  511. BlackBerry::Platform::createMethodCallMessage<FunctionType, CookieManager, const KURL, const String>(
  512. &CookieManager::removeCookieWithName, this, url, cookieName));
  513. return;
  514. }
  515. // We get all cookies from all domains that domain matches the request domain
  516. // and delete any cookies with the specified name that path matches the request path
  517. Vector<RefPtr<ParsedCookie> > results;
  518. getRawCookies(results, url, WithHttpOnlyCookies);
  519. // Delete the cookies that path matches the request path
  520. for (size_t i = 0; i < results.size(); i++) {
  521. RefPtr<ParsedCookie> cookie = results[i];
  522. if (!equalIgnoringCase(cookie->name(), cookieName))
  523. continue;
  524. if (url.path().startsWith(cookie->path(), false)) {
  525. cookie->forceExpire();
  526. checkAndTreatCookie(cookie, RemoveFromBackingStore);
  527. }
  528. }
  529. }
  530. void CookieManager::initiateCookieLimitCleanUp()
  531. {
  532. if (!m_limitTimer.isActive()) {
  533. CookieLog("CookieManager - Starting a timer for cookie cleanup");
  534. m_limitTimer.startOneShot(s_delayToStartCookieCleanup);
  535. } else {
  536. #ifndef NDEBUG
  537. CookieLog("CookieManager - Cookie cleanup timer already running");
  538. #endif
  539. }
  540. }
  541. void CookieManager::cookieLimitCleanUp(Timer<CookieManager>* timer)
  542. {
  543. ASSERT_UNUSED(timer, timer == &m_limitTimer);
  544. CookieLimitLog("CookieManager - Starting cookie clean up");
  545. size_t numberOfCookiesOverLimit = (m_count > s_globalMaxCookieCount) ? m_count - s_globalMaxCookieCount : 0;
  546. size_t amountToDelete = s_cookiesToDeleteWhenLimitReached + numberOfCookiesOverLimit;
  547. CookieLimitLog("CookieManager - Excess: %d Amount to Delete: %d", numberOfCookiesOverLimit, amountToDelete);
  548. // Call the database to delete 'amountToDelete' of cookies
  549. Vector<RefPtr<ParsedCookie> > cookiesToDelete;
  550. cookiesToDelete.reserveInitialCapacity(amountToDelete);
  551. CookieLimitLog("CookieManager - Calling database to clean up");
  552. m_cookieBackingStore->getCookiesFromDatabase(cookiesToDelete, amountToDelete);
  553. // Cookies are ordered in ASC order by lastAccessed
  554. for (size_t i = 0; i < amountToDelete; ++i) {
  555. // Expire them and call checkandtreat to delete them from memory and database
  556. RefPtr<ParsedCookie> newCookie = cookiesToDelete[i];
  557. CookieLimitLog("CookieManager - Expire cookie: %s and delete", newCookie->toString().utf8().data());
  558. newCookie->forceExpire();
  559. checkAndTreatCookie(newCookie, RemoveFromBackingStore);
  560. }
  561. CookieLimitLog("CookieManager - Cookie clean up complete.");
  562. }
  563. } // namespace WebCore