/extensions/cookie/test/unit/head_cookies.js

http://github.com/zpao/v8monkey · JavaScript · 571 lines · 467 code · 76 blank · 28 comment · 26 complexity · c594f38fa1e431560a4a9f26c1d93322 MD5 · raw file

  1. /* Any copyright is dedicated to the Public Domain.
  2. * http://creativecommons.org/publicdomain/zero/1.0/
  3. */
  4. Components.utils.import("resource://gre/modules/Services.jsm");
  5. Components.utils.import("resource://gre/modules/NetUtil.jsm");
  6. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  7. const Cc = Components.classes;
  8. const Ci = Components.interfaces;
  9. const Cr = Components.results;
  10. XPCOMUtils.defineLazyServiceGetter(Services, "cookies",
  11. "@mozilla.org/cookieService;1",
  12. "nsICookieService");
  13. XPCOMUtils.defineLazyServiceGetter(Services, "cookiemgr",
  14. "@mozilla.org/cookiemanager;1",
  15. "nsICookieManager2");
  16. XPCOMUtils.defineLazyServiceGetter(Services, "etld",
  17. "@mozilla.org/network/effective-tld-service;1",
  18. "nsIEffectiveTLDService");
  19. XPCOMUtils.defineLazyServiceGetter(Services, "permissions",
  20. "@mozilla.org/permissionmanager;1",
  21. "nsIPermissionManager");
  22. XPCOMUtils.defineLazyServiceGetter(Services, "pb",
  23. "@mozilla.org/privatebrowsing;1",
  24. "nsIPrivateBrowsingService");
  25. function do_check_throws(f, result, stack)
  26. {
  27. if (!stack)
  28. stack = Components.stack.caller;
  29. try {
  30. f();
  31. } catch (exc) {
  32. if (exc.result == result)
  33. return;
  34. do_throw("expected result " + result + ", caught " + exc, stack);
  35. }
  36. do_throw("expected result " + result + ", none thrown", stack);
  37. }
  38. // Helper to step a generator function and catch a StopIteration exception.
  39. function do_run_generator(generator)
  40. {
  41. try {
  42. generator.next();
  43. } catch (e) {
  44. if (e != StopIteration)
  45. do_throw("caught exception " + e, Components.stack.caller);
  46. }
  47. }
  48. // Helper to finish a generator function test.
  49. function do_finish_generator_test(generator)
  50. {
  51. do_execute_soon(function() {
  52. generator.close();
  53. do_test_finished();
  54. });
  55. }
  56. function _observer(generator, topic) {
  57. Services.obs.addObserver(this, topic, false);
  58. this.generator = generator;
  59. this.topic = topic;
  60. }
  61. _observer.prototype = {
  62. observe: function (subject, topic, data) {
  63. do_check_eq(this.topic, topic);
  64. Services.obs.removeObserver(this, this.topic);
  65. // Continue executing the generator function.
  66. if (this.generator)
  67. do_run_generator(this.generator);
  68. this.generator = null;
  69. this.topic = null;
  70. }
  71. }
  72. // Close the cookie database. If a generator is supplied, it will be invoked
  73. // once the close is complete.
  74. function do_close_profile(generator, cleanse) {
  75. // Register an observer for db close.
  76. let obs = new _observer(generator, "cookie-db-closed");
  77. // Close the db.
  78. let service = Services.cookies.QueryInterface(Ci.nsIObserver);
  79. service.observe(null, "profile-before-change", cleanse ? cleanse : "");
  80. }
  81. // Load the cookie database. If a generator is supplied, it will be invoked
  82. // once the load is complete.
  83. function do_load_profile(generator) {
  84. // Register an observer for read completion.
  85. let obs = new _observer(generator, "cookie-db-read");
  86. // Load the profile.
  87. let service = Services.cookies.QueryInterface(Ci.nsIObserver);
  88. service.observe(null, "profile-do-change", "");
  89. }
  90. // Set four cookies; with & without channel, http and non-http; and test
  91. // the cookie count against 'expected' after each set.
  92. function do_set_cookies(uri, channel, session, expected) {
  93. let suffix = session ? "" : "; max-age=1000";
  94. // without channel
  95. Services.cookies.setCookieString(uri, null, "oh=hai" + suffix, null);
  96. do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[0]);
  97. // with channel
  98. Services.cookies.setCookieString(uri, null, "can=has" + suffix, channel);
  99. do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[1]);
  100. // without channel, from http
  101. Services.cookies.setCookieStringFromHttp(uri, null, null, "cheez=burger" + suffix, null, null);
  102. do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[2]);
  103. // with channel, from http
  104. Services.cookies.setCookieStringFromHttp(uri, null, null, "hot=dog" + suffix, null, channel);
  105. do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[3]);
  106. }
  107. function do_count_enumerator(enumerator) {
  108. let i = 0;
  109. while (enumerator.hasMoreElements()) {
  110. enumerator.getNext();
  111. ++i;
  112. }
  113. return i;
  114. }
  115. function do_count_cookies() {
  116. return do_count_enumerator(Services.cookiemgr.enumerator);
  117. }
  118. // Helper object to store cookie data.
  119. function Cookie(name,
  120. value,
  121. host,
  122. path,
  123. expiry,
  124. lastAccessed,
  125. creationTime,
  126. isSession,
  127. isSecure,
  128. isHttpOnly)
  129. {
  130. this.name = name;
  131. this.value = value;
  132. this.host = host;
  133. this.path = path;
  134. this.expiry = expiry;
  135. this.lastAccessed = lastAccessed;
  136. this.creationTime = creationTime;
  137. this.isSession = isSession;
  138. this.isSecure = isSecure;
  139. this.isHttpOnly = isHttpOnly;
  140. let strippedHost = host.charAt(0) == '.' ? host.slice(1) : host;
  141. try {
  142. this.baseDomain = Services.etld.getBaseDomainFromHost(strippedHost);
  143. } catch (e) {
  144. if (e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS ||
  145. e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS)
  146. this.baseDomain = strippedHost;
  147. }
  148. }
  149. // Object representing a database connection and associated statements. The
  150. // implementation varies depending on schema version.
  151. function CookieDatabaseConnection(file, schema)
  152. {
  153. // Manually generate a cookies.sqlite file with appropriate rows, columns,
  154. // and schema version. If it already exists, just set up our statements.
  155. let exists = file.exists();
  156. this.db = Services.storage.openDatabase(file);
  157. this.schema = schema;
  158. if (!exists)
  159. this.db.schemaVersion = schema;
  160. switch (schema) {
  161. case 1:
  162. {
  163. if (!exists) {
  164. this.db.executeSimpleSQL(
  165. "CREATE TABLE moz_cookies ( \
  166. id INTEGER PRIMARY KEY, \
  167. name TEXT, \
  168. value TEXT, \
  169. host TEXT, \
  170. path TEXT, \
  171. expiry INTEGER, \
  172. isSecure INTEGER, \
  173. isHttpOnly INTEGER)");
  174. }
  175. this.stmtInsert = this.db.createStatement(
  176. "INSERT INTO moz_cookies ( \
  177. id, \
  178. name, \
  179. value, \
  180. host, \
  181. path, \
  182. expiry, \
  183. isSecure, \
  184. isHttpOnly) \
  185. VALUES ( \
  186. :id, \
  187. :name, \
  188. :value, \
  189. :host, \
  190. :path, \
  191. :expiry, \
  192. :isSecure, \
  193. :isHttpOnly)");
  194. this.stmtDelete = this.db.createStatement(
  195. "DELETE FROM moz_cookies WHERE id = :id");
  196. break;
  197. }
  198. case 2:
  199. {
  200. if (!exists) {
  201. this.db.executeSimpleSQL(
  202. "CREATE TABLE moz_cookies ( \
  203. id INTEGER PRIMARY KEY, \
  204. name TEXT, \
  205. value TEXT, \
  206. host TEXT, \
  207. path TEXT, \
  208. expiry INTEGER, \
  209. lastAccessed INTEGER, \
  210. isSecure INTEGER, \
  211. isHttpOnly INTEGER)");
  212. }
  213. this.stmtInsert = this.db.createStatement(
  214. "INSERT OR REPLACE INTO moz_cookies ( \
  215. id, \
  216. name, \
  217. value, \
  218. host, \
  219. path, \
  220. expiry, \
  221. lastAccessed, \
  222. isSecure, \
  223. isHttpOnly) \
  224. VALUES ( \
  225. :id, \
  226. :name, \
  227. :value, \
  228. :host, \
  229. :path, \
  230. :expiry, \
  231. :lastAccessed, \
  232. :isSecure, \
  233. :isHttpOnly)");
  234. this.stmtDelete = this.db.createStatement(
  235. "DELETE FROM moz_cookies WHERE id = :id");
  236. this.stmtUpdate = this.db.createStatement(
  237. "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id");
  238. break;
  239. }
  240. case 3:
  241. {
  242. if (!exists) {
  243. this.db.executeSimpleSQL(
  244. "CREATE TABLE moz_cookies ( \
  245. id INTEGER PRIMARY KEY, \
  246. baseDomain TEXT, \
  247. name TEXT, \
  248. value TEXT, \
  249. host TEXT, \
  250. path TEXT, \
  251. expiry INTEGER, \
  252. lastAccessed INTEGER, \
  253. isSecure INTEGER, \
  254. isHttpOnly INTEGER)");
  255. this.db.executeSimpleSQL(
  256. "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)");
  257. }
  258. this.stmtInsert = this.db.createStatement(
  259. "INSERT INTO moz_cookies ( \
  260. id, \
  261. baseDomain, \
  262. name, \
  263. value, \
  264. host, \
  265. path, \
  266. expiry, \
  267. lastAccessed, \
  268. isSecure, \
  269. isHttpOnly) \
  270. VALUES ( \
  271. :id, \
  272. :baseDomain, \
  273. :name, \
  274. :value, \
  275. :host, \
  276. :path, \
  277. :expiry, \
  278. :lastAccessed, \
  279. :isSecure, \
  280. :isHttpOnly)");
  281. this.stmtDelete = this.db.createStatement(
  282. "DELETE FROM moz_cookies WHERE id = :id");
  283. this.stmtUpdate = this.db.createStatement(
  284. "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id");
  285. break;
  286. }
  287. case 4:
  288. {
  289. if (!exists) {
  290. this.db.executeSimpleSQL(
  291. "CREATE TABLE moz_cookies ( \
  292. id INTEGER PRIMARY KEY, \
  293. baseDomain TEXT, \
  294. name TEXT, \
  295. value TEXT, \
  296. host TEXT, \
  297. path TEXT, \
  298. expiry INTEGER, \
  299. lastAccessed INTEGER, \
  300. creationTime INTEGER, \
  301. isSecure INTEGER, \
  302. isHttpOnly INTEGER \
  303. CONSTRAINT moz_uniqueid UNIQUE (name, host, path))");
  304. this.db.executeSimpleSQL(
  305. "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)");
  306. this.db.executeSimpleSQL(
  307. "PRAGMA journal_mode = WAL");
  308. }
  309. this.stmtInsert = this.db.createStatement(
  310. "INSERT INTO moz_cookies ( \
  311. baseDomain, \
  312. name, \
  313. value, \
  314. host, \
  315. path, \
  316. expiry, \
  317. lastAccessed, \
  318. creationTime, \
  319. isSecure, \
  320. isHttpOnly) \
  321. VALUES ( \
  322. :baseDomain, \
  323. :name, \
  324. :value, \
  325. :host, \
  326. :path, \
  327. :expiry, \
  328. :lastAccessed, \
  329. :creationTime, \
  330. :isSecure, \
  331. :isHttpOnly)");
  332. this.stmtDelete = this.db.createStatement(
  333. "DELETE FROM moz_cookies \
  334. WHERE name = :name AND host = :host AND path = :path");
  335. this.stmtUpdate = this.db.createStatement(
  336. "UPDATE moz_cookies SET lastAccessed = :lastAccessed \
  337. WHERE name = :name AND host = :host AND path = :path");
  338. break;
  339. }
  340. default:
  341. do_throw("unrecognized schemaVersion!");
  342. }
  343. }
  344. CookieDatabaseConnection.prototype =
  345. {
  346. insertCookie: function(cookie)
  347. {
  348. if (!(cookie instanceof Cookie))
  349. do_throw("not a cookie");
  350. switch (this.schema)
  351. {
  352. case 1:
  353. this.stmtInsert.bindByName("id", cookie.creationTime);
  354. this.stmtInsert.bindByName("name", cookie.name);
  355. this.stmtInsert.bindByName("value", cookie.value);
  356. this.stmtInsert.bindByName("host", cookie.host);
  357. this.stmtInsert.bindByName("path", cookie.path);
  358. this.stmtInsert.bindByName("expiry", cookie.expiry);
  359. this.stmtInsert.bindByName("isSecure", cookie.isSecure);
  360. this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
  361. break;
  362. case 2:
  363. this.stmtInsert.bindByName("id", cookie.creationTime);
  364. this.stmtInsert.bindByName("name", cookie.name);
  365. this.stmtInsert.bindByName("value", cookie.value);
  366. this.stmtInsert.bindByName("host", cookie.host);
  367. this.stmtInsert.bindByName("path", cookie.path);
  368. this.stmtInsert.bindByName("expiry", cookie.expiry);
  369. this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
  370. this.stmtInsert.bindByName("isSecure", cookie.isSecure);
  371. this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
  372. break;
  373. case 3:
  374. this.stmtInsert.bindByName("id", cookie.creationTime);
  375. this.stmtInsert.bindByName("baseDomain", cookie.baseDomain);
  376. this.stmtInsert.bindByName("name", cookie.name);
  377. this.stmtInsert.bindByName("value", cookie.value);
  378. this.stmtInsert.bindByName("host", cookie.host);
  379. this.stmtInsert.bindByName("path", cookie.path);
  380. this.stmtInsert.bindByName("expiry", cookie.expiry);
  381. this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
  382. this.stmtInsert.bindByName("isSecure", cookie.isSecure);
  383. this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
  384. break;
  385. case 4:
  386. this.stmtInsert.bindByName("baseDomain", cookie.baseDomain);
  387. this.stmtInsert.bindByName("name", cookie.name);
  388. this.stmtInsert.bindByName("value", cookie.value);
  389. this.stmtInsert.bindByName("host", cookie.host);
  390. this.stmtInsert.bindByName("path", cookie.path);
  391. this.stmtInsert.bindByName("expiry", cookie.expiry);
  392. this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed);
  393. this.stmtInsert.bindByName("creationTime", cookie.creationTime);
  394. this.stmtInsert.bindByName("isSecure", cookie.isSecure);
  395. this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly);
  396. break;
  397. default:
  398. do_throw("unrecognized schemaVersion!");
  399. }
  400. do_execute_stmt(this.stmtInsert);
  401. },
  402. deleteCookie: function(cookie)
  403. {
  404. if (!(cookie instanceof Cookie))
  405. do_throw("not a cookie");
  406. switch (this.db.schemaVersion)
  407. {
  408. case 1:
  409. case 2:
  410. case 3:
  411. this.stmtDelete.bindByName("id", cookie.creationTime);
  412. break;
  413. case 4:
  414. this.stmtDelete.bindByName("name", cookie.name);
  415. this.stmtDelete.bindByName("host", cookie.host);
  416. this.stmtDelete.bindByName("path", cookie.path);
  417. break;
  418. default:
  419. do_throw("unrecognized schemaVersion!");
  420. }
  421. do_execute_stmt(this.stmtDelete);
  422. },
  423. updateCookie: function(cookie)
  424. {
  425. if (!(cookie instanceof Cookie))
  426. do_throw("not a cookie");
  427. switch (this.db.schemaVersion)
  428. {
  429. case 1:
  430. do_throw("can't update a schema 1 cookie!");
  431. case 2:
  432. case 3:
  433. this.stmtUpdate.bindByName("id", cookie.creationTime);
  434. this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed);
  435. break;
  436. case 4:
  437. this.stmtDelete.bindByName("name", cookie.name);
  438. this.stmtDelete.bindByName("host", cookie.host);
  439. this.stmtDelete.bindByName("path", cookie.path);
  440. this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed);
  441. break;
  442. default:
  443. do_throw("unrecognized schemaVersion!");
  444. }
  445. do_execute_stmt(this.stmtUpdate);
  446. },
  447. close: function()
  448. {
  449. this.stmtInsert.finalize();
  450. this.stmtDelete.finalize();
  451. if (this.stmtUpdate)
  452. this.stmtUpdate.finalize();
  453. this.db.close();
  454. this.stmtInsert = null;
  455. this.stmtDelete = null;
  456. this.stmtUpdate = null;
  457. this.db = null;
  458. }
  459. }
  460. function do_get_cookie_file(profile)
  461. {
  462. let file = profile.clone();
  463. file.append("cookies.sqlite");
  464. return file;
  465. }
  466. // Count the cookies from 'host' in a database. If 'host' is null, count all
  467. // cookies.
  468. function do_count_cookies_in_db(connection, host)
  469. {
  470. let select = null;
  471. if (host) {
  472. select = connection.createStatement(
  473. "SELECT COUNT(1) FROM moz_cookies WHERE host = :host");
  474. select.bindByName("host", host);
  475. } else {
  476. select = connection.createStatement(
  477. "SELECT COUNT(1) FROM moz_cookies");
  478. }
  479. select.executeStep();
  480. let result = select.getInt32(0);
  481. select.reset();
  482. select.finalize();
  483. return result;
  484. }
  485. // Execute 'stmt', ensuring that we reset it if it throws.
  486. function do_execute_stmt(stmt)
  487. {
  488. try {
  489. stmt.executeStep();
  490. stmt.reset();
  491. } catch (e) {
  492. stmt.reset();
  493. throw e;
  494. }
  495. }