Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  test_cookies_async_failure.js   Sprache: JAVA

 
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */


// Test the various ways opening a cookie database can fail in an asynchronous
// (i.e. after synchronous initialization) manner, and that the database is
// renamed and recreated under each circumstance. These circumstances are, in no
// particular order:
//
// 1) A write operation failing after the database has been read in.
// 2) Asynchronous read failure due to a corrupt database.
// 3) Synchronous read failure due to a corrupt database, when reading:
//    a) a single base domain;
//    b) the entire database.
// 4) Asynchronous read failure, followed by another failure during INSERT but
//    before the database closes for rebuilding. (The additional error should be
//    ignored.)
// 5) Asynchronous read failure, followed by an INSERT failure during rebuild.
//    This should result in an abort of the database rebuild; the partially-
//    built database should be moved to 'cookies.sqlite.bak-rebuild'.

"use strict";

let profile;
let cookie;

add_task(async () => {
  // Set up a profile.
  profile = do_get_profile();
  Services.prefs.setBoolPref("dom.security.https_first"false);

  // Allow all cookies.
  Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
  Services.prefs.setBoolPref(
    "network.cookieJarSettings.unblocked_for_testing",
    true
  );

  // Bug 1617611 - Fix all the tests broken by "cookies SameSite=Lax by default"
  Services.prefs.setBoolPref("network.cookie.sameSite.laxByDefault"false);

  // The server.
  const hosts = ["foo.com""hither.com""haithur.com""bar.com"];
  for (let i = 0; i < 3000; ++i) {
    hosts.push(i + ".com");
  }
  CookieXPCShellUtils.createServer({ hosts });

  // Get the cookie file and the backup file.
  Assert.ok(!do_get_cookie_file(profile).exists());
  Assert.ok(!do_get_backup_file().exists());

  // Create a cookie object for testing.
  let now = Date.now() * 1000;
  let futureExpiry = Math.round(now / 1e6 + 1000);
  cookie = new Cookie(
    "oh",
    "hai",
    "bar.com",
    "/",
    futureExpiry,
    now,
    now,
    false,
    false,
    false
  );

  await run_test_1();
  await run_test_2();
  await run_test_3();
  await run_test_4();
  await run_test_5();
  Services.prefs.clearUserPref("dom.security.https_first");
  Services.prefs.clearUserPref("network.cookie.sameSite.laxByDefault");
});

function do_get_backup_file() {
  let file = profile.clone();
  file.append("cookies.sqlite.bak");
  return file;
}

function do_get_rebuild_backup_file() {
  let file = profile.clone();
  file.append("cookies.sqlite.bak-rebuild");
  return file;
}

function do_corrupt_db(file) {
  // Sanity check: the database size should be larger than 320k, since we've
  // written about 460k of data. If it's not, let's make it obvious now.
  let size = file.fileSize;
  Assert.ok(size > 320e3);

  // Corrupt the database by writing bad data to the end of the file. We
  // assume that the important metadata -- table structure etc -- is stored
  // elsewhere, and that doing this will not cause synchronous failure when
  // initializing the database connection. This is totally empirical --
  // overwriting between 1k and 100k of live data seems to work. (Note that the
  // database file will be larger than the actual content requires, since the
  // cookie service uses a large growth increment. So we calculate the offset
  // based on the expected size of the content, not just the file size.)
  let ostream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
    Ci.nsIFileOutputStream
  );
  ostream.init(file, 2, -1, 0);
  let sstream = ostream.QueryInterface(Ci.nsISeekableStream);
  let n = size - 320e3 + 20e3;
  sstream.seek(Ci.nsISeekableStream.NS_SEEK_SET, size - n);
  for (let i = 0; i < n; ++i) {
    ostream.write("a", 1);
  }
  ostream.flush();
  ostream.close();

  Assert.equal(file.clone().fileSize, size);
  return size;
}

