michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cr = Components.results; michael@0: const Cu = Components.utils; michael@0: michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource://testing-common/httpd.js"); michael@0: michael@0: var server = new HttpServer(); michael@0: server.registerPathHandler('/image.png', imageHandler); michael@0: server.start(-1); michael@0: michael@0: load('image_load_helpers.js'); michael@0: michael@0: var gHits = 0; michael@0: michael@0: var gIoService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); michael@0: var gPublicLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); michael@0: var gPrivateLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); michael@0: gPrivateLoader.QueryInterface(Ci.imgICache).respectPrivacyNotifications(); michael@0: michael@0: function imageHandler(metadata, response) { michael@0: gHits++; michael@0: response.setHeader("Cache-Control", "max-age=10000", false); michael@0: response.setStatusLine(metadata.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "image/png", false); michael@0: var body = "iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII="; michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: michael@0: var requests = []; michael@0: var listeners = []; michael@0: michael@0: function NotificationCallbacks(isPrivate) { michael@0: this.usePrivateBrowsing = isPrivate; michael@0: } michael@0: michael@0: NotificationCallbacks.prototype = { michael@0: QueryInterface: function (iid) { michael@0: if (iid.equals(Ci.nsISupports) || michael@0: iid.equals(Ci.nsILoadContext)) michael@0: return this; michael@0: throw Cr.NS_ERROR_NO_INTERFACE; michael@0: }, michael@0: getInterface: function(iid) { michael@0: if (iid.equals(Ci.nsILoadContext)) michael@0: return this; michael@0: throw Cr.NS_ERROR_NO_INTERFACE; michael@0: } michael@0: }; michael@0: michael@0: var gImgPath = 'http://localhost:' + server.identity.primaryPort + '/image.png'; michael@0: michael@0: function setup_chan(path, isPrivate, callback) { michael@0: var uri = gIoService.newURI(gImgPath, null, null); michael@0: var chan = gIoService.newChannelFromURI(uri); michael@0: chan.notificationCallbacks = new NotificationCallbacks(isPrivate); michael@0: var channelListener = new ChannelListener(); michael@0: chan.asyncOpen(channelListener, null); michael@0: michael@0: var listener = new ImageListener(null, callback); michael@0: var outlistener = {}; michael@0: var loader = isPrivate ? gPrivateLoader : gPublicLoader; michael@0: var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) michael@0: .createScriptedObserver(listener); michael@0: listeners.push(outer); michael@0: requests.push(loader.loadImageWithChannelXPCOM(chan, outer, null, outlistener)); michael@0: channelListener.outputListener = outlistener.value; michael@0: listener.synchronous = false; michael@0: } michael@0: michael@0: function loadImage(isPrivate, callback) { michael@0: var listener = new ImageListener(null, callback); michael@0: var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) michael@0: .createScriptedObserver(listener); michael@0: var uri = gIoService.newURI(gImgPath, null, null); michael@0: var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup); michael@0: loadGroup.notificationCallbacks = new NotificationCallbacks(isPrivate); michael@0: var loader = isPrivate ? gPrivateLoader : gPublicLoader; michael@0: requests.push(loader.loadImageXPCOM(uri, null, null, null, loadGroup, outer, null, 0, null, null)); michael@0: listener.synchronous = false; michael@0: } michael@0: michael@0: function run_loadImage_tests() { michael@0: function observer() { michael@0: Services.obs.removeObserver(observer, "cacheservice:empty-cache"); michael@0: gHits = 0; michael@0: loadImage(false, function() { michael@0: loadImage(false, function() { michael@0: loadImage(true, function() { michael@0: loadImage(true, function() { michael@0: do_check_eq(gHits, 2); michael@0: server.stop(do_test_finished); michael@0: }); michael@0: }); michael@0: }); michael@0: }); michael@0: } michael@0: michael@0: Services.obs.addObserver(observer, "cacheservice:empty-cache", false); michael@0: let cs = Cc["@mozilla.org/netwerk/cache-storage-service;1"] michael@0: .getService(Ci.nsICacheStorageService); michael@0: cs.clear(); michael@0: } michael@0: michael@0: function cleanup() michael@0: { michael@0: for (var i = 0; i < requests.length; ++i) { michael@0: requests[i].cancelAndForgetObserver(0); michael@0: } michael@0: } michael@0: michael@0: function run_test() { michael@0: do_register_cleanup(cleanup); michael@0: michael@0: do_test_pending(); michael@0: michael@0: // We create a public channel that loads an image, then an identical michael@0: // one that should cause a cache read. We then create a private channel michael@0: // and load the same image, and do that a second time to ensure a cache michael@0: // read. In total, we should cause two separate http responses to occur, michael@0: // since the private channels shouldn't be able to use the public cache. michael@0: setup_chan('/image.png', false, function() { michael@0: setup_chan('/image.png', false, function() { michael@0: setup_chan('/image.png', true, function() { michael@0: setup_chan('/image.png', true, function() { michael@0: do_check_eq(gHits, 2); michael@0: run_loadImage_tests(); michael@0: }); michael@0: }); michael@0: }); michael@0: }); michael@0: }