"use strict";

var prefs;
var http2pref;
var origin;
var rcwnpref;

function run_test() {
  var h2Port = Services.env.get("MOZHTTP2_PORT");
  Assert.notEqual(h2Port, null);
  Assert.notEqual(h2Port, "");

  // Set to allow the cert presented by our H2 server
  do_get_profile();
  prefs = Services.prefs;

  http2pref = prefs.getBoolPref("network.http.http2.enabled");
  rcwnpref = prefs.getBoolPref("network.http.rcwn.enabled");

  prefs.setBoolPref("network.http.http2.enabled", true);
  prefs.setCharPref(
    "network.dns.localDomains",
    "foo.example.com, bar.example.com"
  );
  // Disable rcwn to make cache behavior deterministic.
  prefs.setBoolPref("network.http.rcwn.enabled", false);

  // The moz-http2 cert is for foo.example.com and is signed by http2-ca.pem
  // so add that cert to the trust list as a signing cert.  // the foo.example.com domain name.
  let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
    Ci.nsIX509CertDB
  );
  addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");

  origin = "https://foo.example.com:" + h2Port;
  dump("origin - " + origin + "\n");
  doTest1();
}

function resetPrefs() {
  prefs.setBoolPref("network.http.http2.enabled", http2pref);
  prefs.setBoolPref("network.http.rcwn.enabled", rcwnpref);
  prefs.clearUserPref("network.dns.localDomains");
}

function makeChan(path) {
  return NetUtil.newChannel({
    uri: origin + path,
    loadUsingSystemPrincipal: true,
  }).QueryInterface(Ci.nsIHttpChannel);
}

var nextTest;
var expectPass = true;
var expectConditional = false;

var Listener = function () {};
Listener.prototype = {
  onStartRequest: function testOnStartRequest(request) {
    Assert.ok(request instanceof Ci.nsIHttpChannel);

    if (expectPass) {
      if (!Components.isSuccessCode(request.status)) {
        do_throw(
          "Channel should have a success code! (" + request.status + ")"
        );
      }
      Assert.equal(request.responseStatus, 200);
    } else {
      Assert.equal(Components.isSuccessCode(request.status), false);
    }
  },

  onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
    read_stream(stream, cnt);
  },

  onStopRequest: function testOnStopRequest(request) {
    if (expectConditional) {
      Assert.equal(request.getResponseHeader("x-conditional"), "true");
    } else {
      try {
        Assert.notEqual(request.getResponseHeader("x-conditional"), "true");
      } catch (e) {
        Assert.ok(true);
      }
    }
    nextTest();
    do_test_finished();
  },
};

function testsDone() {
  dump("testDone\n");
  resetPrefs();
}

function doTest1() {
  dump("execute doTest1 - resource without immutable. initial request\n");
  do_test_pending();
  expectConditional = false;
  var chan = makeChan("/immutable-test-without-attribute");
  var listener = new Listener();
  nextTest = doTest2;
  chan.asyncOpen(listener);
}

function doTest2() {
  dump("execute doTest2 - resource without immutable. reload\n");
  do_test_pending();
  expectConditional = true;
  var chan = makeChan("/immutable-test-without-attribute");
  var listener = new Listener();
  nextTest = doTest3;
  chan.loadFlags = Ci.nsIRequest.VALIDATE_ALWAYS;
  chan.asyncOpen(listener);
}

function doTest3() {
  dump("execute doTest3 - resource without immutable. shift reload\n");
  do_test_pending();
  expectConditional = false;
  var chan = makeChan("/immutable-test-without-attribute");
  var listener = new Listener();
  nextTest = doTest4;
  chan.loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
  chan.asyncOpen(listener);
}

function doTest4() {
  dump("execute doTest4 - resource with immutable. initial request\n");
  do_test_pending();
  expectConditional = false;
  var chan = makeChan("/immutable-test-with-attribute");
  var listener = new Listener();
  nextTest = doTest5;
  chan.asyncOpen(listener);
}

function doTest5() {
  dump("execute doTest5 - resource with immutable. reload\n");
  do_test_pending();
  expectConditional = false;
  var chan = makeChan("/immutable-test-with-attribute");
  var listener = new Listener();
  nextTest = doTest6;
  chan.loadFlags = Ci.nsIRequest.VALIDATE_ALWAYS;
  chan.asyncOpen(listener);
}

function doTest6() {
  dump("execute doTest6 - resource with immutable. shift reload\n");
  do_test_pending();
  expectConditional = false;
  var chan = makeChan("/immutable-test-with-attribute");
  var listener = new Listener();
  nextTest = doTest7;
  chan.loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
  chan.asyncOpen(listener);
}

function doTest7() {
  dump("execute doTest7 - expired resource with immutable. initial request\n");
  do_test_pending();
  expectConditional = false;
  var chan = makeChan("/immutable-test-expired-with-Expires-header");
  var listener = new Listener();
  nextTest = doTest8;
  chan.asyncOpen(listener);
}

function doTest8() {
  dump("execute doTest8 - expired resource with immutable. reload\n");
  do_test_pending();
  expectConditional = true;
  var chan = makeChan("/immutable-test-expired-with-Expires-header");
  var listener = new Listener();
  nextTest = doTest9;
  chan.loadFlags = Ci.nsIRequest.VALIDATE_ALWAYS;
  chan.asyncOpen(listener);
}

function doTest9() {
  dump(
    "execute doTest9 - expired resource with immutable cache extension and Last modified header. initial request\n"
  );
  do_test_pending();
  expectConditional = false;
  var chan = makeChan("/immutable-test-expired-with-last-modified-header");
  var listener = new Listener();
  nextTest = doTest10;
  chan.asyncOpen(listener);
}

function doTest10() {
  dump(
    "execute doTest10 - expired resource with immutable cache extension and Last modified heder. reload\n"
  );
  do_test_pending();
  expectConditional = true;
  var chan = makeChan("/immutable-test-expired-with-last-modified-header");
  var listener = new Listener();
  nextTest = testsDone;
  chan.loadFlags = Ci.nsIRequest.VALIDATE_ALWAYS;
  chan.asyncOpen(listener);
}