async function run_test_1() {
  // Load the profile and populate it.
  await CookieXPCShellUtils.setCookieToDocument(
    "http://foo.com/",
    "oh=hai; max-age=1000"
  );

  // Close the profile.
  await promise_close_profile();

  // Open a database connection now, before we load the profile and begin
  // asynchronous write operations.
  let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 12);
  Assert.equal(do_count_cookies_in_db(db.db), 1);

  // Load the profile, and wait for async read completion...
  await promise_load_profile();

  // Insert a row.
  db.insertCookie(cookie);
  db.close();

  // Attempt to insert a cookie with the same (name, host, path) triplet.
  Services.cookies.add(
    cookie.host,
    cookie.path,
    cookie.name,
    "hallo",
    cookie.isSecure,
    cookie.isHttpOnly,
    cookie.isSession,
    cookie.expiry,
    {},
    Ci.nsICookie.SAMESITE_NONE,
    Ci.nsICookie.SCHEME_HTTPS
  );

  // Check that the cookie service accepted the new cookie.
  Assert.equal(Services.cookies.countCookiesFromHost(cookie.host), 1);

  let isRebuildingDone = false;
  let rebuildingObserve = function () {
    isRebuildingDone = true;
    Services.obs.removeObserver(rebuildingObserve, "cookie-db-rebuilding");
  };
  Services.obs.addObserver(rebuildingObserve, "cookie-db-rebuilding");

  // Crash test: we're going to rebuild the cookie database. Close all the db
  // connections in the main thread and initialize a new database file in the
  // cookie thread. Trigger some access of cookies to ensure we won't crash in
  // the chaos status.
  for (let i = 0; i < 10; ++i) {
    Assert.equal(Services.cookies.countCookiesFromHost(cookie.host), 1);
    await new Promise(resolve => executeSoon(resolve));
  }

  // Wait for the cookie service to rename the old database and rebuild if not yet.
  if (!isRebuildingDone) {
    Services.obs.removeObserver(rebuildingObserve, "cookie-db-rebuilding");
    await new _promise_observer("cookie-db-rebuilding");
  }

  await new Promise(resolve => executeSoon(resolve));

  // At this point, the cookies should still be in memory.
  Assert.equal(Services.cookies.countCookiesFromHost("foo.com"), 1);
  Assert.equal(Services.cookies.countCookiesFromHost(cookie.host), 1);
  Assert.equal(do_count_cookies(), 2);

  // Close the profile.
  await promise_close_profile();

  // Check that the original database was renamed, and that it contains the
  // original cookie.
  Assert.ok(do_get_backup_file().exists());
  let backupdb = Services.storage.openDatabase(do_get_backup_file());
  Assert.equal(do_count_cookies_in_db(backupdb, "foo.com"), 1);
  backupdb.close();

  // Load the profile, and check that it contains the new cookie.
  do_load_profile();

  Assert.equal(Services.cookies.countCookiesFromHost("foo.com"), 1);
  let cookies = Services.cookies.getCookiesFromHost(cookie.host, {});
  Assert.equal(cookies.length, 1);
  let dbcookie = cookies[0];
  Assert.equal(dbcookie.value, "hallo");

  // Close the profile.
  await promise_close_profile();

  // Clean up.
  do_get_cookie_file(profile).remove(false);
  do_get_backup_file().remove(false);
  Assert.ok(!do_get_cookie_file(profile).exists());
  Assert.ok(!do_get_backup_file().exists());
}

async function run_test_2() {
  // Load the profile and populate it.
  do_load_profile();

  Services.cookies.runInTransaction(_ => {
    let uri = NetUtil.newURI("http://foo.com/");
    const channel = NetUtil.newChannel({
      uri,
      loadUsingSystemPrincipal: true,
      contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
    });

    for (let i = 0; i < 3000; ++i) {
      uri = NetUtil.newURI("http://" + i + ".com/");
      Services.cookies.setCookieStringFromHttp(
        uri,
        "oh=hai; max-age=1000",
        channel
      );
    }
  });

  // Close the profile.
  await promise_close_profile();

  // Corrupt the database file.
  let size = do_corrupt_db(do_get_cookie_file(profile));

  // Load the profile.
  do_load_profile();

  // At this point, the database connection should be open. Ensure that it
  // succeeded.
  Assert.ok(!do_get_backup_file().exists());

  // Recreate a new database since it was corrupted
  Assert.equal(Services.cookies.countCookiesFromHost("0.com"), 0);
  Assert.equal(do_count_cookies(), 0);

  // Close the profile.
  await promise_close_profile();

  // Check that the original database was renamed.
  Assert.ok(do_get_backup_file().exists());
  Assert.equal(do_get_backup_file().fileSize, size);
  let db = Services.storage.openDatabase(do_get_cookie_file(profile));
  db.close();

  do_load_profile();
  Assert.equal(Services.cookies.countCookiesFromHost("0.com"), 0);
  Assert.equal(do_count_cookies(), 0);

  // Close the profile.
  await promise_close_profile();

  // Clean up.
  do_get_cookie_file(profile).remove(false);
  do_get_backup_file().remove(false);
  Assert.ok(!do_get_cookie_file(profile).exists());
  Assert.ok(!do_get_backup_file().exists());
}

