michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /** michael@0: * Test download resume to do real-resume instead of stalling-the-channel michael@0: * resume. Also test bug 395537 for resuming files that are deleted before michael@0: * they're resumed. Bug 398216 is checked by making sure the reported progress michael@0: * and file size are updated for finished downloads. michael@0: */ michael@0: michael@0: const nsIF = Ci.nsIFile; michael@0: const nsIDM = Ci.nsIDownloadManager; michael@0: const nsIWBP = Ci.nsIWebBrowserPersist; michael@0: const nsIWPL = Ci.nsIWebProgressListener; michael@0: const dm = Cc["@mozilla.org/download-manager;1"].getService(nsIDM); michael@0: michael@0: function run_test() michael@0: { michael@0: if (oldDownloadManagerDisabled()) { michael@0: return; michael@0: } michael@0: michael@0: /** michael@0: * 1. Create data for http server to send michael@0: */ michael@0: // data starts at 10 bytes michael@0: var data = "1234567890"; michael@0: // data * 10^4 = 100,000 bytes (actually 101,111 bytes with newline) michael@0: for (var i = 0; i < 4; i++) { michael@0: data = [data,data,data,data,data,data,data,data,data,data,"\n"].join(""); michael@0: } michael@0: michael@0: /** michael@0: * 2. Start the http server that can handle resume michael@0: */ michael@0: var httpserv = new HttpServer(); michael@0: var didResumeServer = false; michael@0: httpserv.registerPathHandler("/resume", function(meta, resp) { michael@0: var body = data; michael@0: resp.setHeader("Content-Type", "text/html", false); michael@0: if (meta.hasHeader("Range")) { michael@0: // track that we resumed for testing michael@0: didResumeServer = true; michael@0: // Syntax: bytes=[from]-[to] (we don't support multiple ranges) michael@0: var matches = meta.getHeader("Range").match(/^\s*bytes=(\d+)?-(\d+)?\s*$/); michael@0: var from = (matches[1] === undefined) ? 0 : matches[1]; michael@0: var to = (matches[2] === undefined) ? data.length - 1 : matches[2]; michael@0: if (from >= data.length) { michael@0: resp.setStatusLine(meta.httpVersion, 416, "Start pos too high"); michael@0: resp.setHeader("Content-Range", "*/" + data.length, false); michael@0: return; michael@0: } michael@0: body = body.substring(from, to + 1); michael@0: // always respond to successful range requests with 206 michael@0: resp.setStatusLine(meta.httpVersion, 206, "Partial Content"); michael@0: resp.setHeader("Content-Range", from + "-" + to + "/" + data.length, false); michael@0: } michael@0: resp.bodyOutputStream.write(body, body.length); michael@0: }); michael@0: httpserv.start(-1); michael@0: michael@0: /** michael@0: * 3. Perform various actions for certain download states michael@0: */ michael@0: var didPause = false; michael@0: var didResumeDownload = false; michael@0: dm.addListener({ michael@0: onDownloadStateChange: function(a, aDl) { michael@0: if (aDl.state == nsIDM.DOWNLOAD_DOWNLOADING && !didPause) { michael@0: /** michael@0: * (1) queued -> downloading = pause the download michael@0: */ michael@0: dm.pauseDownload(aDl.id); michael@0: } else if (aDl.state == nsIDM.DOWNLOAD_PAUSED) { michael@0: /** michael@0: * (2) downloading -> paused = remove the file michael@0: */ michael@0: didPause = true; michael@0: // Test bug 395537 by removing the file before we actually resume michael@0: aDl.targetFile.remove(false); michael@0: } else if (aDl.state == nsIDM.DOWNLOAD_FINISHED) { michael@0: /** michael@0: * (4) downloading (resumed) -> finished = check tests michael@0: */ michael@0: // did we pause at all? michael@0: do_check_true(didPause); michael@0: // did we real-resume and not fake-resume? michael@0: do_check_true(didResumeDownload); michael@0: // extra real-resume check for the server michael@0: do_check_true(didResumeServer); michael@0: // did we download the whole file? michael@0: do_check_eq(data.length, aDl.targetFile.fileSize); michael@0: // extra sanity checks on size (test bug 398216) michael@0: do_check_eq(data.length, aDl.amountTransferred); michael@0: do_check_eq(data.length, aDl.size); michael@0: michael@0: httpserv.stop(do_test_finished); michael@0: } michael@0: }, michael@0: onStateChange: function(a, b, aState, d, aDl) { michael@0: if ((aState & nsIWPL.STATE_STOP) && didPause && !didResumeServer && michael@0: !didResumeDownload) { michael@0: /** michael@0: * (3) paused -> stopped = resume the download michael@0: */ michael@0: dm.resumeDownload(aDl.id); michael@0: didResumeDownload = true; michael@0: } michael@0: }, michael@0: onProgressChange: function(a, b, c, d, e, f, g) { }, michael@0: onSecurityChange: function(a, b, c, d) { } michael@0: }); michael@0: dm.addListener(getDownloadListener()); michael@0: michael@0: /** michael@0: * 4. Start the download michael@0: */ michael@0: var destFile = dirSvc.get("ProfD", nsIF); michael@0: destFile.append("resumed"); michael@0: if (destFile.exists()) michael@0: destFile.remove(false); michael@0: var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]. michael@0: createInstance(nsIWBP); michael@0: persist.persistFlags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES | michael@0: nsIWBP.PERSIST_FLAGS_BYPASS_CACHE | michael@0: nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION; michael@0: var dl = dm.addDownload(nsIDM.DOWNLOAD_TYPE_DOWNLOAD, michael@0: createURI("http://localhost:" + michael@0: httpserv.identity.primaryPort + "/resume"), michael@0: createURI(destFile), null, null, michael@0: Math.round(Date.now() * 1000), null, persist, false); michael@0: persist.progressListener = dl.QueryInterface(nsIWPL); michael@0: persist.saveURI(dl.source, null, null, null, null, dl.targetFile, null); michael@0: michael@0: // Mark as pending, so clear this when we actually finish the download michael@0: do_test_pending(); michael@0: }