michael@0: Cu.import("resource://testing-common/httpd.js"); michael@0: michael@0: var httpServer = null; michael@0: var path = "/bug699001"; michael@0: michael@0: XPCOMUtils.defineLazyGetter(this, "URI", function() { michael@0: return "http://localhost:" + httpServer.identity.primaryPort + path; michael@0: }); michael@0: michael@0: function make_channel(url) { michael@0: var ios = Cc["@mozilla.org/network/io-service;1"]. michael@0: getService(Ci.nsIIOService); michael@0: return ios.newChannel(url, "", null); michael@0: } michael@0: michael@0: var fetched; michael@0: michael@0: // The test loads a resource that expires in one year, has an etag and varies only by User-Agent michael@0: // First we load it, then check we load it only from the cache w/o even checking with the server michael@0: // Then we modify our User-Agent and try it again michael@0: // We have to get a new content (even though with the same etag) and again on next load only from michael@0: // cache w/o accessing the server michael@0: // Goal is to check we've updated User-Agent request header in cache after we've got 304 response michael@0: // from the server michael@0: michael@0: var tests = [ michael@0: { michael@0: prepare: function() { }, michael@0: test: function(response) { michael@0: do_check_true(fetched); michael@0: } michael@0: }, michael@0: { michael@0: prepare: function() { }, michael@0: test: function(response) { michael@0: do_check_false(fetched); michael@0: } michael@0: }, michael@0: { michael@0: prepare: function() { michael@0: setUA("A different User Agent"); michael@0: }, michael@0: test: function(response) { michael@0: do_check_true(fetched); michael@0: } michael@0: }, michael@0: { michael@0: prepare: function() { }, michael@0: test: function(response) { michael@0: do_check_false(fetched); michael@0: } michael@0: }, michael@0: { michael@0: prepare: function() { michael@0: setUA("And another User Agent"); michael@0: }, michael@0: test: function(response) { michael@0: do_check_true(fetched); michael@0: } michael@0: }, michael@0: { michael@0: prepare: function() { }, michael@0: test: function(response) { michael@0: do_check_false(fetched); michael@0: } michael@0: } michael@0: ]; michael@0: michael@0: function handler(metadata, response) michael@0: { michael@0: if (metadata.hasHeader("If-None-Match")) { michael@0: response.setStatusLine(metadata.httpVersion, 304, "Not modified"); michael@0: } michael@0: else { michael@0: response.setStatusLine(metadata.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "text/plain"); michael@0: michael@0: var body = "body"; michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: michael@0: fetched = true; michael@0: michael@0: response.setHeader("Expires", getDateString(+1)); michael@0: response.setHeader("Cache-Control", "private"); michael@0: response.setHeader("Vary", "User-Agent"); michael@0: response.setHeader("ETag", "1234"); michael@0: } michael@0: michael@0: function run_test() michael@0: { michael@0: httpServer = new HttpServer(); michael@0: httpServer.registerPathHandler(path, handler); michael@0: httpServer.start(-1); michael@0: michael@0: do_test_pending(); michael@0: michael@0: nextTest(); michael@0: } michael@0: michael@0: function nextTest() michael@0: { michael@0: fetched = false; michael@0: tests[0].prepare(); michael@0: michael@0: dump("Testing with User-Agent: " + getUA() + "\n"); michael@0: var chan = make_channel(URI); michael@0: michael@0: // Give the old channel a chance to close the cache entry first. michael@0: // XXX This is actually a race condition that might be considered a bug... michael@0: do_execute_soon(function() { michael@0: chan.asyncOpen(new ChannelListener(checkAndShiftTest, null), null); michael@0: }); michael@0: } michael@0: michael@0: function checkAndShiftTest(request, response) michael@0: { michael@0: tests[0].test(response); michael@0: michael@0: tests.shift(); michael@0: if (tests.length == 0) { michael@0: httpServer.stop(tearDown); michael@0: return; michael@0: } michael@0: michael@0: nextTest(); michael@0: } michael@0: michael@0: function tearDown() michael@0: { michael@0: setUA(""); michael@0: do_test_finished(); michael@0: } michael@0: michael@0: // Helpers michael@0: michael@0: function getUA() michael@0: { michael@0: var httphandler = Cc["@mozilla.org/network/protocol;1?name=http"]. michael@0: getService(Ci.nsIHttpProtocolHandler); michael@0: return httphandler.userAgent; michael@0: } michael@0: michael@0: function setUA(value) michael@0: { michael@0: var prefs = Cc["@mozilla.org/preferences-service;1"]. michael@0: getService(Ci.nsIPrefBranch); michael@0: prefs.setCharPref("general.useragent.override", value); michael@0: } michael@0: michael@0: function getDateString(yearDelta) { michael@0: var months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', michael@0: 'Sep', 'Oct', 'Nov', 'Dec' ]; michael@0: var days = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]; michael@0: michael@0: var d = new Date(); michael@0: return days[d.getUTCDay()] + ", " + d.getUTCDate() + " " michael@0: + months[d.getUTCMonth()] + " " + (d.getUTCFullYear() + yearDelta) michael@0: + " " + d.getUTCHours() + ":" + d.getUTCMinutes() + ":" michael@0: + d.getUTCSeconds() + " UTC"; michael@0: }