async function run_test_3() {
  // Set the maximum cookies per base domain limit to a large value, so that
  // corrupting the database is easier.
  Services.prefs.setIntPref("network.cookie.maxPerHost", 3000);

  // Load the profile and populate it.
  do_load_profile();
  Services.cookies.runInTransaction(_ => {
    let uri = NetUtil.newURI("http://hither.com/");
    let channel = NetUtil.newChannel({
      uri,
      loadUsingSystemPrincipal: true,
      contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
    });
    for (let i = 0; i < 10; ++i) {
      Services.cookies.setCookieStringFromHttp(
        uri,
        "oh" + i + "=hai; max-age=1000",
        channel
      );
    }
    uri = NetUtil.newURI("http://haithur.com/");
    channel = NetUtil.newChannel({
      uri,
      loadUsingSystemPrincipal: true,
      contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
    });
    for (let i = 10; i < 3000; ++i) {
      Services.cookies.setCookieStringFromHttp(
        uri,
        "oh" + i + "=hai; max-age=1000",
        channel
      );
    }
  });

  // Close the profile.
  await promise_close_profile();

  // Corrupt the database file.
  let size = do_corrupt_db(do_get_cookie_file(profile));

  // Load the profile.
  do_load_profile();

  // At this point, the database connection should be open. Ensure that it
  // succeeded.
  Assert.ok(!do_get_backup_file().exists());

  // Recreate a new database since it was corrupted
  Assert.equal(Services.cookies.countCookiesFromHost("hither.com"), 0);
  Assert.equal(Services.cookies.countCookiesFromHost("haithur.com"), 0);

  // Close the profile.
  await promise_close_profile();

  let db = Services.storage.openDatabase(do_get_cookie_file(profile));
  Assert.equal(do_count_cookies_in_db(db, "hither.com"), 0);
  Assert.equal(do_count_cookies_in_db(db), 0);
  db.close();

  // Check that the original database was renamed.
  Assert.ok(do_get_backup_file().exists());
  Assert.equal(do_get_backup_file().fileSize, size);

  // Rename it back, and try loading the entire database synchronously.
  do_get_backup_file().moveTo(null"cookies.sqlite");
  do_load_profile();

  // At this point, the database connection should be open. Ensure that it
  // succeeded.
  Assert.ok(!do_get_backup_file().exists());

  // Synchronously read in everything.
  Assert.equal(do_count_cookies(), 0);

  // Close the profile.
  await promise_close_profile();

  db = Services.storage.openDatabase(do_get_cookie_file(profile));
  Assert.equal(do_count_cookies_in_db(db), 0);
  db.close();

  // Check that the original database was renamed.
  Assert.ok(do_get_backup_file().exists());
  Assert.equal(do_get_backup_file().fileSize, size);

  // Clean up.
  do_get_cookie_file(profile).remove(false);
  do_get_backup_file().remove(false);
  Assert.ok(!do_get_cookie_file(profile).exists());
  Assert.ok(!do_get_backup_file().exists());
}

