"use strict";

do_get_profile();

// This test checks that active private-browsing HTTP channels, do not save
// cookies after the termination of the private-browsing session.

// This test consists in following steps:
// - starts a http server
// - no cookies at this point
// - does a beacon request in private-browsing mode
// - after the completion of the request, a cookie should be set (cookie cleanup)
// - does a beacon request in private-browsing mode and dispatch a
//   last-pb-context-exit notification
// - after the completion of the request, no cookies should be set

const { HttpServer } = ChromeUtils.importESModule(
  "resource://testing-common/httpd.sys.mjs"
);

let server;

function setupServer() {
  info("Starting the server...");

  function beaconHandler(metadata, response) {
    response.setHeader("Cache-Control", "max-age=10000", false);
    response.setStatusLine(metadata.httpVersion, 204, "No Content");
    response.setHeader("Set-Cookie", "a=b; path=/beacon; sameSite=lax", false);
    response.bodyOutputStream.write("", 0);
  }

  server = new HttpServer();
  server.registerPathHandler("/beacon", beaconHandler);
  server.start(-1);
  next();
}

function shutdownServer() {
  info("Terminating the server...");
  server.stop(next);
}

function sendRequest(notification) {
  info("Sending a request...");

  var privateLoadContext = Cu.createPrivateLoadContext();

  var path =
    "http://localhost:" +
    server.identity.primaryPort +
    "/beacon?" +
    Math.random();

  var uri = NetUtil.newURI(path);
  var securityFlags =
    Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL |
    Ci.nsILoadInfo.SEC_COOKIES_INCLUDE;
  var principal = Services.scriptSecurityManager.createContentPrincipal(uri, {
    privateBrowsingId: 1,
  });

  var chan = NetUtil.newChannel({
    uri,
    loadingPrincipal: principal,
    securityFlags,
    contentPolicyType: Ci.nsIContentPolicy.TYPE_BEACON,
  });

  chan.notificationCallbacks = Cu.createPrivateLoadContext();

  let loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(
    Ci.nsILoadGroup
  );

  loadGroup.notificationCallbacks = Cu.createPrivateLoadContext();
  chan.loadGroup = loadGroup;

  chan.notificationCallbacks = privateLoadContext;
  var channelListener = new ChannelListener(next, null, CL_ALLOW_UNKNOWN_CL);

  if (notification) {
    info("Sending notification...");
    Services.obs.notifyObservers(null, "last-pb-context-exited");
  }

  chan.asyncOpen(channelListener);
}

function checkCookies(hasCookie) {
  let cm = Services.cookies;
  Assert.equal(
    cm.cookieExists("localhost", "/beacon", "a", { privateBrowsingId: 1 }),
    hasCookie
  );
  cm.removeAll();
  next();
}

const steps = [
  setupServer,

  // no cookie at startup
  () => checkCookies(false),

  // no last-pb-context-exit notification
  () => sendRequest(false),
  () => checkCookies(true),

  // last-pb-context-exit notification
  () => sendRequest(true),
  () => checkCookies(false),

  shutdownServer,
];

function next() {
  if (!steps.length) {
    do_test_finished();
    return;
  }

  steps.shift()();
}

function run_test() {
  // We don't want to have CookieJarSettings blocking this test.
  Services.prefs.setBoolPref(
    "network.cookieJarSettings.unblocked_for_testing",
    true
  );

  do_test_pending();
  next();
}
