extensions/cookie/test/unit/head_cookies.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial