Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/Services.jsm");

var httpServer = null;
var path = "/bug699001";

XPCOMUtils.defineLazyGetter(this, "URI", function() {
  return "http://localhost:" + httpServer.identity.primaryPort + path;
});

function make_channel(url) {
  var ios = Cc["@mozilla.org/network/io-service;1"].
            getService(Ci.nsIIOService);
  return ios.newChannel2(url,
                         "",
                         null,
                         null,      // aLoadingNode
                         Services.scriptSecurityManager.getSystemPrincipal(),
                         null,      // aTriggeringPrincipal
                         Ci.nsILoadInfo.SEC_NORMAL,
                         Ci.nsIContentPolicy.TYPE_OTHER);
}

var fetched;

// The test loads a resource that expires in one year, has an etag and varies only by User-Agent
// First we load it, then check we load it only from the cache w/o even checking with the server
// Then we modify our User-Agent and try it again
// We have to get a new content (even though with the same etag) and again on next load only from
// cache w/o accessing the server
// Goal is to check we've updated User-Agent request header in cache after we've got 304 response
// from the server

var tests = [
{
  prepare: function() { },
  test: function(response) {
    do_check_true(fetched);
  }
},
{
  prepare: function() { },
  test: function(response) {
    do_check_false(fetched);
  }
},
{
  prepare: function() {
    setUA("A different User Agent");
  },
  test: function(response) {
    do_check_true(fetched);
  }
},
{
  prepare: function() { },
  test: function(response) {
    do_check_false(fetched);
  }
},
{
  prepare: function() {
    setUA("And another User Agent");
  },
  test: function(response) {
    do_check_true(fetched);
  }
},
{
  prepare: function() { },
  test: function(response) {
    do_check_false(fetched);
  }
}
];

function handler(metadata, response)
{
  if (metadata.hasHeader("If-None-Match")) {
    response.setStatusLine(metadata.httpVersion, 304, "Not modified");
  }
  else {
    response.setStatusLine(metadata.httpVersion, 200, "OK");
    response.setHeader("Content-Type", "text/plain");

    var body = "body";
    response.bodyOutputStream.write(body, body.length);
  }

  fetched = true;

  response.setHeader("Expires", getDateString(+1));
  response.setHeader("Cache-Control", "private");
  response.setHeader("Vary", "User-Agent");
  response.setHeader("ETag", "1234");
}

function run_test()
{
  httpServer = new HttpServer();
  httpServer.registerPathHandler(path, handler);
  httpServer.start(-1);

  do_test_pending();

  nextTest();
}

function nextTest()
{
  fetched = false;
  tests[0].prepare();

  dump("Testing with User-Agent: " + getUA() + "\n");
  var chan = make_channel(URI);

  // Give the old channel a chance to close the cache entry first.
  // XXX This is actually a race condition that might be considered a bug...
  do_execute_soon(function() {
    chan.asyncOpen(new ChannelListener(checkAndShiftTest, null), null);
  });
}

function checkAndShiftTest(request, response)
{
  tests[0].test(response);

  tests.shift();
  if (tests.length == 0) {
    httpServer.stop(tearDown);
    return;
  }

  nextTest();
}

function tearDown()
{
  setUA("");
  do_test_finished();
}

// Helpers

function getUA()
{
  var httphandler = Cc["@mozilla.org/network/protocol;1?name=http"].
                 getService(Ci.nsIHttpProtocolHandler);
  return httphandler.userAgent;
}

function setUA(value)
{
  var prefs = Cc["@mozilla.org/preferences-service;1"].
                 getService(Ci.nsIPrefBranch);
  prefs.setCharPref("general.useragent.override", value);
}

function getDateString(yearDelta) {
  var months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug',
          'Sep', 'Oct', 'Nov', 'Dec' ];
  var days = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];

  var d = new Date();
  return days[d.getUTCDay()] + ", " + d.getUTCDate() + " "
          + months[d.getUTCMonth()] + " " + (d.getUTCFullYear() + yearDelta)
          + " " + d.getUTCHours() + ":" + d.getUTCMinutes() + ":"
          + d.getUTCSeconds() + " UTC";
}
