diff options
Diffstat (limited to 'dom/downloads')
-rw-r--r-- | dom/downloads/DownloadsAPI.js | 517 | ||||
-rw-r--r-- | dom/downloads/DownloadsAPI.jsm | 365 | ||||
-rw-r--r-- | dom/downloads/DownloadsAPI.manifest | 6 | ||||
-rw-r--r-- | dom/downloads/DownloadsIPC.jsm | 224 | ||||
-rw-r--r-- | dom/downloads/moz.build | 21 | ||||
-rw-r--r-- | dom/downloads/tests/clear_all_done_helper.js | 67 | ||||
-rw-r--r-- | dom/downloads/tests/mochitest.ini | 15 | ||||
-rw-r--r-- | dom/downloads/tests/serve_file.sjs | 170 | ||||
-rw-r--r-- | dom/downloads/tests/test_downloads_bad_file.html | 93 | ||||
-rw-r--r-- | dom/downloads/tests/test_downloads_basic.html | 128 | ||||
-rw-r--r-- | dom/downloads/tests/test_downloads_large.html | 110 | ||||
-rw-r--r-- | dom/downloads/tests/test_downloads_navigator_object.html | 75 | ||||
-rw-r--r-- | dom/downloads/tests/test_downloads_pause_remove.html | 117 | ||||
-rw-r--r-- | dom/downloads/tests/test_downloads_pause_resume.html | 121 |
14 files changed, 0 insertions, 2029 deletions
diff --git a/dom/downloads/DownloadsAPI.js b/dom/downloads/DownloadsAPI.js deleted file mode 100644 index 8294e2a3e..000000000 --- a/dom/downloads/DownloadsAPI.js +++ /dev/null @@ -1,517 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const Cr = Components.results; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); -Cu.import("resource://gre/modules/DownloadsIPC.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "cpmm", - "@mozilla.org/childprocessmessagemanager;1", - "nsIMessageSender"); -XPCOMUtils.defineLazyServiceGetter(this, "volumeService", - "@mozilla.org/telephony/volume-service;1", - "nsIVolumeService"); - -/** - * The content process implementations of navigator.mozDownloadManager and its - * DOMDownload download objects. Uses DownloadsIPC.jsm to communicate with - * DownloadsAPI.jsm in the parent process. - */ - -function debug(aStr) { -#ifdef MOZ_DEBUG - dump("-*- DownloadsAPI.js : " + aStr + "\n"); -#endif -} - -function DOMDownloadManagerImpl() { - debug("DOMDownloadManagerImpl constructor"); -} - -DOMDownloadManagerImpl.prototype = { - __proto__: DOMRequestIpcHelper.prototype, - - // nsIDOMGlobalPropertyInitializer implementation - init: function(aWindow) { - debug("DownloadsManager init"); - this.initDOMRequestHelper(aWindow, - ["Downloads:Added", - "Downloads:Removed"]); - - // Get the manifest URL if this is an installed app - let appsService = Cc["@mozilla.org/AppsService;1"] - .getService(Ci.nsIAppsService); - let principal = aWindow.document.nodePrincipal; - // This returns the empty string if we're not an installed app. Coerce to - // null. - this._manifestURL = appsService.getManifestURLByLocalId(principal.appId) || - null; - }, - - uninit: function() { - debug("uninit"); - downloadsCache.evict(this._window); - }, - - set ondownloadstart(aHandler) { - this.__DOM_IMPL__.setEventHandler("ondownloadstart", aHandler); - }, - - get ondownloadstart() { - return this.__DOM_IMPL__.getEventHandler("ondownloadstart"); - }, - - getDownloads: function() { - debug("getDownloads()"); - - return this.createPromise(function (aResolve, aReject) { - DownloadsIPC.getDownloads().then( - function(aDownloads) { - // Turn the list of download objects into DOM objects and - // send them. - let array = new this._window.Array(); - for (let id in aDownloads) { - let dom = createDOMDownloadObject(this._window, aDownloads[id]); - array.push(this._prepareForContent(dom)); - } - aResolve(array); - }.bind(this), - function() { - aReject("GetDownloadsError"); - } - ); - }.bind(this)); - }, - - clearAllDone: function() { - debug("clearAllDone()"); - // This is a void function; we just kick it off. No promises, etc. - DownloadsIPC.clearAllDone(); - }, - - remove: function(aDownload) { - debug("remove " + aDownload.url + " " + aDownload.id); - return this.createPromise(function (aResolve, aReject) { - if (!downloadsCache.has(this._window, aDownload.id)) { - debug("no download " + aDownload.id); - aReject("InvalidDownload"); - return; - } - - DownloadsIPC.remove(aDownload.id).then( - function(aResult) { - let dom = createDOMDownloadObject(this._window, aResult); - // Change the state right away to not race against the update message. - dom.wrappedJSObject.state = "finalized"; - aResolve(this._prepareForContent(dom)); - }.bind(this), - function() { - aReject("RemoveError"); - } - ); - }.bind(this)); - }, - - adoptDownload: function(aAdoptDownloadDict) { - // Our AdoptDownloadDict only includes simple types, which WebIDL enforces. - // We have no object/any types so we do not need to worry about invoking - // JSON.stringify (and it inheriting our security privileges). - debug("adoptDownload"); - return this.createPromise(function (aResolve, aReject) { - if (!aAdoptDownloadDict) { - debug("Download dictionary is required!"); - aReject("InvalidDownload"); - return; - } - if (!aAdoptDownloadDict.storageName || !aAdoptDownloadDict.storagePath || - !aAdoptDownloadDict.contentType) { - debug("Missing one of: storageName, storagePath, contentType"); - aReject("InvalidDownload"); - return; - } - - // Convert storageName/storagePath to a local filesystem path. - let volume; - // getVolumeByName throws if you give it something it doesn't like - // because XPConnect converts the NS_ERROR_NOT_AVAILABLE to an - // exception. So catch it. - try { - volume = volumeService.getVolumeByName(aAdoptDownloadDict.storageName); - } catch (ex) {} - if (!volume) { - debug("Invalid storage name: " + aAdoptDownloadDict.storageName); - aReject("InvalidDownload"); - return; - } - let computedPath = volume.mountPoint + '/' + - aAdoptDownloadDict.storagePath; - // We validate that there is actually a file at the given path in the - // parent process in DownloadsAPI.js because that's where the file - // access would actually occur either way. - - // Create a DownloadsAPI.jsm 'jsonDownload' style representation. - let jsonDownload = { - url: aAdoptDownloadDict.url, - path: computedPath, - contentType: aAdoptDownloadDict.contentType, - startTime: aAdoptDownloadDict.startTime.valueOf() || Date.now(), - sourceAppManifestURL: this._manifestURL - }; - - DownloadsIPC.adoptDownload(jsonDownload).then( - function(aResult) { - let domDownload = createDOMDownloadObject(this._window, aResult); - aResolve(this._prepareForContent(domDownload)); - }.bind(this), - function(aResult) { - // This will be one of: AdoptError (generic catch-all), - // AdoptNoSuchFile, AdoptFileIsDirectory - aReject(aResult.error); - } - ); - }.bind(this)); - }, - - - /** - * Turns a chrome download object into a content accessible one. - * When we have __DOM_IMPL__ available we just use that, otherwise - * we run _create() with the wrapped js object. - */ - _prepareForContent: function(aChromeObject) { - if (aChromeObject.__DOM_IMPL__) { - return aChromeObject.__DOM_IMPL__; - } - let res = this._window.DOMDownload._create(this._window, - aChromeObject.wrappedJSObject); - return res; - }, - - receiveMessage: function(aMessage) { - let data = aMessage.data; - switch(aMessage.name) { - case "Downloads:Added": - debug("Adding " + uneval(data)); - let event = new this._window.DownloadEvent("downloadstart", { - download: - this._prepareForContent(createDOMDownloadObject(this._window, data)) - }); - this.__DOM_IMPL__.dispatchEvent(event); - break; - } - }, - - classID: Components.ID("{c6587afa-0696-469f-9eff-9dac0dd727fe}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, - Ci.nsISupportsWeakReference, - Ci.nsIObserver, - Ci.nsIDOMGlobalPropertyInitializer]), - -}; - -/** - * Keep track of download objects per window. - */ -var downloadsCache = { - init: function() { - this.cache = new WeakMap(); - }, - - has: function(aWindow, aId) { - let downloads = this.cache.get(aWindow); - return !!(downloads && downloads[aId]); - }, - - get: function(aWindow, aDownload) { - let downloads = this.cache.get(aWindow); - if (!(downloads && downloads[aDownload.id])) { - debug("Adding download " + aDownload.id + " to cache."); - if (!downloads) { - this.cache.set(aWindow, {}); - downloads = this.cache.get(aWindow); - } - // Create the object and add it to the cache. - let impl = Cc["@mozilla.org/downloads/download;1"] - .createInstance(Ci.nsISupports); - impl.wrappedJSObject._init(aWindow, aDownload); - downloads[aDownload.id] = impl; - } - return downloads[aDownload.id]; - }, - - evict: function(aWindow) { - this.cache.delete(aWindow); - } -}; - -downloadsCache.init(); - -/** - * The DOM facade of a download object. - */ - -function createDOMDownloadObject(aWindow, aDownload) { - return downloadsCache.get(aWindow, aDownload); -} - -function DOMDownloadImpl() { - debug("DOMDownloadImpl constructor "); - - this.wrappedJSObject = this; - this.totalBytes = 0; - this.currentBytes = 0; - this.url = null; - this.path = null; - this.storageName = null; - this.storagePath = null; - this.contentType = null; - - /* fields that require getters/setters */ - this._error = null; - this._startTime = new Date(); - this._state = "stopped"; - - /* private fields */ - this.id = null; -} - -DOMDownloadImpl.prototype = { - - createPromise: function(aPromiseInit) { - return new this._window.Promise(aPromiseInit); - }, - - pause: function() { - debug("DOMDownloadImpl pause"); - let id = this.id; - // We need to wrap the Promise.jsm promise in a "real" DOM promise... - return this.createPromise(function(aResolve, aReject) { - DownloadsIPC.pause(id).then(aResolve, aReject); - }); - }, - - resume: function() { - debug("DOMDownloadImpl resume"); - let id = this.id; - // We need to wrap the Promise.jsm promise in a "real" DOM promise... - return this.createPromise(function(aResolve, aReject) { - DownloadsIPC.resume(id).then(aResolve, aReject); - }); - }, - - set onstatechange(aHandler) { - this.__DOM_IMPL__.setEventHandler("onstatechange", aHandler); - }, - - get onstatechange() { - return this.__DOM_IMPL__.getEventHandler("onstatechange"); - }, - - get error() { - return this._error; - }, - - set error(aError) { - this._error = aError; - }, - - get startTime() { - return this._startTime; - }, - - set startTime(aStartTime) { - if (aStartTime instanceof Date) { - this._startTime = aStartTime; - } - else { - this._startTime = new Date(aStartTime); - } - }, - - get state() { - return this._state; - }, - - // We require a setter here to simplify the internals of the Download Manager - // since we actually pass dummy JSON objects to the child process and update - // them. This is the case for all other setters for read-only attributes - // implemented in this object. - set state(aState) { - // We need to ensure that XPCOM consumers of this API respect the enum - // values as well. - if (["downloading", - "stopped", - "succeeded", - "finalized"].indexOf(aState) != -1) { - this._state = aState; - } - }, - - /** - * Initialize a DOMDownload instance for the given window using the - * 'jsonDownload' serialized format of the download encoded by - * DownloadsAPI.jsm. - */ - _init: function(aWindow, aDownload) { - this._window = aWindow; - this.id = aDownload.id; - this._update(aDownload); - Services.obs.addObserver(this, "downloads-state-change-" + this.id, - /* ownsWeak */ true); - debug("observer set for " + this.id); - }, - - /** - * Updates the state of the object and fires the statechange event. - */ - _update: function(aDownload) { - debug("update " + uneval(aDownload)); - if (this.id != aDownload.id) { - return; - } - - let props = ["totalBytes", "currentBytes", "url", "path", "storageName", - "storagePath", "state", "contentType", "startTime", - "sourceAppManifestURL"]; - let changed = false; - let changedProps = {}; - - props.forEach((prop) => { - if (prop in aDownload && (aDownload[prop] != this[prop])) { - this[prop] = aDownload[prop]; - changedProps[prop] = changed = true; - } - }); - - // When the path changes, we should update the storage name and - // storage path used for our downloaded file in case our download - // was re-targetted to a different storage and/or filename. - if (changedProps["path"]) { - let storages = this._window.navigator.getDeviceStorages("sdcard"); - let preferredStorageName; - // Use the first one or the default storage. Just like jsdownloads picks - // the default / preferred download directory. - storages.forEach((aStorage) => { - if (aStorage.default || !preferredStorageName) { - preferredStorageName = aStorage.storageName; - } - }); - // Now get the path for this storage area. - let volume; - if (preferredStorageName) { - let volume = volumeService.getVolumeByName(preferredStorageName); - if (volume) { - // Finally, create the relative path of the file that can be used - // later on to retrieve the file via DeviceStorage. Our path - // needs to omit the starting '/'. - this.storageName = preferredStorageName; - this.storagePath = - this.path.substring(this.path.indexOf(volume.mountPoint) + - volume.mountPoint.length + 1); - } - } - } - - if (aDownload.error) { - // - // When we get a generic error failure back from the js downloads api - // we will verify the status of device storage to see if we can't provide - // a better error result value. - // - // XXX If these checks expand further, consider moving them into their - // own function. - // - let result = aDownload.error.result; - let storage = this._window.navigator.getDeviceStorage("sdcard"); - - // If we don't have access to device storage we'll opt out of these - // extra checks as they are all dependent on the state of the storage. - if (result == Cr.NS_ERROR_FAILURE && storage) { - // We will delay sending the notification until we've inferred which - // error is really happening. - changed = false; - debug("Attempting to infer error via device storage sanity checks."); - // Get device storage and request availability status. - let available = storage.available(); - available.onsuccess = (function() { - debug("Storage Status = '" + available.result + "'"); - let inferredError = result; - switch (available.result) { - case "unavailable": - inferredError = Cr.NS_ERROR_FILE_NOT_FOUND; - break; - case "shared": - inferredError = Cr.NS_ERROR_FILE_ACCESS_DENIED; - break; - } - this._updateWithError(aDownload, inferredError); - }).bind(this); - available.onerror = (function() { - this._updateWithError(aDownload, result); - }).bind(this); - } - - this.error = - new this._window.DOMError("DownloadError", result); - } else { - this.error = null; - } - - // The visible state has not changed, so no need to fire an event. - if (!changed) { - return; - } - - this._sendStateChange(); - }, - - _updateWithError: function(aDownload, aError) { - this.error = - new this._window.DOMError("DownloadError", aError); - this._sendStateChange(); - }, - - _sendStateChange: function() { - // __DOM_IMPL__ may not be available at first update. - if (this.__DOM_IMPL__) { - let event = new this._window.DownloadEvent("statechange", { - download: this.__DOM_IMPL__ - }); - debug("Dispatching statechange event. state=" + this.state); - this.__DOM_IMPL__.dispatchEvent(event); - } - }, - - observe: function(aSubject, aTopic, aData) { - debug("DOMDownloadImpl observe " + aTopic); - if (aTopic !== "downloads-state-change-" + this.id) { - return; - } - - try { - let download = JSON.parse(aData); - // We get the start time as milliseconds, not as a Date object. - if (download.startTime) { - download.startTime = new Date(download.startTime); - } - this._update(download); - } catch(e) {} - }, - - classID: Components.ID("{96b81b99-aa96-439d-8c59-92eeed34705f}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, - Ci.nsIObserver, - Ci.nsISupportsWeakReference]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DOMDownloadManagerImpl, - DOMDownloadImpl]); diff --git a/dom/downloads/DownloadsAPI.jsm b/dom/downloads/DownloadsAPI.jsm deleted file mode 100644 index dfb8286fe..000000000 --- a/dom/downloads/DownloadsAPI.jsm +++ /dev/null @@ -1,365 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; - -this.EXPORTED_SYMBOLS = []; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Downloads.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "ppmm", - "@mozilla.org/parentprocessmessagemanager;1", - "nsIMessageBroadcaster"); - -/** - * Parent process logic that services download API requests from the - * DownloadAPI.js instances in content processeses. The actual work of managing - * downloads is done by Toolkit's Downloads.jsm. This module is loaded by B2G's - * shell.js - */ - -function debug(aStr) { -#ifdef MOZ_DEBUG - dump("-*- DownloadsAPI.jsm : " + aStr + "\n"); -#endif -} - -function sendPromiseMessage(aMm, aMessageName, aData, aError) { - debug("sendPromiseMessage " + aMessageName); - let msg = { - id: aData.id, - promiseId: aData.promiseId - }; - - if (aError) { - msg.error = aError; - } - - aMm.sendAsyncMessage(aMessageName, msg); -} - -var DownloadsAPI = { - init: function() { - debug("init"); - - this._ids = new WeakMap(); // Maps toolkit download objects to ids. - this._index = {}; // Maps ids to downloads. - - ["Downloads:GetList", - "Downloads:ClearAllDone", - "Downloads:Remove", - "Downloads:Pause", - "Downloads:Resume", - "Downloads:Adopt"].forEach((msgName) => { - ppmm.addMessageListener(msgName, this); - }); - - let self = this; - Task.spawn(function () { - let list = yield Downloads.getList(Downloads.ALL); - yield list.addView(self); - - debug("view added to download list."); - }).then(null, Components.utils.reportError); - - this._currentId = 0; - }, - - /** - * Returns a unique id for each download, hashing the url and the path. - */ - downloadId: function(aDownload) { - let id = this._ids.get(aDownload, null); - if (!id) { - id = "download-" + this._currentId++; - this._ids.set(aDownload, id); - this._index[id] = aDownload; - } - return id; - }, - - getDownloadById: function(aId) { - return this._index[aId]; - }, - - /** - * Converts a download object into a plain json object that we'll - * send to the DOM side. - */ - jsonDownload: function(aDownload) { - let res = { - totalBytes: aDownload.totalBytes, - currentBytes: aDownload.currentBytes, - url: aDownload.source.url, - path: aDownload.target.path, - contentType: aDownload.contentType, - startTime: aDownload.startTime.getTime(), - sourceAppManifestURL: aDownload._unknownProperties && - aDownload._unknownProperties.sourceAppManifestURL - }; - - if (aDownload.error) { - res.error = aDownload.error; - } - - res.id = this.downloadId(aDownload); - - // The state of the download. Can be any of "downloading", "stopped", - // "succeeded", finalized". - - // Default to "stopped" - res.state = "stopped"; - if (!aDownload.stopped && - !aDownload.canceled && - !aDownload.succeeded && - !aDownload.DownloadError) { - res.state = "downloading"; - } else if (aDownload.succeeded) { - res.state = "succeeded"; - } - return res; - }, - - /** - * download view methods. - */ - onDownloadAdded: function(aDownload) { - let download = this.jsonDownload(aDownload); - debug("onDownloadAdded " + uneval(download)); - ppmm.broadcastAsyncMessage("Downloads:Added", download); - }, - - onDownloadRemoved: function(aDownload) { - let download = this.jsonDownload(aDownload); - download.state = "finalized"; - debug("onDownloadRemoved " + uneval(download)); - ppmm.broadcastAsyncMessage("Downloads:Removed", download); - this._index[this._ids.get(aDownload)] = null; - this._ids.delete(aDownload); - }, - - onDownloadChanged: function(aDownload) { - let download = this.jsonDownload(aDownload); - debug("onDownloadChanged " + uneval(download)); - ppmm.broadcastAsyncMessage("Downloads:Changed", download); - }, - - receiveMessage: function(aMessage) { - if (!aMessage.target.assertPermission("downloads")) { - debug("No 'downloads' permission!"); - return; - } - - debug("message: " + aMessage.name); - - switch (aMessage.name) { - case "Downloads:GetList": - this.getList(aMessage.data, aMessage.target); - break; - case "Downloads:ClearAllDone": - this.clearAllDone(aMessage.data, aMessage.target); - break; - case "Downloads:Remove": - this.remove(aMessage.data, aMessage.target); - break; - case "Downloads:Pause": - this.pause(aMessage.data, aMessage.target); - break; - case "Downloads:Resume": - this.resume(aMessage.data, aMessage.target); - break; - case "Downloads:Adopt": - this.adoptDownload(aMessage.data, aMessage.target); - break; - default: - debug("Invalid message: " + aMessage.name); - } - }, - - getList: function(aData, aMm) { - debug("getList called!"); - let self = this; - Task.spawn(function () { - let list = yield Downloads.getList(Downloads.ALL); - let downloads = yield list.getAll(); - let res = []; - downloads.forEach((aDownload) => { - res.push(self.jsonDownload(aDownload)); - }); - aMm.sendAsyncMessage("Downloads:GetList:Return", res); - }).then(null, Components.utils.reportError); - }, - - clearAllDone: function(aData, aMm) { - debug("clearAllDone called!"); - Task.spawn(function () { - let list = yield Downloads.getList(Downloads.ALL); - list.removeFinished(); - }).then(null, Components.utils.reportError); - }, - - remove: function(aData, aMm) { - debug("remove id " + aData.id); - let download = this.getDownloadById(aData.id); - if (!download) { - sendPromiseMessage(aMm, "Downloads:Remove:Return", - aData, "NoSuchDownload"); - return; - } - - Task.spawn(function() { - yield download.finalize(true); - let list = yield Downloads.getList(Downloads.ALL); - yield list.remove(download); - }).then( - function() { - sendPromiseMessage(aMm, "Downloads:Remove:Return", aData); - }, - function() { - sendPromiseMessage(aMm, "Downloads:Remove:Return", - aData, "RemoveError"); - } - ); - }, - - pause: function(aData, aMm) { - debug("pause id " + aData.id); - let download = this.getDownloadById(aData.id); - if (!download) { - sendPromiseMessage(aMm, "Downloads:Pause:Return", - aData, "NoSuchDownload"); - return; - } - - download.cancel().then( - function() { - sendPromiseMessage(aMm, "Downloads:Pause:Return", aData); - }, - function() { - sendPromiseMessage(aMm, "Downloads:Pause:Return", - aData, "PauseError"); - } - ); - }, - - resume: function(aData, aMm) { - debug("resume id " + aData.id); - let download = this.getDownloadById(aData.id); - if (!download) { - sendPromiseMessage(aMm, "Downloads:Resume:Return", - aData, "NoSuchDownload"); - return; - } - - download.start().then( - function() { - sendPromiseMessage(aMm, "Downloads:Resume:Return", aData); - }, - function() { - sendPromiseMessage(aMm, "Downloads:Resume:Return", - aData, "ResumeError"); - } - ); - }, - - /** - * Receive a download to adopt in the same representation we produce from - * our "jsonDownload" normalizer and add it to the list of downloads. - */ - adoptDownload: function(aData, aMm) { - let adoptJsonRep = aData.jsonDownload; - debug("adoptDownload " + uneval(adoptJsonRep)); - - Task.spawn(function* () { - // Verify that the file exists on disk. This will result in a rejection - // if the file does not exist. We will also use this information for the - // file size to avoid weird inconsistencies. We ignore the filesystem - // timestamp in favor of whatever the caller is telling us. - let fileInfo = yield OS.File.stat(adoptJsonRep.path); - - // We also require that the file is not a directory. - if (fileInfo.isDir) { - throw new Error("AdoptFileIsDirectory"); - } - - // We need to create a Download instance to add to the list. Create a - // serialized representation and then from there the instance. - let serializedRep = { - // explicit initializations in toSerializable - source: { - url: adoptJsonRep.url - // This is where isPrivate would go if adoption supported private - // browsing. - }, - target: { - path: adoptJsonRep.path, - }, - startTime: adoptJsonRep.startTime, - // kPlainSerializableDownloadProperties propagations - succeeded: true, // (all adopted downloads are required to be completed) - totalBytes: fileInfo.size, - contentType: adoptJsonRep.contentType, - // unknown properties added/used by the DownloadsAPI - currentBytes: fileInfo.size, - sourceAppManifestURL: adoptJsonRep.sourceAppManifestURL - }; - - let download = yield Downloads.createDownload(serializedRep); - - // The ALL list is a DownloadCombinedList instance that combines the - // PUBLIC (persisted to disk) and PRIVATE (ephemeral) download lists.. - // When we call add on it, it dispatches to the appropriate list based on - // the 'isPrivate' field of the source. (Which we don't initialize and - // defaults to false.) - let allDownloadList = yield Downloads.getList(Downloads.ALL); - - // This add will automatically notify all views of the added download, - // including DownloadsAPI instances and the DownloadAutoSaveView that's - // subscribed to the PUBLIC list and will save the download. - yield allDownloadList.add(download); - - debug("download adopted"); - // The notification above occurred synchronously, and so we will have - // already dispatched an added notification for our download to the child - // process in question. As such, we only need to relay the download id - // since the download will already have been cached. - return download; - }.bind(this)).then( - (download) => { - sendPromiseMessage(aMm, "Downloads:Adopt:Return", - { - id: this.downloadId(download), - promiseId: aData.promiseId - }); - }, - (ex) => { - let reportAs = "AdoptError"; - // Provide better error codes for expected errors. - if (ex instanceof OS.File.Error && ex.becauseNoSuchFile) { - reportAs = "AdoptNoSuchFile"; - } else if (ex.message === "AdoptFileIsDirectory") { - reportAs = ex.message; - } else { - // Anything else is unexpected and should be reported to help track - // down what's going wrong. - debug("unexpected download error: " + ex); - Cu.reportError(ex); - } - sendPromiseMessage(aMm, "Downloads:Adopt:Return", - { - promiseId: aData.promiseId - }, - reportAs); - }); - } -}; - -DownloadsAPI.init(); diff --git a/dom/downloads/DownloadsAPI.manifest b/dom/downloads/DownloadsAPI.manifest deleted file mode 100644 index 8d6dc9396..000000000 --- a/dom/downloads/DownloadsAPI.manifest +++ /dev/null @@ -1,6 +0,0 @@ -# DownloadsAPI.js -component {c6587afa-0696-469f-9eff-9dac0dd727fe} DownloadsAPI.js -contract @mozilla.org/downloads/manager;1 {c6587afa-0696-469f-9eff-9dac0dd727fe} - -component {96b81b99-aa96-439d-8c59-92eeed34705f} DownloadsAPI.js -contract @mozilla.org/downloads/download;1 {96b81b99-aa96-439d-8c59-92eeed34705f} diff --git a/dom/downloads/DownloadsIPC.jsm b/dom/downloads/DownloadsIPC.jsm deleted file mode 100644 index 0e290abf4..000000000 --- a/dom/downloads/DownloadsIPC.jsm +++ /dev/null @@ -1,224 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; - -this.EXPORTED_SYMBOLS = ["DownloadsIPC"]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "cpmm", - "@mozilla.org/childprocessmessagemanager;1", - "nsIMessageSender"); - -/** - * This module lives in the child process and receives the ipc messages - * from the parent. It saves the download's state and redispatch changes - * to DOM objects using an observer notification. - * - * This module needs to be loaded once and only once per process. - */ - -function debug(aStr) { -#ifdef MOZ_DEBUG - dump("-*- DownloadsIPC.jsm : " + aStr + "\n"); -#endif -} - -const ipcMessages = ["Downloads:Added", - "Downloads:Removed", - "Downloads:Changed", - "Downloads:GetList:Return", - "Downloads:Remove:Return", - "Downloads:Pause:Return", - "Downloads:Resume:Return", - "Downloads:Adopt:Return"]; - -this.DownloadsIPC = { - downloads: {}, - - init: function() { - debug("init"); - Services.obs.addObserver(this, "xpcom-shutdown", false); - ipcMessages.forEach((aMessage) => { - cpmm.addMessageListener(aMessage, this); - }); - - // We need to get the list of current downloads. - this.ready = false; - this.getListPromises = []; - this.downloadPromises = {}; - cpmm.sendAsyncMessage("Downloads:GetList", {}); - this._promiseId = 0; - }, - - notifyChanges: function(aId) { - // TODO: use the subject instead of stringifying. - if (this.downloads[aId]) { - debug("notifyChanges notifying changes for " + aId); - Services.obs.notifyObservers(null, "downloads-state-change-" + aId, - JSON.stringify(this.downloads[aId])); - } else { - debug("notifyChanges failed for " + aId) - } - }, - - _updateDownloadsArray: function(aDownloads) { - this.downloads = []; - // We actually have an array of downloads. - aDownloads.forEach((aDownload) => { - this.downloads[aDownload.id] = aDownload; - }); - }, - - receiveMessage: function(aMessage) { - let download = aMessage.data; - debug("message: " + aMessage.name); - switch(aMessage.name) { - case "Downloads:GetList:Return": - this._updateDownloadsArray(download); - - if (!this.ready) { - this.getListPromises.forEach(aPromise => - aPromise.resolve(this.downloads)); - this.getListPromises.length = 0; - } - this.ready = true; - break; - case "Downloads:Added": - this.downloads[download.id] = download; - this.notifyChanges(download.id); - break; - case "Downloads:Removed": - if (this.downloads[download.id]) { - this.downloads[download.id] = download; - this.notifyChanges(download.id); - delete this.downloads[download.id]; - } - break; - case "Downloads:Changed": - // Only update properties that actually changed. - let cached = this.downloads[download.id]; - if (!cached) { - debug("No download found for " + download.id); - return; - } - let props = ["totalBytes", "currentBytes", "url", "path", "state", - "contentType", "startTime"]; - let changed = false; - - props.forEach((aProp) => { - if (download[aProp] && (download[aProp] != cached[aProp])) { - cached[aProp] = download[aProp]; - changed = true; - } - }); - - // Updating the error property. We always get a 'state' change as - // well. - cached.error = download.error; - - if (changed) { - this.notifyChanges(download.id); - } - break; - case "Downloads:Remove:Return": - case "Downloads:Pause:Return": - case "Downloads:Resume:Return": - case "Downloads:Adopt:Return": - if (this.downloadPromises[download.promiseId]) { - if (!download.error) { - this.downloadPromises[download.promiseId].resolve(download); - } else { - this.downloadPromises[download.promiseId].reject(download); - } - delete this.downloadPromises[download.promiseId]; - } - break; - } - }, - - /** - * Returns a promise that is resolved with the list of current downloads. - */ - getDownloads: function() { - debug("getDownloads()"); - let deferred = Promise.defer(); - if (this.ready) { - debug("Returning existing list."); - deferred.resolve(this.downloads); - } else { - this.getListPromises.push(deferred); - } - return deferred.promise; - }, - - /** - * Void function to trigger removal of completed downloads. - */ - clearAllDone: function() { - debug("clearAllDone"); - cpmm.sendAsyncMessage("Downloads:ClearAllDone", {}); - }, - - promiseId: function() { - return this._promiseId++; - }, - - remove: function(aId) { - debug("remove " + aId); - let deferred = Promise.defer(); - let pId = this.promiseId(); - this.downloadPromises[pId] = deferred; - cpmm.sendAsyncMessage("Downloads:Remove", - { id: aId, promiseId: pId }); - return deferred.promise; - }, - - pause: function(aId) { - debug("pause " + aId); - let deferred = Promise.defer(); - let pId = this.promiseId(); - this.downloadPromises[pId] = deferred; - cpmm.sendAsyncMessage("Downloads:Pause", - { id: aId, promiseId: pId }); - return deferred.promise; - }, - - resume: function(aId) { - debug("resume " + aId); - let deferred = Promise.defer(); - let pId = this.promiseId(); - this.downloadPromises[pId] = deferred; - cpmm.sendAsyncMessage("Downloads:Resume", - { id: aId, promiseId: pId }); - return deferred.promise; - }, - - adoptDownload: function(aJsonDownload) { - debug("adoptDownload"); - let deferred = Promise.defer(); - let pId = this.promiseId(); - this.downloadPromises[pId] = deferred; - cpmm.sendAsyncMessage("Downloads:Adopt", - { jsonDownload: aJsonDownload, promiseId: pId }); - return deferred.promise; - }, - - observe: function(aSubject, aTopic, aData) { - if (aTopic == "xpcom-shutdown") { - ipcMessages.forEach((aMessage) => { - cpmm.removeMessageListener(aMessage, this); - }); - } - } -}; - -DownloadsIPC.init(); diff --git a/dom/downloads/moz.build b/dom/downloads/moz.build deleted file mode 100644 index 07bda1c4f..000000000 --- a/dom/downloads/moz.build +++ /dev/null @@ -1,21 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -if CONFIG["MOZ_B2G"]: - MOCHITEST_MANIFESTS += ['tests/mochitest.ini'] - -EXTRA_COMPONENTS += [ - 'DownloadsAPI.manifest', -] - -EXTRA_PP_COMPONENTS += [ - 'DownloadsAPI.js', -] - -EXTRA_PP_JS_MODULES += [ - 'DownloadsAPI.jsm', - 'DownloadsIPC.jsm', -] diff --git a/dom/downloads/tests/clear_all_done_helper.js b/dom/downloads/tests/clear_all_done_helper.js deleted file mode 100644 index 62fa1a2f3..000000000 --- a/dom/downloads/tests/clear_all_done_helper.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * A helper to clear out the existing downloads known to the mozDownloadManager - * / downloads.js. - * - * It exists because previously mozDownloadManager.clearAllDone() thought that - * when it returned that all the completed downloads would be cleared out. It - * was wrong and this led to various intermittent test failurse. In discussion - * on https://bugzil.la/979446#c13 and onwards, it was decided that - * clearAllDone() was in the wrong and that the jsdownloads API it depends on - * was not going to change to make it be in the right. - * - * The existing uses of clearAllDone() in tests seemed to be about: - * - Exploding if there was somehow still a download in progress - * - Clearing out the download list at the start of a test so that calls to - * getDownloads() wouldn't have to worry about existing downloads, etc. - * - * From discussion, the right way to handle clearing is to wait for the expected - * removal events to occur for the existing downloads. So that's what we do. - * We still generate a test failure if there are any in-progress downloads. - * - * @param {Boolean} [getDownloads=false] - * If true, invoke getDownloads after clearing the download list and return - * its value. - */ -function clearAllDoneHelper(getDownloads) { - var clearedPromise = new Promise(function(resolve, reject) { - function gotDownloads(downloads) { - // If there are no downloads, we're already done. - if (downloads.length === 0) { - resolve(); - return; - } - - // Track the set of expected downloads that will be finalized. - var expectedIds = new Set(); - function changeHandler(evt) { - var download = evt.download; - if (download.state === "finalized") { - expectedIds.delete(download.id); - if (expectedIds.size === 0) { - resolve(); - } - } - } - downloads.forEach(function(download) { - if (download.state === "downloading") { - ok(false, "A download is still active: " + download.path); - reject("Active download"); - } - download.onstatechange = changeHandler; - expectedIds.add(download.id); - }); - navigator.mozDownloadManager.clearAllDone(); - } - function gotBadNews(err) { - ok(false, "Problem clearing all downloads: " + err); - reject(err); - } - navigator.mozDownloadManager.getDownloads().then(gotDownloads, gotBadNews); - }); - if (!getDownloads) { - return clearedPromise; - } - return clearedPromise.then(function() { - return navigator.mozDownloadManager.getDownloads(); - }); -} diff --git a/dom/downloads/tests/mochitest.ini b/dom/downloads/tests/mochitest.ini deleted file mode 100644 index e13e4d887..000000000 --- a/dom/downloads/tests/mochitest.ini +++ /dev/null @@ -1,15 +0,0 @@ -[DEFAULT] -# The actual requirement for mozDownloadManager is MOZ_GONK because of -# the nsIVolumeService dependency. Until https://bugzil.la/1130264 is -# addressed, there is no way for mulet to run these tests. -run-if = toolkit == 'gonk' -support-files = - serve_file.sjs - clear_all_done_helper.js - -[test_downloads_navigator_object.html] -[test_downloads_basic.html] -[test_downloads_large.html] -[test_downloads_bad_file.html] -[test_downloads_pause_remove.html] -[test_downloads_pause_resume.html] diff --git a/dom/downloads/tests/serve_file.sjs b/dom/downloads/tests/serve_file.sjs deleted file mode 100644 index d0171d7ca..000000000 --- a/dom/downloads/tests/serve_file.sjs +++ /dev/null @@ -1,170 +0,0 @@ -// Serves a file with a given mime type and size at an optionally given rate. - -function getQuery(request) { - var query = {}; - request.queryString.split('&').forEach(function (val) { - var [name, value] = val.split('='); - query[name] = unescape(value); - }); - return query; -} - -function handleResponse() { - // Is this a rate limited response? - if (this.state.rate > 0) { - // Calculate how many bytes we have left to send. - var bytesToWrite = this.state.totalBytes - this.state.sentBytes; - - // Do we have any bytes left to send? If not we'll just fall thru and - // cancel our repeating timer and finalize the response. - if (bytesToWrite > 0) { - // Figure out how many bytes to send, based on the rate limit. - bytesToWrite = - (bytesToWrite > this.state.rate) ? this.state.rate : bytesToWrite; - - for (let i = 0; i < bytesToWrite; i++) { - try { - this.response.bodyOutputStream.write("0", 1); - } catch (e) { - // Connection was closed by client. - if (e == Components.results.NS_ERROR_NOT_AVAILABLE) { - // There's no harm in calling this multiple times. - this.response.finish(); - - // It's possible that our timer wasn't cancelled in time - // and we'll be called again. - if (this.timer) { - this.timer.cancel(); - this.timer = null; - } - - return; - } - } - } - - // Update the number of bytes we've sent to the client. - this.state.sentBytes += bytesToWrite; - - // Wait until the next call to do anything else. - return; - } - } - else { - // Not rate limited, write it all out. - for (let i = 0; i < this.state.totalBytes; i++) { - this.response.write("0"); - } - } - - // Finalize the response. - this.response.finish(); - - // All done sending, go ahead and cancel our repeating timer. - this.timer.cancel(); - - // Clear the timer. - this.timer = null; -} - -function handleRequest(request, response) { - var query = getQuery(request); - - // sending at a specific rate requires our response to be asynchronous so - // we handle all requests asynchronously. See handleResponse(). - response.processAsync(); - - // Default status when responding. - var version = "1.1"; - var statusCode = 200; - var description = "OK"; - - // Default values for content type, size and rate. - var contentType = "text/plain"; - var contentRange = null; - var size = 1024; - var rate = 0; - - // optional content type to be used by our response. - if ("contentType" in query) { - contentType = query["contentType"]; - } - - // optional size (in bytes) for generated file. - if ("size" in query) { - size = parseInt(query["size"]); - } - - // optional range request check. - if (request.hasHeader("range")) { - version = "1.1"; - statusCode = 206; - description = "Partial Content"; - - // We'll only support simple range byte style requests. - var [offset, total] = request.getHeader("range").slice("bytes=".length).split("-"); - // Enforce valid Number values. - offset = parseInt(offset); - offset = isNaN(offset) ? 0 : offset; - // Same. - total = parseInt(total); - total = isNaN(total) ? 0 : total; - - // We'll need to original total size as part of the Content-Range header - // value in our response. - var originalSize = size; - - // If we have a total size requested, we must make sure to send that number - // of bytes only (minus the start offset). - if (total && total < size) { - size = total - offset; - } else if (offset) { - // Looks like we just have a byte offset to deal with. - size = size - offset; - } - - // We specifically need to add a Content-Range header to all responses for - // requests that include a range request header. - contentRange = "bytes " + offset + "-" + (size - 1) + "/" + originalSize; - } - - // optional rate (in bytes/s) at which to send the file. - if ("rate" in query) { - rate = parseInt(query["rate"]); - } - - // The context for the responseHandler. - var context = { - response: response, - state: { - contentType: contentType, - totalBytes: size, - sentBytes: 0, - rate: rate - }, - timer: null - }; - - // The notify implementation for the timer. - context.notify = handleResponse.bind(context); - - context.timer = - Components.classes["@mozilla.org/timer;1"] - .createInstance(Components.interfaces.nsITimer); - - // generate the content. - response.setStatusLine(version, statusCode, description); - response.setHeader("Content-Type", contentType, false); - if (contentRange) { - response.setHeader("Content-Range", contentRange, false); - } - response.setHeader("Content-Length", size.toString(), false); - - // initialize the timer and start writing out the response. - context.timer.initWithCallback( - context, - 1000, - Components.interfaces.nsITimer.TYPE_REPEATING_SLACK - ); - -} diff --git a/dom/downloads/tests/test_downloads_bad_file.html b/dom/downloads/tests/test_downloads_bad_file.html deleted file mode 100644 index a2b3992e6..000000000 --- a/dom/downloads/tests/test_downloads_bad_file.html +++ /dev/null @@ -1,93 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=960749 ---> -<head> - <title>Test for Bug 960749 Downloads API</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=960749">Mozilla Bug 960749</a> -<p id="display"></p> -<div id="content" style="display: none"> -</div> -<a href="serve_file.sjs?contentType=application/octet-stream&size=1024" download=".<.EVIL.>\ / : * ? " |file.bin" id="download1">Download #1</a> -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> - -// Testing a simple download, waiting for it to be done. - -SimpleTest.waitForExplicitFinish(); - -var index = -1; -var expected = "_.EVIL.__ _ _ _ _ _ _file.bin"; - -function next() { - index += 1; - if (index >= steps.length) { - ok(false, "Shouldn't get here!"); - return; - } - try { - steps[index](); - } catch(ex) { - ok(false, "Caught exception", ex); - } -} - -function checkTargetFilename(download) { - ok(download.path.endsWith(expected), - "Download path leaf name '" + download.path + - "' should match '" + expected + "' filename."); - - SimpleTest.finish(); -} - -function downloadChange(evt) { - var download = evt.download; - - if (download.state === "succeeded") { - checkTargetFilename(download); - } -} - -function downloadStart(evt) { - var download = evt.download; - download.onstatechange = downloadChange; -} - -var steps = [ - // Start by setting the pref to true. - function() { - SpecialPowers.pushPrefEnv({ - set: [["dom.mozDownloads.enabled", true]] - }, next); - }, - - // Setup the event listeners. - function() { - SpecialPowers.pushPermissions([ - {type: "downloads", allow: true, context: document} - ], function() { - navigator.mozDownloadManager.ondownloadstart = downloadStart; - next(); - }); - }, - - // Click on the <a download> to start the download. - function() { - document.getElementById("download1").click(); - } -]; - -next(); - -</script> -</pre> -</body> -</html> - diff --git a/dom/downloads/tests/test_downloads_basic.html b/dom/downloads/tests/test_downloads_basic.html deleted file mode 100644 index 051a1faa1..000000000 --- a/dom/downloads/tests/test_downloads_basic.html +++ /dev/null @@ -1,128 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=938023 ---> -<head> - <title>Test for Bug 938023 Downloads API</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=938023">Mozilla Bug 938023</a> -<p id="display"></p> -<div id="content" style="display: none"> -</div> -<a href="serve_file.sjs?contentType=application/octet-stream&size=1024" download="test.bin" id="download1">Download #1</a> -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> - -// Testing a simple download, waiting for it to be done. - -SimpleTest.waitForExplicitFinish(); - -var index = -1; -var todayDate = new Date(); -var baseServeURL = "http://mochi.test:8888/tests/dom/downloads/tests/"; -var lastKnownCurrentBytes = 0; - -function next() { - index += 1; - if (index >= steps.length) { - ok(false, "Shouldn't get here!"); - return; - } - try { - steps[index](); - } catch(ex) { - ok(false, "Caught exception", ex); - } -} - -function checkConsistentDownloadAttributes(download) { - var href = document.getElementById("download1").getAttribute("href"); - var expectedServeURL = baseServeURL + href; - var destinationRegEx = /test\(?[0-9]*\)?\.bin$/; - - // bug 945323: Download path isn't honoring download attribute - ok(destinationRegEx.test(download.path), - "Download path '" + download.path + - "' should match '" + destinationRegEx + "' regexp."); - - ok(download.startTime >= todayDate, - "Download start time should be greater than or equal to today"); - - is(download.error, null, "Download does not have an error"); - - is(download.url, expectedServeURL, - "Download URL = " + expectedServeURL); - ok(download.id !== null, "Download id is defined"); - is(download.contentType, "application/octet-stream", - "Download content type is application/octet-stream"); -} - -function downloadChange(evt) { - var download = evt.download; - checkConsistentDownloadAttributes(download); - is(download.totalBytes, 1024, "Download total size is 1024 bytes"); - - if (download.state === "succeeded") { - is(download.currentBytes, 1024, "Download current size is 1024 bytes"); - SimpleTest.finish(); - } else if (download.state === "downloading") { - // Note that this case may or may not trigger, depending on whether the - // download is initially reported with 0 bytes (we should happen) or with - // 1024 bytes (we should not happen). If we do happen, an additional 8 - // TEST-PASS events should be logged. - ok(download.currentBytes > lastKnownCurrentBytes, - "Download current size is larger than last download change event"); - lastKnownCurrentBytes = download.currentBytes; - } else { - ok(false, "Unexpected download state = " + download.state); - } -} - -function downloadStart(evt) { - var download = evt.download; - checkConsistentDownloadAttributes(download); - - // We used to check that the currentBytes was 0. This was incorrect. It - // is very common to first hear about the download already at 1024 bytes. - is(download.state, "downloading", "Download state is downloading"); - - download.onstatechange = downloadChange; -} - -var steps = [ - // Start by setting the pref to true. - function() { - SpecialPowers.pushPrefEnv({ - set: [["dom.mozDownloads.enabled", true]] - }, next); - }, - - // Setup the event listeners. - function() { - SpecialPowers.pushPermissions([ - {type: "downloads", allow: true, context: document} - ], function() { - navigator.mozDownloadManager.ondownloadstart = downloadStart; - next(); - }); - }, - - // Click on the <a download> to start the download. - function() { - document.getElementById("download1").click(); - } -]; - -next(); - -</script> -</pre> -</body> -</html> - diff --git a/dom/downloads/tests/test_downloads_large.html b/dom/downloads/tests/test_downloads_large.html deleted file mode 100644 index 9f7f73c19..000000000 --- a/dom/downloads/tests/test_downloads_large.html +++ /dev/null @@ -1,110 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=938023 ---> -<head> - <title>Test for Bug 938023 Downloads API</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript" src="clear_all_done_helper.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=938023">Mozilla Bug 938023</a> -<p id="display"></p> -<div id="content" style="display: none"> -</div> -<a href="serve_file.sjs?contentType=application/octet-stream&size=102400" download="test.bin" id="download1">Large Download</a> -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> - -// Testing downloading a file, then checking getDownloads() and clearAllDone(). - -SimpleTest.waitForExplicitFinish(); - -var index = -1; - -function next(args) { - index += 1; - if (index >= steps.length) { - ok(false, "Shouldn't get here!"); - return; - } - try { - steps[index](args); - } catch(ex) { - ok(false, "Caught exception", ex); - } -} - -// Catch all error function. -function error() { - ok(false, "API failure"); - SimpleTest.finish(); -} - -function getDownloads(downloads) { - ok(downloads.length == 1, "One downloads after getDownloads"); - clearAllDoneHelper(true).then(clearAllDone, error); -} - -function clearAllDone(downloads) { - ok(downloads.length == 0, "No downloads after clearAllDone"); - SimpleTest.finish(); -} - -function downloadChange(evt) { - var download = evt.download; - - if (download.state == "succeeded") { - ok(download.totalBytes == 102400, "Download size is 100k bytes."); - navigator.mozDownloadManager.getDownloads().then(getDownloads, error); - } -} - -var steps = [ - // Start by setting the pref to true. - function() { - SpecialPowers.pushPrefEnv({ - set: [["dom.mozDownloads.enabled", true]] - }, next); - }, - - // Setup permission and clear current list. - function() { - SpecialPowers.pushPermissions([ - {type: "downloads", allow: true, context: document} - ], function() { - clearAllDoneHelper(true).then(next, error); - }); - }, - - function(downloads) { - ok(downloads.length == 0, "Start with an empty download list."); - next(); - }, - - // Setup the event listeners. - function() { - navigator.mozDownloadManager.ondownloadstart = - function(evt) { - ok(true, "Download started"); - evt.download.addEventListener("statechange", downloadChange); - } - next(); - }, - - // Click on the <a download> to start the download. - function() { - document.getElementById("download1").click(); - } -]; - -next(); - -</script> -</pre> -</body> -</html> diff --git a/dom/downloads/tests/test_downloads_navigator_object.html b/dom/downloads/tests/test_downloads_navigator_object.html deleted file mode 100644 index 1c38388b7..000000000 --- a/dom/downloads/tests/test_downloads_navigator_object.html +++ /dev/null @@ -1,75 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=938023 ---> -<head> - <title>Test for Bug 938023 Downloads API</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=938023">Mozilla Bug 938023</a> -<p id="display"></p> -<div id="content" style="display: none"> -<iframe></iframe> -</div> -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> - -SimpleTest.waitForExplicitFinish(); - -var index = -1; - -function next() { - index += 1; - if (index >= steps.length) { - ok(false, "Shouldn't get here!"); - return; - } - try { - steps[index](); - } catch(ex) { - ok(false, "Caught exception", ex); - } -} - -var steps = [ - // Start by setting the pref to true. - function() { - SpecialPowers.pushPrefEnv({ - set: [["dom.mozDownloads.enabled", true]] - }, next); - }, - - function() { - SpecialPowers.pushPermissions([ - {type: "downloads", allow: 0, context: document} - ], function() { - is(frames[0].navigator.mozDownloadManager, null, "navigator.mozDownloadManager is null when the page doesn't have permissions"); - next(); - }); - }, - - function() { - SpecialPowers.pushPrefEnv({ - set: [["dom.mozDownloads.enabled", false]] - }, function() { - is(navigator.mozDownloadManager, undefined, "navigator.mozDownloadManager is undefined"); - next(); - }); - }, - - function() { - SimpleTest.finish(); - } -]; - -next(); - -</script> -</pre> -</body> -</html> diff --git a/dom/downloads/tests/test_downloads_pause_remove.html b/dom/downloads/tests/test_downloads_pause_remove.html deleted file mode 100644 index 3b410a667..000000000 --- a/dom/downloads/tests/test_downloads_pause_remove.html +++ /dev/null @@ -1,117 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=938023 ---> -<head> - <title>Test for Bug 938023 Downloads API</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript" src="clear_all_done_helper.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=938023">Mozilla Bug 938023</a> -<p id="display"></p> -<div id="content" style="display: none"> -</div> -<a href="serve_file.sjs?contentType=application/octet-stream&size=102400&rate=1024" download="test.bin" id="download1">Large Download</a> -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> - -// Testing pausing a download and then removing it. - -SimpleTest.waitForExplicitFinish(); - -var index = -1; - -function next(args) { - index += 1; - if (index >= steps.length) { - ok(false, "Shouldn't get here!"); - return; - } - try { - steps[index](args); - } catch(ex) { - ok(false, "Caught exception", ex); - } -} - -var pausing = false; - -// Catch all error function. -function error() { - ok(false, "API failure"); - SimpleTest.finish(); -} - -function checkDownloadList(downloads) { - ok(downloads.length == 0, "No downloads left"); - SimpleTest.finish(); -} - -function checkRemoved(download) { - ok(download.state == "finalized", "Download removed."); - navigator.mozDownloadManager.getDownloads() - .then(checkDownloadList, error); -} - -function downloadChange(evt) { - var download = evt.download; - - if (download.state == "downloading" && !pausing) { - pausing = true; - download.pause(); - } else if (download.state == "stopped") { - ok(pausing, "Download stopped by pause()"); - navigator.mozDownloadManager.remove(download) - .then(checkRemoved, error); - } -} - -var steps = [ - // Start by setting the pref to true. - function() { - SpecialPowers.pushPrefEnv({ - set: [["dom.mozDownloads.enabled", true]] - }, next); - }, - - // Setup permission and clear current list. - function() { - SpecialPowers.pushPermissions([ - {type: "downloads", allow: true, context: document} - ], function() { - clearAllDoneHelper(true).then(next, error); - }); - }, - - function(downloads) { - ok(downloads.length == 0, "Start with an empty download list."); - next(); - }, - - // Setup the event listeners. - function() { - navigator.mozDownloadManager.ondownloadstart = - function(evt) { - ok(true, "Download started"); - evt.download.addEventListener("statechange", downloadChange); - } - next(); - }, - - // Click on the <a download> to start the download. - function() { - document.getElementById("download1").click(); - } -]; - -next(); - -</script> -</pre> -</body> -</html> diff --git a/dom/downloads/tests/test_downloads_pause_resume.html b/dom/downloads/tests/test_downloads_pause_resume.html deleted file mode 100644 index 76e249e5a..000000000 --- a/dom/downloads/tests/test_downloads_pause_resume.html +++ /dev/null @@ -1,121 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=938023 ---> -<head> - <title>Test for Bug 938023 Downloads API</title> - <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript" src="clear_all_done_helper.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=938023">Mozilla Bug 938023</a> -<p id="display"></p> -<div id="content" style="display: none"> -</div> -<a href="serve_file.sjs?contentType=application/octet-stream&size=102400&rate=1024" download="test.bin" id="download1">Large Download</a> -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> - -// Testing pausing a download and then resuming it. - -SimpleTest.waitForExplicitFinish(); - -var index = -1; - -function next(args) { - index += 1; - if (index >= steps.length) { - ok(false, "Shouldn't get here!"); - return; - } - try { - steps[index](args); - } catch(ex) { - ok(false, "Caught exception", ex); - } -} - -var pausing = false; -var resuming = false; - -// Catch all error function. -function error() { - ok(false, "API failure"); - SimpleTest.finish(); -} - -function checkDownloadList(downloads) { - ok(downloads.length == 0, "No downloads left"); - SimpleTest.finish(); -} - -function checkResumeSucceeded(download) { - ok(download.state == "succeeded", "Download resumed successfully."); - clearAllDoneHelper(true).then(checkDownloadList, error); -} - -function downloadChange(evt) { - var download = evt.download; - - info("got download event, state: " + download.state + - " current bytes: " + download.currentBytes + - " pausing?: " + pausing + " resuming?: " + resuming); - if (download.state == "downloading" && !pausing) { - pausing = true; - download.pause(); - } else if (download.state == "stopped" && !resuming) { - resuming = true; - ok(pausing, "Download stopped by pause()"); - download.resume() - .then(function() { checkResumeSucceeded(download); }, error); - } -} - -var steps = [ - // Start by setting the pref to true. - function() { - SpecialPowers.pushPrefEnv({ - set: [["dom.mozDownloads.enabled", true]] - }, next); - }, - - // Setup permission and clear current list. - function() { - SpecialPowers.pushPermissions([ - {type: "downloads", allow: true, context: document} - ], function() { - clearAllDoneHelper(true).then(next, error); - }); - }, - - function(downloads) { - ok(downloads.length == 0, "Start with an empty download list."); - next(); - }, - - // Setup the event listeners. - function() { - navigator.mozDownloadManager.ondownloadstart = - function(evt) { - ok(true, "Download started"); - evt.download.addEventListener("statechange", downloadChange); - } - next(); - }, - - // Click on the <a download> to start the download. - function() { - document.getElementById("download1").click(); - } -]; - -next(); - -</script> -</pre> -</body> -</html> |