async function run_test_4() {
  // Load the profile and populate it.
  do_load_profile();
  Services.cookies.runInTransaction(_ => {
    let uri = NetUtil.newURI("http://foo.com/");
    let channel = NetUtil.newChannel({
      uri,
      loadUsingSystemPrincipal: true,
      contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
    });
    for (let i = 0; i < 3000; ++i) {
      uri = NetUtil.newURI("http://" + i + ".com/");
      Services.cookies.setCookieStringFromHttp(
        uri,
        "oh=hai; max-age=1000",
        channel
      );
    }
  });

  // Close the profile.
  await promise_close_profile();

  // Corrupt the database file.
  let size = do_corrupt_db(do_get_cookie_file(profile));

  // Load the profile.
  do_load_profile();

  // At this point, the database connection should be open. Ensure that it
  // succeeded.
  Assert.ok(!do_get_backup_file().exists());

  // Recreate a new database since it was corrupted
  Assert.equal(Services.cookies.countCookiesFromHost("0.com"), 0);

  // Queue up an INSERT for the same base domain. This should also go into
  // memory and be written out during database rebuild.
  await CookieXPCShellUtils.setCookieToDocument(
    "http://0.com/",
    "oh2=hai; max-age=1000"
  );

  // At this point, the cookies should still be in memory.
  Assert.equal(Services.cookies.countCookiesFromHost("0.com"), 1);
  Assert.equal(do_count_cookies(), 1);

  // Close the profile.
  await promise_close_profile();

  // Check that the original database was renamed.
  Assert.ok(do_get_backup_file().exists());
  Assert.equal(do_get_backup_file().fileSize, size);

  // Load the profile, and check that it contains the new cookie.
  do_load_profile();
  Assert.equal(Services.cookies.countCookiesFromHost("0.com"), 1);
  Assert.equal(do_count_cookies(), 1);

  // Close the profile.
  await promise_close_profile();

  // Clean up.
  do_get_cookie_file(profile).remove(false);
  do_get_backup_file().remove(false);
  Assert.ok(!do_get_cookie_file(profile).exists());
  Assert.ok(!do_get_backup_file().exists());
}

async function run_test_5() {
  // Load the profile and populate it.
  do_load_profile();
  Services.cookies.runInTransaction(_ => {
    let uri = NetUtil.newURI("http://bar.com/");
    const channel = NetUtil.newChannel({
      uri,
      loadUsingSystemPrincipal: true,
      contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
    });
    Services.cookies.setCookieStringFromHttp(
      uri,
      "oh=hai; path=/; max-age=1000",
      channel
    );
    for (let i = 0; i < 3000; ++i) {
      uri = NetUtil.newURI("http://" + i + ".com/");
      Services.cookies.setCookieStringFromHttp(
        uri,
        "oh=hai; max-age=1000",
        channel
      );
    }
  });

  // Close the profile.
  await promise_close_profile();

  // Corrupt the database file.
  let size = do_corrupt_db(do_get_cookie_file(profile));

  // Load the profile.
  do_load_profile();

  // At this point, the database connection should be open. Ensure that it
  // succeeded.
  Assert.ok(!do_get_backup_file().exists());

  // Recreate a new database since it was corrupted
  Assert.equal(Services.cookies.countCookiesFromHost("bar.com"), 0);
  Assert.equal(Services.cookies.countCookiesFromHost("0.com"), 0);
  Assert.equal(do_count_cookies(), 0);
  Assert.ok(do_get_backup_file().exists());
  Assert.equal(do_get_backup_file().fileSize, size);
  Assert.ok(!do_get_rebuild_backup_file().exists());

  // Open a database connection, and write a row that will trigger a constraint
  // violation.
  let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 12);
  db.insertCookie(cookie);
  Assert.equal(do_count_cookies_in_db(db.db, "bar.com"), 1);
  Assert.equal(do_count_cookies_in_db(db.db), 1);
  db.close();

  // Check that the original backup and the database itself are gone.
  Assert.ok(do_get_backup_file().exists());
  Assert.equal(do_get_backup_file().fileSize, size);

  Assert.equal(Services.cookies.countCookiesFromHost("bar.com"), 0);
  Assert.equal(Services.cookies.countCookiesFromHost("0.com"), 0);
  Assert.equal(do_count_cookies(), 0);

  // Close the profile. We do not need to wait for completion, because the
  // database has already been closed. Ensure the cookie file is unlocked.
  await promise_close_profile();

  // Clean up.
  do_get_cookie_file(profile).remove(false);
  do_get_backup_file().remove(false);
  Assert.ok(!do_get_cookie_file(profile).exists());
  Assert.ok(!do_get_backup_file().exists());
}

Messung V0.5
C=77 H=87 G=81

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge