tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_cookies_sync_failure.js (8790B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 // Test the various ways opening a cookie database can fail in a synchronous
      5 // (i.e. immediate) manner, and that the database is renamed and recreated
      6 // under each circumstance. These circumstances are, in no particular order:
      7 //
      8 // 1) A corrupt database, such that opening the connection fails.
      9 // 2) The 'moz_cookies' table doesn't exist.
     10 // 3) Not all of the expected columns exist, and statement creation fails when:
     11 //    a) The schema version is larger than the current version.
     12 //    b) The schema version is less than or equal to the current version.
     13 // 4) Migration fails. This will have different modes depending on the initial
     14 //    version:
     15 //    a) Schema 1: the 'lastAccessed' column already exists.
     16 //    b) Schema 2: the 'baseDomain' column already exists; or 'baseDomain'
     17 //       cannot be computed for a particular host.
     18 //    c) Schema 3: the 'creationTime' column already exists; or the
     19 //       'moz_uniqueid' index already exists.
     20 
     21 "use strict";
     22 
     23 let profile;
     24 let cookieFile;
     25 let backupFile;
     26 let sub_generator;
     27 let now;
     28 let futureExpiry;
     29 let cookie;
     30 
     31 var COOKIE_DATABASE_SCHEMA_CURRENT = 17;
     32 
     33 var test_generator = do_run_test();
     34 
     35 function run_test() {
     36  do_test_pending();
     37  do_run_generator(test_generator);
     38 }
     39 
     40 function finish_test() {
     41  executeSoon(function () {
     42    test_generator.return();
     43    do_test_finished();
     44  });
     45 }
     46 
     47 function* do_run_test() {
     48  // Set up a profile.
     49  profile = do_get_profile();
     50 
     51  // Allow all cookies.
     52  Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
     53  Services.prefs.setBoolPref(
     54    "network.cookieJarSettings.unblocked_for_testing",
     55    true
     56  );
     57 
     58  // Get the cookie file and the backup file.
     59  cookieFile = profile.clone();
     60  cookieFile.append("cookies.sqlite");
     61  backupFile = profile.clone();
     62  backupFile.append("cookies.sqlite.bak");
     63  Assert.ok(!cookieFile.exists());
     64  Assert.ok(!backupFile.exists());
     65 
     66  // Create a cookie object for testing.
     67  now = Date.now() * 1000;
     68  futureExpiry = Math.round(now / 1e6 + 1000);
     69  cookie = new Cookie(
     70    "oh",
     71    "hai",
     72    "bar.com",
     73    "/",
     74    futureExpiry,
     75    now,
     76    now,
     77    false,
     78    false,
     79    false
     80  );
     81 
     82  sub_generator = run_test_1(test_generator);
     83  sub_generator.next();
     84  yield;
     85 
     86  sub_generator = run_test_2(test_generator);
     87  sub_generator.next();
     88  yield;
     89 
     90  sub_generator = run_test_3(test_generator, 99);
     91  sub_generator.next();
     92  yield;
     93 
     94  sub_generator = run_test_3(test_generator, COOKIE_DATABASE_SCHEMA_CURRENT);
     95  sub_generator.next();
     96  yield;
     97 
     98  sub_generator = run_test_3(test_generator, 4);
     99  sub_generator.next();
    100  yield;
    101 
    102  sub_generator = run_test_3(test_generator, 3);
    103  sub_generator.next();
    104  yield;
    105 
    106  sub_generator = run_test_4_exists(
    107    test_generator,
    108    1,
    109    "ALTER TABLE moz_cookies ADD lastAccessed INTEGER"
    110  );
    111  sub_generator.next();
    112  yield;
    113 
    114  sub_generator = run_test_4_exists(
    115    test_generator,
    116    2,
    117    "ALTER TABLE moz_cookies ADD baseDomain TEXT"
    118  );
    119  sub_generator.next();
    120  yield;
    121 
    122  sub_generator = run_test_4_baseDomain(test_generator);
    123  sub_generator.next();
    124  yield;
    125 
    126  sub_generator = run_test_4_exists(
    127    test_generator,
    128    3,
    129    "ALTER TABLE moz_cookies ADD creationTime INTEGER"
    130  );
    131  sub_generator.next();
    132  yield;
    133 
    134  sub_generator = run_test_4_exists(
    135    test_generator,
    136    3,
    137    "CREATE UNIQUE INDEX moz_uniqueid ON moz_cookies (name, host, path)"
    138  );
    139  sub_generator.next();
    140  yield;
    141 
    142  finish_test();
    143 }
    144 
    145 const garbage = "hello thar!";
    146 
    147 function create_garbage_file(file) {
    148  // Create an empty database file.
    149  file.create(Ci.nsIFile.NORMAL_FILE_TYPE, -1);
    150  Assert.ok(file.exists());
    151  Assert.equal(file.fileSize, 0);
    152 
    153  // Write some garbage to it.
    154  let ostream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
    155    Ci.nsIFileOutputStream
    156  );
    157  ostream.init(file, -1, -1, 0);
    158  ostream.write(garbage, garbage.length);
    159  ostream.flush();
    160  ostream.close();
    161 
    162  file = file.clone(); // Windows maintains a stat cache. It's lame.
    163  Assert.equal(file.fileSize, garbage.length);
    164 }
    165 
    166 function check_garbage_file(file) {
    167  Assert.ok(file.exists());
    168  Assert.equal(file.fileSize, garbage.length);
    169  file.remove(false);
    170  Assert.ok(!file.exists());
    171 }
    172 
    173 function* run_test_1(generator) {
    174  // Create a garbage database file.
    175  create_garbage_file(cookieFile);
    176 
    177  let uri = NetUtil.newURI("http://foo.com/");
    178  const channel = NetUtil.newChannel({
    179    uri,
    180    loadUsingSystemPrincipal: true,
    181    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
    182  });
    183 
    184  // Load the profile and populate it.
    185  Services.cookies.setCookieStringFromHttp(
    186    uri,
    187    "oh=hai; max-age=1000",
    188    channel
    189  );
    190 
    191  // Fake a profile change.
    192  do_close_profile(sub_generator);
    193  yield;
    194  do_load_profile();
    195 
    196  // Check that the new database contains the cookie, and the old file was
    197  // renamed.
    198  Assert.equal(do_count_cookies(), 1);
    199  check_garbage_file(backupFile);
    200 
    201  // Close the profile.
    202  do_close_profile(sub_generator);
    203  yield;
    204 
    205  // Clean up.
    206  cookieFile.remove(false);
    207  Assert.ok(!cookieFile.exists());
    208  do_run_generator(generator);
    209 }
    210 
    211 function* run_test_2(generator) {
    212  // Load the profile and populate it.
    213  do_load_profile();
    214  let uri = NetUtil.newURI("http://foo.com/");
    215  const channel = NetUtil.newChannel({
    216    uri,
    217    loadUsingSystemPrincipal: true,
    218    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
    219  });
    220  Services.cookies.setCookieStringFromHttp(
    221    uri,
    222    "oh=hai; max-age=1000",
    223    channel
    224  );
    225 
    226  // Fake a profile change.
    227  do_close_profile(sub_generator);
    228  yield;
    229 
    230  // Drop the table.
    231  let db = Services.storage.openDatabase(cookieFile);
    232  db.executeSimpleSQL("DROP TABLE moz_cookies");
    233  db.close();
    234 
    235  // Load the profile and check that the table is recreated in-place.
    236  do_load_profile();
    237  Assert.equal(do_count_cookies(), 0);
    238  Assert.ok(!backupFile.exists());
    239 
    240  // Close the profile.
    241  do_close_profile(sub_generator);
    242  yield;
    243 
    244  // Clean up.
    245  cookieFile.remove(false);
    246  Assert.ok(!cookieFile.exists());
    247  do_run_generator(generator);
    248 }
    249 
    250 function* run_test_3(generator, schema) {
    251  // Manually create a schema 2 database, populate it, and set the schema
    252  // version to the desired number.
    253  let schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2);
    254  schema2db.insertCookie(cookie);
    255  schema2db.db.schemaVersion = schema;
    256  schema2db.close();
    257 
    258  // Load the profile and check that the column existence test fails.
    259  do_load_profile();
    260  Assert.equal(do_count_cookies(), 0);
    261 
    262  // Close the profile.
    263  do_close_profile(sub_generator);
    264  yield;
    265 
    266  // Check that the schema version has been reset.
    267  let db = Services.storage.openDatabase(cookieFile);
    268  Assert.equal(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT);
    269  db.close();
    270 
    271  // Clean up.
    272  cookieFile.remove(false);
    273  Assert.ok(!cookieFile.exists());
    274  do_run_generator(generator);
    275 }
    276 
    277 function* run_test_4_exists(generator, schema, stmt) {
    278  // Manually create a database, populate it, and add the desired column.
    279  let db = new CookieDatabaseConnection(do_get_cookie_file(profile), schema);
    280  db.insertCookie(cookie);
    281  db.db.executeSimpleSQL(stmt);
    282  db.close();
    283 
    284  // Load the profile and check that migration fails.
    285  do_load_profile();
    286  Assert.equal(do_count_cookies(), 0);
    287 
    288  // Close the profile.
    289  do_close_profile(sub_generator);
    290  yield;
    291 
    292  // Check that the schema version has been reset and the backup file exists.
    293  db = Services.storage.openDatabase(cookieFile);
    294  Assert.equal(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT);
    295  db.close();
    296  Assert.ok(backupFile.exists());
    297 
    298  // Clean up.
    299  cookieFile.remove(false);
    300  backupFile.remove(false);
    301  Assert.ok(!cookieFile.exists());
    302  Assert.ok(!backupFile.exists());
    303  do_run_generator(generator);
    304 }
    305 
    306 function* run_test_4_baseDomain(generator) {
    307  // Manually create a database and populate it with a bad host.
    308  let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2);
    309  let badCookie = new Cookie(
    310    "oh",
    311    "hai",
    312    ".",
    313    "/",
    314    futureExpiry,
    315    now,
    316    now,
    317    false,
    318    false,
    319    false
    320  );
    321  db.insertCookie(badCookie);
    322  db.close();
    323 
    324  // Load the profile and check that migration fails.
    325  do_load_profile();
    326  Assert.equal(do_count_cookies(), 0);
    327 
    328  // Close the profile.
    329  do_close_profile(sub_generator);
    330  yield;
    331 
    332  // Check that the schema version has been reset and the backup file exists.
    333  db = Services.storage.openDatabase(cookieFile);
    334  Assert.equal(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT);
    335  db.close();
    336  Assert.ok(backupFile.exists());
    337 
    338  // Clean up.
    339  cookieFile.remove(false);
    340  backupFile.remove(false);
    341  Assert.ok(!cookieFile.exists());
    342  Assert.ok(!backupFile.exists());
    343  do_run_generator(generator);
    344 }