diff options
Diffstat (limited to 'extensions/cookie/test/unit/head_cookies.js')
-rw-r--r-- | extensions/cookie/test/unit/head_cookies.js | 570 |
1 files changed, 570 insertions, 0 deletions
diff --git a/extensions/cookie/test/unit/head_cookies.js b/extensions/cookie/test/unit/head_cookies.js new file mode 100644 index 000000000..fe4c0a53d --- /dev/null +++ b/extensions/cookie/test/unit/head_cookies.js @@ -0,0 +1,570 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +Components.utils.import("resource://gre/modules/Services.jsm"); +Components.utils.import("resource://gre/modules/NetUtil.jsm"); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cr = Components.results; + +XPCOMUtils.defineLazyServiceGetter(Services, "cookies", + "@mozilla.org/cookieService;1", + "nsICookieService"); +XPCOMUtils.defineLazyServiceGetter(Services, "cookiemgr", + "@mozilla.org/cookiemanager;1", + "nsICookieManager2"); + +XPCOMUtils.defineLazyServiceGetter(Services, "etld", + "@mozilla.org/network/effective-tld-service;1", + "nsIEffectiveTLDService"); + +function do_check_throws(f, result, stack) +{ + if (!stack) + stack = Components.stack.caller; + + try { + f(); + } catch (exc) { + if (exc.result == result) + return; + do_throw("expected result " + result + ", caught " + exc, stack); + } + do_throw("expected result " + result + ", none thrown", stack); +} + +// Helper to step a generator function and catch a StopIteration exception. +function do_run_generator(generator) +{ + try { + generator.next(); + } catch (e) { + if (e != StopIteration) + do_throw("caught exception " + e, Components.stack.caller); + } +} + +// Helper to finish a generator function test. +function do_finish_generator_test(generator) +{ + do_execute_soon(function() { + generator.close(); + do_test_finished(); + }); +} + +function _observer(generator, topic) { + Services.obs.addObserver(this, topic, false); + + this.generator = generator; + this.topic = topic; +} + +_observer.prototype = { + observe: function (subject, topic, data) { + do_check_eq(this.topic, topic); + + Services.obs.removeObserver(this, this.topic); + + // Continue executing the generator function. + if (this.generator) + do_run_generator(this.generator); + + this.generator = null; + this.topic = null; + } +} + +// Close the cookie database. If a generator is supplied, it will be invoked +// once the close is complete. +function do_close_profile(generator) { + // Register an observer for db close. + let obs = new _observer(generator, "cookie-db-closed"); + + // Close the db. + let service = Services.cookies.QueryInterface(Ci.nsIObserver); + service.observe(null, "profile-before-change", "shutdown-persist"); +} + +// Load the cookie database. If a generator is supplied, it will be invoked +// once the load is complete. +function do_load_profile(generator) { + // Register an observer for read completion. + let obs = new _observer(generator, "cookie-db-read"); + + // Load the profile. + let service = Services.cookies.QueryInterface(Ci.nsIObserver); + service.observe(null, "profile-do-change", ""); +} + +// Set a single session cookie using http and test the cookie count +// against 'expected' +function do_set_single_http_cookie(uri, channel, expected) { + Services.cookies.setCookieStringFromHttp(uri, null, null, "foo=bar", null, channel); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected); +} + +// Set four cookies; with & without channel, http and non-http; and test +// the cookie count against 'expected' after each set. +function do_set_cookies(uri, channel, session, expected) { + let suffix = session ? "" : "; max-age=1000"; + + // without channel + Services.cookies.setCookieString(uri, null, "oh=hai" + suffix, null); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[0]); + // with channel + Services.cookies.setCookieString(uri, null, "can=has" + suffix, channel); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[1]); + // without channel, from http + Services.cookies.setCookieStringFromHttp(uri, null, null, "cheez=burger" + suffix, null, null); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[2]); + // with channel, from http + Services.cookies.setCookieStringFromHttp(uri, null, null, "hot=dog" + suffix, null, channel); + do_check_eq(Services.cookiemgr.countCookiesFromHost(uri.host), expected[3]); +} + +function do_count_enumerator(enumerator) { + let i = 0; + while (enumerator.hasMoreElements()) { + enumerator.getNext(); + ++i; + } + return i; +} + +function do_count_cookies() { + return do_count_enumerator(Services.cookiemgr.enumerator); +} + +// Helper object to store cookie data. +function Cookie(name, + value, + host, + path, + expiry, + lastAccessed, + creationTime, + isSession, + isSecure, + isHttpOnly) +{ + this.name = name; + this.value = value; + this.host = host; + this.path = path; + this.expiry = expiry; + this.lastAccessed = lastAccessed; + this.creationTime = creationTime; + this.isSession = isSession; + this.isSecure = isSecure; + this.isHttpOnly = isHttpOnly; + + let strippedHost = host.charAt(0) == '.' ? host.slice(1) : host; + + try { + this.baseDomain = Services.etld.getBaseDomainFromHost(strippedHost); + } catch (e) { + if (e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS || + e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) + this.baseDomain = strippedHost; + } +} + +// Object representing a database connection and associated statements. The +// implementation varies depending on schema version. +function CookieDatabaseConnection(file, schema) +{ + // Manually generate a cookies.sqlite file with appropriate rows, columns, + // and schema version. If it already exists, just set up our statements. + let exists = file.exists(); + + this.db = Services.storage.openDatabase(file); + this.schema = schema; + if (!exists) + this.db.schemaVersion = schema; + + switch (schema) { + case 1: + { + if (!exists) { + this.db.executeSimpleSQL( + "CREATE TABLE moz_cookies ( \ + id INTEGER PRIMARY KEY, \ + name TEXT, \ + value TEXT, \ + host TEXT, \ + path TEXT, \ + expiry INTEGER, \ + isSecure INTEGER, \ + isHttpOnly INTEGER)"); + } + + this.stmtInsert = this.db.createStatement( + "INSERT INTO moz_cookies ( \ + id, \ + name, \ + value, \ + host, \ + path, \ + expiry, \ + isSecure, \ + isHttpOnly) \ + VALUES ( \ + :id, \ + :name, \ + :value, \ + :host, \ + :path, \ + :expiry, \ + :isSecure, \ + :isHttpOnly)"); + + this.stmtDelete = this.db.createStatement( + "DELETE FROM moz_cookies WHERE id = :id"); + + break; + } + + case 2: + { + if (!exists) { + this.db.executeSimpleSQL( + "CREATE TABLE moz_cookies ( \ + id INTEGER PRIMARY KEY, \ + name TEXT, \ + value TEXT, \ + host TEXT, \ + path TEXT, \ + expiry INTEGER, \ + lastAccessed INTEGER, \ + isSecure INTEGER, \ + isHttpOnly INTEGER)"); + } + + this.stmtInsert = this.db.createStatement( + "INSERT OR REPLACE INTO moz_cookies ( \ + id, \ + name, \ + value, \ + host, \ + path, \ + expiry, \ + lastAccessed, \ + isSecure, \ + isHttpOnly) \ + VALUES ( \ + :id, \ + :name, \ + :value, \ + :host, \ + :path, \ + :expiry, \ + :lastAccessed, \ + :isSecure, \ + :isHttpOnly)"); + + this.stmtDelete = this.db.createStatement( + "DELETE FROM moz_cookies WHERE id = :id"); + + this.stmtUpdate = this.db.createStatement( + "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id"); + + break; + } + + case 3: + { + if (!exists) { + this.db.executeSimpleSQL( + "CREATE TABLE moz_cookies ( \ + id INTEGER PRIMARY KEY, \ + baseDomain TEXT, \ + name TEXT, \ + value TEXT, \ + host TEXT, \ + path TEXT, \ + expiry INTEGER, \ + lastAccessed INTEGER, \ + isSecure INTEGER, \ + isHttpOnly INTEGER)"); + + this.db.executeSimpleSQL( + "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"); + } + + this.stmtInsert = this.db.createStatement( + "INSERT INTO moz_cookies ( \ + id, \ + baseDomain, \ + name, \ + value, \ + host, \ + path, \ + expiry, \ + lastAccessed, \ + isSecure, \ + isHttpOnly) \ + VALUES ( \ + :id, \ + :baseDomain, \ + :name, \ + :value, \ + :host, \ + :path, \ + :expiry, \ + :lastAccessed, \ + :isSecure, \ + :isHttpOnly)"); + + this.stmtDelete = this.db.createStatement( + "DELETE FROM moz_cookies WHERE id = :id"); + + this.stmtUpdate = this.db.createStatement( + "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id"); + + break; + } + + case 4: + { + if (!exists) { + this.db.executeSimpleSQL( + "CREATE TABLE moz_cookies ( \ + id INTEGER PRIMARY KEY, \ + baseDomain TEXT, \ + name TEXT, \ + value TEXT, \ + host TEXT, \ + path TEXT, \ + expiry INTEGER, \ + lastAccessed INTEGER, \ + creationTime INTEGER, \ + isSecure INTEGER, \ + isHttpOnly INTEGER \ + CONSTRAINT moz_uniqueid UNIQUE (name, host, path))"); + + this.db.executeSimpleSQL( + "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)"); + + this.db.executeSimpleSQL( + "PRAGMA journal_mode = WAL"); + } + + this.stmtInsert = this.db.createStatement( + "INSERT INTO moz_cookies ( \ + baseDomain, \ + name, \ + value, \ + host, \ + path, \ + expiry, \ + lastAccessed, \ + creationTime, \ + isSecure, \ + isHttpOnly) \ + VALUES ( \ + :baseDomain, \ + :name, \ + :value, \ + :host, \ + :path, \ + :expiry, \ + :lastAccessed, \ + :creationTime, \ + :isSecure, \ + :isHttpOnly)"); + + this.stmtDelete = this.db.createStatement( + "DELETE FROM moz_cookies \ + WHERE name = :name AND host = :host AND path = :path"); + + this.stmtUpdate = this.db.createStatement( + "UPDATE moz_cookies SET lastAccessed = :lastAccessed \ + WHERE name = :name AND host = :host AND path = :path"); + + break; + } + + default: + do_throw("unrecognized schemaVersion!"); + } +} + +CookieDatabaseConnection.prototype = +{ + insertCookie: function(cookie) + { + if (!(cookie instanceof Cookie)) + do_throw("not a cookie"); + + switch (this.schema) + { + case 1: + this.stmtInsert.bindByName("id", cookie.creationTime); + this.stmtInsert.bindByName("name", cookie.name); + this.stmtInsert.bindByName("value", cookie.value); + this.stmtInsert.bindByName("host", cookie.host); + this.stmtInsert.bindByName("path", cookie.path); + this.stmtInsert.bindByName("expiry", cookie.expiry); + this.stmtInsert.bindByName("isSecure", cookie.isSecure); + this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); + break; + + case 2: + this.stmtInsert.bindByName("id", cookie.creationTime); + this.stmtInsert.bindByName("name", cookie.name); + this.stmtInsert.bindByName("value", cookie.value); + this.stmtInsert.bindByName("host", cookie.host); + this.stmtInsert.bindByName("path", cookie.path); + this.stmtInsert.bindByName("expiry", cookie.expiry); + this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); + this.stmtInsert.bindByName("isSecure", cookie.isSecure); + this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); + break; + + case 3: + this.stmtInsert.bindByName("id", cookie.creationTime); + this.stmtInsert.bindByName("baseDomain", cookie.baseDomain); + this.stmtInsert.bindByName("name", cookie.name); + this.stmtInsert.bindByName("value", cookie.value); + this.stmtInsert.bindByName("host", cookie.host); + this.stmtInsert.bindByName("path", cookie.path); + this.stmtInsert.bindByName("expiry", cookie.expiry); + this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); + this.stmtInsert.bindByName("isSecure", cookie.isSecure); + this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); + break; + + case 4: + this.stmtInsert.bindByName("baseDomain", cookie.baseDomain); + this.stmtInsert.bindByName("name", cookie.name); + this.stmtInsert.bindByName("value", cookie.value); + this.stmtInsert.bindByName("host", cookie.host); + this.stmtInsert.bindByName("path", cookie.path); + this.stmtInsert.bindByName("expiry", cookie.expiry); + this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); + this.stmtInsert.bindByName("creationTime", cookie.creationTime); + this.stmtInsert.bindByName("isSecure", cookie.isSecure); + this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); + break; + + default: + do_throw("unrecognized schemaVersion!"); + } + + do_execute_stmt(this.stmtInsert); + }, + + deleteCookie: function(cookie) + { + if (!(cookie instanceof Cookie)) + do_throw("not a cookie"); + + switch (this.db.schemaVersion) + { + case 1: + case 2: + case 3: + this.stmtDelete.bindByName("id", cookie.creationTime); + break; + + case 4: + this.stmtDelete.bindByName("name", cookie.name); + this.stmtDelete.bindByName("host", cookie.host); + this.stmtDelete.bindByName("path", cookie.path); + break; + + default: + do_throw("unrecognized schemaVersion!"); + } + + do_execute_stmt(this.stmtDelete); + }, + + updateCookie: function(cookie) + { + if (!(cookie instanceof Cookie)) + do_throw("not a cookie"); + + switch (this.db.schemaVersion) + { + case 1: + do_throw("can't update a schema 1 cookie!"); + + case 2: + case 3: + this.stmtUpdate.bindByName("id", cookie.creationTime); + this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed); + break; + + case 4: + this.stmtDelete.bindByName("name", cookie.name); + this.stmtDelete.bindByName("host", cookie.host); + this.stmtDelete.bindByName("path", cookie.path); + this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed); + break; + + default: + do_throw("unrecognized schemaVersion!"); + } + + do_execute_stmt(this.stmtUpdate); + }, + + close: function() + { + this.stmtInsert.finalize(); + this.stmtDelete.finalize(); + if (this.stmtUpdate) + this.stmtUpdate.finalize(); + this.db.close(); + + this.stmtInsert = null; + this.stmtDelete = null; + this.stmtUpdate = null; + this.db = null; + } +} + +function do_get_cookie_file(profile) +{ + let file = profile.clone(); + file.append("cookies.sqlite"); + return file; +} + +// Count the cookies from 'host' in a database. If 'host' is null, count all +// cookies. +function do_count_cookies_in_db(connection, host) +{ + let select = null; + if (host) { + select = connection.createStatement( + "SELECT COUNT(1) FROM moz_cookies WHERE host = :host"); + select.bindByName("host", host); + } else { + select = connection.createStatement( + "SELECT COUNT(1) FROM moz_cookies"); + } + + select.executeStep(); + let result = select.getInt32(0); + select.reset(); + select.finalize(); + return result; +} + +// Execute 'stmt', ensuring that we reset it if it throws. +function do_execute_stmt(stmt) +{ + try { + stmt.executeStep(); + stmt.reset(); + } catch (e) { + stmt.reset(); + throw e; + } +} |