michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cu = Components.utils; michael@0: const Cr = Components.results; michael@0: michael@0: Cu.import("resource://testing-common/httpd.js"); michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: do_get_profile(); michael@0: michael@0: // Dynamically generates a classID for our component, registers it to mask michael@0: // the existing component, and stored the masked components classID to be michael@0: // restored later, when we unregister. michael@0: function registerTemporaryComponent(comp) michael@0: { michael@0: let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); michael@0: if (!comp.prototype.classID) { michael@0: let uuidgen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); michael@0: comp.prototype.classID = uuidgen.generateUUID(); michael@0: } michael@0: comp.prototype.maskedClassID = Components.ID(Cc[comp.prototype.contractID].number); michael@0: if (!comp.prototype.factory) michael@0: comp.prototype.factory = getFactory(comp); michael@0: registrar.registerFactory(comp.prototype.classID, "", comp.prototype.contractID, comp.prototype.factory); michael@0: } michael@0: michael@0: function unregisterTemporaryComponent(comp) michael@0: { michael@0: let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); michael@0: registrar.unregisterFactory(comp.prototype.classID, comp.prototype.factory); michael@0: registrar.registerFactory(comp.prototype.maskedClassID, "", comp.prototype.contractID, null); michael@0: } michael@0: michael@0: let DownloadListener = { michael@0: init: function () { michael@0: let obs = Services.obs; michael@0: obs.addObserver(this, "dl-done", true); michael@0: }, michael@0: michael@0: observe: function (subject, topic, data) { michael@0: this.onFinished(subject, topic, data); michael@0: }, michael@0: michael@0: QueryInterface: function (iid) { michael@0: if (iid.equals(Ci.nsIObserver) || michael@0: iid.equals(Ci.nsISupportsWeakReference) || michael@0: iid.equals(Ci.nsISupports)) michael@0: return this; michael@0: michael@0: throw Cr.NS_ERROR_NO_INTERFACE; michael@0: } michael@0: } michael@0: DownloadListener.init(); michael@0: michael@0: function HelperAppDlg() { } michael@0: HelperAppDlg.prototype = { michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]), michael@0: contractID: "@mozilla.org/helperapplauncherdialog;1", michael@0: show: function (launcher, ctx, reason, usePrivateUI) { michael@0: launcher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToFile; michael@0: launcher.launchWithApplication(null, false); michael@0: }, michael@0: michael@0: promptForSaveToFile: function (launcher, ctx, defaultFile, suggestedExtension, forcePrompt) { } michael@0: } michael@0: michael@0: // Stolen from XPCOMUtils, since this handy function is not public there michael@0: function getFactory(comp) michael@0: { michael@0: return { michael@0: createInstance: function (outer, iid) { michael@0: if (outer) michael@0: throw Cr.NS_ERROR_NO_AGGREGATION; michael@0: return (new comp()).QueryInterface(iid); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Override the download-manager-ui to prevent anyone from trying to open michael@0: // a window. michael@0: function DownloadMgrUI() { } michael@0: DownloadMgrUI.prototype = { michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadManagerUI]), michael@0: contractID: "@mozilla.org/download-manager-ui;1", michael@0: show: function (ir, aID, reason) { }, michael@0: michael@0: visible: false, michael@0: michael@0: getAttention: function () { } michael@0: } michael@0: michael@0: function AlertsSVC() { } michael@0: AlertsSVC.prototype = { michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]), michael@0: contractID: "@mozilla.org/alerts-service;1", michael@0: showAlertNotification: function (url, title, text, clickable, cookie, listener, name) { }, michael@0: } michael@0: michael@0: registerTemporaryComponent(HelperAppDlg); michael@0: registerTemporaryComponent(DownloadMgrUI); michael@0: registerTemporaryComponent(AlertsSVC); michael@0: michael@0: function initChildTestEnv() michael@0: { michael@0: sendCommand(' \ michael@0: const Cc = Components.classes; \ michael@0: const Ci = Components.interfaces; \ michael@0: const Cr = Components.results; \ michael@0: function WindowContext() { } \ michael@0: \ michael@0: WindowContext.prototype = { \ michael@0: getInterface: function (iid) { \ michael@0: if (iid.equals(Ci.nsIInterfaceRequestor) || \ michael@0: iid.equals(Ci.nsIURIContentListener) || \ michael@0: iid.equals(Ci.nsILoadGroup) || \ michael@0: iid.equals(Ci.nsIDocumentLoader) || \ michael@0: iid.equals(Ci.nsIDOMWindow)) \ michael@0: return this; \ michael@0: \ michael@0: throw Cr.NS_ERROR_NO_INTERFACE; \ michael@0: }, \ michael@0: \ michael@0: /* nsIURIContentListener */ \ michael@0: onStartURIOpen: function (uri) { }, \ michael@0: isPreferred: function (type, desiredtype) { return false; }, \ michael@0: \ michael@0: /* nsILoadGroup */ \ michael@0: addRequest: function (request, context) { }, \ michael@0: removeRequest: function (request, context, status) { } \ michael@0: }; \ michael@0: \ michael@0: var ioservice = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);\ michael@0: var uriloader = Cc["@mozilla.org/uriloader;1"].getService(Ci.nsIURILoader);\ michael@0: '); michael@0: } michael@0: michael@0: function testFinisher(endFunc) { michael@0: let ef = endFunc; michael@0: return function (file) { michael@0: ef(file); michael@0: runNextTest(); michael@0: } michael@0: } michael@0: michael@0: function runChildTestSet(set) michael@0: { michael@0: DownloadListener.onFinished = testFinisher(set[2]); michael@0: sendCommand('\ michael@0: let uri = ioservice.newURI("http://localhost:4444' + set[0] + '", null, null);\ michael@0: let channel = ioservice.newChannelFromURI(uri); \ michael@0: uriloader.openURI(channel, Ci.nsIURILoader.IS_CONTENT_PREFERRED, new WindowContext()); \ michael@0: '); michael@0: } michael@0: michael@0: var httpserver = null; michael@0: let currentTest = 0; michael@0: function runNextTest() michael@0: { michael@0: if (currentTest == tests.length) { michael@0: httpserver.stop(do_test_finished); michael@0: return; michael@0: } michael@0: michael@0: let set = tests[currentTest++]; michael@0: runChildTestSet(set); michael@0: } michael@0: michael@0: const responseBody = [0x1f, 0x8b, 0x08, 0x00, 0x16, 0x5a, 0x8a, 0x48, 0x02, michael@0: 0x03, 0x2b, 0x49, 0x2d, 0x2e, 0xe1, 0x02, 0x00, 0xc6, michael@0: 0x35, 0xb9, 0x3b, 0x05, 0x00, 0x00, 0x00]; michael@0: michael@0: /* michael@0: * First test: a file with Content-Type application/x-gzip and Content-Encoding gzip michael@0: * should not be decoded in a round-trip michael@0: */ michael@0: function testResponse1(metadata, response) { michael@0: response.setHeader("Content-Type", "application/x-gzip", false); michael@0: response.setHeader("Content-Encoding", "gzip", false); michael@0: response.setHeader("Content-Disposition", "attachment", false); michael@0: michael@0: var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream); michael@0: bos.setOutputStream(response.bodyOutputStream); michael@0: bos.writeByteArray(responseBody, responseBody.length); michael@0: } michael@0: michael@0: function finishTest1(subject, topic, data) { michael@0: let file = subject.QueryInterface(Ci.nsIDownload).targetFile; michael@0: do_check_true(file.path.search("test1.gz") != 0); michael@0: let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); michael@0: fis.init(file, -1, -1, 0); michael@0: let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream); michael@0: bis.setInputStream(fis); michael@0: let str = bis.readByteArray(bis.available()); michael@0: do_check_true(str.length == responseBody.length); michael@0: michael@0: let cmp = 0; michael@0: for (i = 0; i < str.length; i++) { michael@0: cmp += str[i] - responseBody[i]; michael@0: if (cmp != 0) break; michael@0: } michael@0: do_check_true(cmp == 0); michael@0: } michael@0: michael@0: /* michael@0: * Second test: a file with Content-Type text/html and Content-Encoding gzip michael@0: * should not be decoded in a round-trip, if its filename ends in ".gz". michael@0: * We specify a Content-disposition header to force it to be saved as a file. michael@0: */ michael@0: function testResponse2(metadata, response) { michael@0: response.setHeader("Content-Type", "text/html", false); michael@0: response.setHeader("Content-Encoding", "gzip", false); michael@0: response.setHeader("Content-Disposition", "attachment", false); michael@0: michael@0: var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream); michael@0: bos.setOutputStream(response.bodyOutputStream); michael@0: bos.writeByteArray(responseBody, responseBody.length); michael@0: } michael@0: michael@0: function finishTest2(subject, topic, data) { michael@0: let file = subject.QueryInterface(Ci.nsIDownload).targetFile; michael@0: do_check_true(file.path.search("test2.gz") != 0); michael@0: let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); michael@0: fis.init(file, -1, -1, 0); michael@0: let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream); michael@0: bis.setInputStream(fis); michael@0: let str = bis.readByteArray(bis.available()); michael@0: do_check_true(str.length == responseBody.length); michael@0: michael@0: let cmp = 0; michael@0: for (i = 0; i < str.length; i++) { michael@0: cmp += str[i] - responseBody[i]; michael@0: if (cmp != 0) break; michael@0: } michael@0: do_check_true(cmp == 0); michael@0: } michael@0: michael@0: function testResponse3(metadata, response) { michael@0: response.setHeader("Content-Type", "text/html", false); michael@0: response.setHeader("Content-Encoding", "gzip", false); michael@0: response.setHeader("Content-Disposition", "attachment", false); michael@0: michael@0: var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream); michael@0: bos.setOutputStream(response.bodyOutputStream); michael@0: bos.writeByteArray(responseBody, responseBody.length); michael@0: } michael@0: michael@0: function finishTest3(subject, topic, data) { michael@0: let file = subject.QueryInterface(Ci.nsIDownload).targetFile; michael@0: do_check_true(file.path.search("test3.txt") != 0); michael@0: let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); michael@0: fis.init(file, -1, -1, 0); michael@0: let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream); michael@0: bis.setInputStream(fis); michael@0: let str = bis.readByteArray(bis.available()); michael@0: let decodedBody = [ 116, 101, 115, 116, 10 ]; // 't','e','s','t','\n' michael@0: do_check_true(str.length == decodedBody.length); michael@0: michael@0: let cmp = 0; michael@0: for (i = 0; i < str.length; i++) { michael@0: cmp += str[i] - decodedBody[i]; michael@0: if (cmp != 0) break; michael@0: } michael@0: do_check_true(cmp == 0); michael@0: } michael@0: michael@0: let tests = [ michael@0: [ "/test1.gz", testResponse1, finishTest1 ], michael@0: [ "/test2.gz", testResponse2, finishTest2 ], michael@0: [ "/test3.txt", testResponse3, finishTest3 ], michael@0: ]; michael@0: michael@0: function run_test() { michael@0: // do_load_child_test_harness(); michael@0: httpserver = new HttpServer(); michael@0: httpserver.start(4444); michael@0: do_test_pending(); michael@0: michael@0: initChildTestEnv(); michael@0: michael@0: for each (set in tests) michael@0: httpserver.registerPathHandler(set[0], set[1]); michael@0: michael@0: runNextTest(); michael@0: }