mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to inbound.
This commit is contained in:
commit
2ca4d83ee9
@ -728,18 +728,6 @@ const gFormSubmitObserver = {
|
|||||||
|
|
||||||
var gBrowserInit = {
|
var gBrowserInit = {
|
||||||
onLoad: function() {
|
onLoad: function() {
|
||||||
// window.arguments[0]: URI to load (string), or an nsISupportsArray of
|
|
||||||
// nsISupportsStrings to load, or a xul:tab of
|
|
||||||
// a tabbrowser, which will be replaced by this
|
|
||||||
// window (for this case, all other arguments are
|
|
||||||
// ignored).
|
|
||||||
// [1]: character set (string)
|
|
||||||
// [2]: referrer (nsIURI)
|
|
||||||
// [3]: postData (nsIInputStream)
|
|
||||||
// [4]: allowThirdPartyFixup (bool)
|
|
||||||
if ("arguments" in window && window.arguments[0])
|
|
||||||
var uriToLoad = window.arguments[0];
|
|
||||||
|
|
||||||
gMultiProcessBrowser = gPrefService.getBoolPref("browser.tabs.remote");
|
gMultiProcessBrowser = gPrefService.getBoolPref("browser.tabs.remote");
|
||||||
|
|
||||||
var mustLoadSidebar = false;
|
var mustLoadSidebar = false;
|
||||||
@ -780,6 +768,7 @@ var gBrowserInit = {
|
|||||||
new nsBrowserAccess();
|
new nsBrowserAccess();
|
||||||
|
|
||||||
// set default character set if provided
|
// set default character set if provided
|
||||||
|
// window.arguments[1]: character set (string)
|
||||||
if ("arguments" in window && window.arguments.length > 1 && window.arguments[1]) {
|
if ("arguments" in window && window.arguments.length > 1 && window.arguments[1]) {
|
||||||
if (window.arguments[1].startsWith("charset=")) {
|
if (window.arguments[1].startsWith("charset=")) {
|
||||||
var arrayArgComponents = window.arguments[1].split("=");
|
var arrayArgComponents = window.arguments[1].split("=");
|
||||||
@ -946,7 +935,7 @@ var gBrowserInit = {
|
|||||||
retrieveToolbarIconsizesFromTheme();
|
retrieveToolbarIconsizesFromTheme();
|
||||||
|
|
||||||
// Wait until chrome is painted before executing code not critical to making the window visible
|
// Wait until chrome is painted before executing code not critical to making the window visible
|
||||||
this._boundDelayedStartup = this._delayedStartup.bind(this, uriToLoad, mustLoadSidebar);
|
this._boundDelayedStartup = this._delayedStartup.bind(this, mustLoadSidebar);
|
||||||
window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
|
window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
|
||||||
|
|
||||||
this._loadHandled = true;
|
this._loadHandled = true;
|
||||||
@ -957,7 +946,7 @@ var gBrowserInit = {
|
|||||||
this._boundDelayedStartup = null;
|
this._boundDelayedStartup = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
_delayedStartup: function(uriToLoad, mustLoadSidebar) {
|
_delayedStartup: function(mustLoadSidebar) {
|
||||||
let tmp = {};
|
let tmp = {};
|
||||||
Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", tmp);
|
Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", tmp);
|
||||||
let TelemetryTimestamps = tmp.TelemetryTimestamps;
|
let TelemetryTimestamps = tmp.TelemetryTimestamps;
|
||||||
@ -976,6 +965,7 @@ var gBrowserInit = {
|
|||||||
socialBrowser.addEventListener("MozApplicationManifest",
|
socialBrowser.addEventListener("MozApplicationManifest",
|
||||||
OfflineApps, false);
|
OfflineApps, false);
|
||||||
|
|
||||||
|
let uriToLoad = this._getUriToLoad();
|
||||||
var isLoadingBlank = isBlankPageURL(uriToLoad);
|
var isLoadingBlank = isBlankPageURL(uriToLoad);
|
||||||
|
|
||||||
// This pageshow listener needs to be registered before we may call
|
// This pageshow listener needs to be registered before we may call
|
||||||
@ -1012,6 +1002,9 @@ var gBrowserInit = {
|
|||||||
|
|
||||||
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);
|
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);
|
||||||
}
|
}
|
||||||
|
// window.arguments[2]: referrer (nsIURI)
|
||||||
|
// [3]: postData (nsIInputStream)
|
||||||
|
// [4]: allowThirdPartyFixup (bool)
|
||||||
else if (window.arguments.length >= 3) {
|
else if (window.arguments.length >= 3) {
|
||||||
loadURI(uriToLoad, window.arguments[2], window.arguments[3] || null,
|
loadURI(uriToLoad, window.arguments[2], window.arguments[3] || null,
|
||||||
window.arguments[4] || false);
|
window.arguments[4] || false);
|
||||||
@ -1293,6 +1286,31 @@ var gBrowserInit = {
|
|||||||
TelemetryTimestamps.add("delayedStartupFinished");
|
TelemetryTimestamps.add("delayedStartupFinished");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Returns the URI(s) to load at startup.
|
||||||
|
_getUriToLoad: function () {
|
||||||
|
// window.arguments[0]: URI to load (string), or an nsISupportsArray of
|
||||||
|
// nsISupportsStrings to load, or a xul:tab of
|
||||||
|
// a tabbrowser, which will be replaced by this
|
||||||
|
// window (for this case, all other arguments are
|
||||||
|
// ignored).
|
||||||
|
if (!window.arguments || !window.arguments[0])
|
||||||
|
return null;
|
||||||
|
|
||||||
|
let uri = window.arguments[0];
|
||||||
|
let sessionStartup = Cc["@mozilla.org/browser/sessionstartup;1"]
|
||||||
|
.getService(Ci.nsISessionStartup);
|
||||||
|
let defaultArgs = Cc["@mozilla.org/browser/clh;1"]
|
||||||
|
.getService(Ci.nsIBrowserHandler)
|
||||||
|
.defaultArgs;
|
||||||
|
|
||||||
|
// If the given URI matches defaultArgs (the default homepage) we want
|
||||||
|
// to block its load if we're going to restore a session anyway.
|
||||||
|
if (uri == defaultArgs && sessionStartup.willOverrideHomepage)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
},
|
||||||
|
|
||||||
onUnload: function() {
|
onUnload: function() {
|
||||||
// In certain scenarios it's possible for unload to be fired before onload,
|
// In certain scenarios it's possible for unload to be fired before onload,
|
||||||
// (e.g. if the window is being closed after browser.js loads but before the
|
// (e.g. if the window is being closed after browser.js loads but before the
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* - and allows to restore everything into one window.
|
* - and allows to restore everything into one window.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[scriptable, uuid(35235b39-7098-4b3b-8e28-cd004a88b06f)]
|
[scriptable, uuid(51f4b9f0-f3d2-11e2-bb62-2c24dd830245)]
|
||||||
interface nsISessionStartup: nsISupports
|
interface nsISessionStartup: nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -23,10 +23,24 @@ interface nsISessionStartup: nsISupports
|
|||||||
readonly attribute jsval state;
|
readonly attribute jsval state;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if session should be restored
|
* Determines whether there is a pending session restore and makes sure that
|
||||||
|
* we're initialized before returning. If we're not yet this will read the
|
||||||
|
* session file synchronously.
|
||||||
*/
|
*/
|
||||||
boolean doRestore();
|
boolean doRestore();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether we will restore a session that ends up replacing the
|
||||||
|
* homepage. The browser uses this to not start loading the homepage if
|
||||||
|
* we're going to stop its load anyway shortly after.
|
||||||
|
*
|
||||||
|
* This is meant to be an optimization for the average case that loading the
|
||||||
|
* session file finishes before we may want to start loading the default
|
||||||
|
* homepage. Should this be called before the session file has been read it
|
||||||
|
* will just return false.
|
||||||
|
*/
|
||||||
|
readonly attribute bool willOverrideHomepage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What type of session we're restoring.
|
* What type of session we're restoring.
|
||||||
* NO_SESSION There is no data available from the previous session
|
* NO_SESSION There is no data available from the previous session
|
||||||
|
@ -162,15 +162,6 @@ SessionStartup.prototype = {
|
|||||||
else
|
else
|
||||||
this._initialState = null; // reset the state
|
this._initialState = null; // reset the state
|
||||||
|
|
||||||
// wait for the first browser window to open
|
|
||||||
// Don't reset the initial window's default args (i.e. the home page(s))
|
|
||||||
// if all stored tabs are pinned.
|
|
||||||
if (this.doRestore() &&
|
|
||||||
(!this._initialState.windows ||
|
|
||||||
!this._initialState.windows.every(function (win)
|
|
||||||
win.tabs.every(function (tab) tab.pinned))))
|
|
||||||
Services.obs.addObserver(this, "domwindowopened", true);
|
|
||||||
|
|
||||||
Services.obs.addObserver(this, "sessionstore-windows-restored", true);
|
Services.obs.addObserver(this, "sessionstore-windows-restored", true);
|
||||||
|
|
||||||
if (this._sessionType != Ci.nsISessionStartup.NO_SESSION)
|
if (this._sessionType != Ci.nsISessionStartup.NO_SESSION)
|
||||||
@ -204,14 +195,6 @@ SessionStartup.prototype = {
|
|||||||
if (this._sessionType != Ci.nsISessionStartup.NO_SESSION)
|
if (this._sessionType != Ci.nsISessionStartup.NO_SESSION)
|
||||||
Services.obs.removeObserver(this, "browser:purge-session-history");
|
Services.obs.removeObserver(this, "browser:purge-session-history");
|
||||||
break;
|
break;
|
||||||
case "domwindowopened":
|
|
||||||
var window = aSubject;
|
|
||||||
var self = this;
|
|
||||||
window.addEventListener("load", function() {
|
|
||||||
self._onWindowOpened(window);
|
|
||||||
window.removeEventListener("load", arguments.callee, false);
|
|
||||||
}, false);
|
|
||||||
break;
|
|
||||||
case "sessionstore-windows-restored":
|
case "sessionstore-windows-restored":
|
||||||
Services.obs.removeObserver(this, "sessionstore-windows-restored");
|
Services.obs.removeObserver(this, "sessionstore-windows-restored");
|
||||||
// free _initialState after nsSessionStore is done with it
|
// free _initialState after nsSessionStore is done with it
|
||||||
@ -225,43 +208,6 @@ SessionStartup.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the default arguments from the first browser window
|
|
||||||
* (and removes the "domwindowopened" observer afterwards).
|
|
||||||
*/
|
|
||||||
_onWindowOpened: function sss_onWindowOpened(aWindow) {
|
|
||||||
var wType = aWindow.document.documentElement.getAttribute("windowtype");
|
|
||||||
if (wType != "navigator:browser")
|
|
||||||
return;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: this relies on the fact that nsBrowserContentHandler will return
|
|
||||||
* a different value the first time its getter is called after an update,
|
|
||||||
* due to its needHomePageOverride() logic. We don't want to remove the
|
|
||||||
* default arguments in the update case, since they include the "What's
|
|
||||||
* New" page.
|
|
||||||
*
|
|
||||||
* Since we're garanteed to be at least the second caller of defaultArgs
|
|
||||||
* (nsBrowserContentHandler calls it to determine which arguments to pass
|
|
||||||
* at startup), we know that if the window's arguments don't match the
|
|
||||||
* current defaultArguments, we're either in the update case, or we're
|
|
||||||
* launching a non-default browser window, so we shouldn't remove the
|
|
||||||
* window's arguments.
|
|
||||||
*/
|
|
||||||
var defaultArgs = Cc["@mozilla.org/browser/clh;1"].
|
|
||||||
getService(Ci.nsIBrowserHandler).defaultArgs;
|
|
||||||
if (aWindow.arguments && aWindow.arguments[0] &&
|
|
||||||
aWindow.arguments[0] == defaultArgs)
|
|
||||||
aWindow.arguments[0] = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Services.obs.removeObserver(this, "domwindowopened");
|
|
||||||
} catch (e) {
|
|
||||||
// This might throw if we're removing the observer multiple times,
|
|
||||||
// but this is safe to ignore.
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ........ Public API ................*/
|
/* ........ Public API ................*/
|
||||||
|
|
||||||
get onceInitialized() {
|
get onceInitialized() {
|
||||||
@ -277,15 +223,47 @@ SessionStartup.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether there is a pending session restore.
|
* Determines whether there is a pending session restore and makes sure that
|
||||||
|
* we're initialized before returning. If we're not yet this will read the
|
||||||
|
* session file synchronously.
|
||||||
* @returns bool
|
* @returns bool
|
||||||
*/
|
*/
|
||||||
doRestore: function sss_doRestore() {
|
doRestore: function sss_doRestore() {
|
||||||
this._ensureInitialized();
|
this._ensureInitialized();
|
||||||
|
return this._willRestore();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether there is a pending session restore.
|
||||||
|
* @returns bool
|
||||||
|
*/
|
||||||
|
_willRestore: function () {
|
||||||
return this._sessionType == Ci.nsISessionStartup.RECOVER_SESSION ||
|
return this._sessionType == Ci.nsISessionStartup.RECOVER_SESSION ||
|
||||||
this._sessionType == Ci.nsISessionStartup.RESUME_SESSION;
|
this._sessionType == Ci.nsISessionStartup.RESUME_SESSION;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether we will restore a session that ends up replacing the
|
||||||
|
* homepage. The browser uses this to not start loading the homepage if
|
||||||
|
* we're going to stop its load anyway shortly after.
|
||||||
|
*
|
||||||
|
* This is meant to be an optimization for the average case that loading the
|
||||||
|
* session file finishes before we may want to start loading the default
|
||||||
|
* homepage. Should this be called before the session file has been read it
|
||||||
|
* will just return false.
|
||||||
|
*
|
||||||
|
* @returns bool
|
||||||
|
*/
|
||||||
|
get willOverrideHomepage() {
|
||||||
|
if (this._initialState && this._willRestore()) {
|
||||||
|
let windows = this._initialState.windows || null;
|
||||||
|
// If there are valid windows with not only pinned tabs, signal that we
|
||||||
|
// will override the default homepage by restoring a session.
|
||||||
|
return windows && windows.some(w => w.tabs.some(t => !t.pinned));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the type of pending session store, if any.
|
* Get the type of pending session store, if any.
|
||||||
*/
|
*/
|
||||||
|
@ -18,7 +18,7 @@ const DEFAULT_UA = Cc["@mozilla.org/network/protocol;1?name=http"]
|
|||||||
const MAX_OVERRIDE_FOR_HOST_CACHE_SIZE = 250;
|
const MAX_OVERRIDE_FOR_HOST_CACHE_SIZE = 250;
|
||||||
|
|
||||||
var gPrefBranch;
|
var gPrefBranch;
|
||||||
var gOverrides;
|
var gOverrides = new Map;
|
||||||
var gOverrideForHostCache = new Map;
|
var gOverrideForHostCache = new Map;
|
||||||
var gInitialized = false;
|
var gInitialized = false;
|
||||||
var gOverrideFunctions = [
|
var gOverrideFunctions = [
|
||||||
@ -63,10 +63,10 @@ this.UserAgentOverrides = {
|
|||||||
|
|
||||||
override = null;
|
override = null;
|
||||||
|
|
||||||
for (let domain in gOverrides) {
|
for (let [domain, userAgent] of gOverrides) {
|
||||||
if (host == domain ||
|
if (host == domain ||
|
||||||
host.endsWith("." + domain)) {
|
host.endsWith("." + domain)) {
|
||||||
override = gOverrides[domain];
|
override = userAgent;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,23 +93,30 @@ this.UserAgentOverrides = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function buildOverrides() {
|
function buildOverrides() {
|
||||||
gOverrides = {};
|
gOverrides.clear();
|
||||||
gOverrideForHostCache.clear();
|
gOverrideForHostCache.clear();
|
||||||
|
|
||||||
if (!Services.prefs.getBoolPref(PREF_OVERRIDES_ENABLED))
|
if (!Services.prefs.getBoolPref(PREF_OVERRIDES_ENABLED))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
let builtUAs = new Map;
|
||||||
let domains = gPrefBranch.getChildList("");
|
let domains = gPrefBranch.getChildList("");
|
||||||
|
|
||||||
for (let domain of domains) {
|
for (let domain of domains) {
|
||||||
let override = gPrefBranch.getCharPref(domain);
|
let override = gPrefBranch.getCharPref(domain);
|
||||||
|
let userAgent = builtUAs.get(override);
|
||||||
|
|
||||||
let [search, replace] = override.split("#", 2);
|
if (userAgent === undefined) {
|
||||||
if (search && replace) {
|
let [search, replace] = override.split("#", 2);
|
||||||
gOverrides[domain] = DEFAULT_UA.replace(new RegExp(search, "g"), replace);
|
if (search && replace) {
|
||||||
} else {
|
userAgent = DEFAULT_UA.replace(new RegExp(search, "g"), replace);
|
||||||
gOverrides[domain] = override;
|
} else {
|
||||||
|
userAgent = override;
|
||||||
|
}
|
||||||
|
builtUAs.set(override, userAgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gOverrides.set(domain, userAgent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadIntegration",
|
XPCOMUtils.defineLazyModuleGetter(this, "DownloadIntegration",
|
||||||
"resource://gre/modules/DownloadIntegration.jsm");
|
"resource://gre/modules/DownloadIntegration.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||||
|
"resource://gre/modules/FileUtils.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||||
"resource://gre/modules/NetUtil.jsm");
|
"resource://gre/modules/NetUtil.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||||
@ -69,6 +71,15 @@ const BackgroundFileSaverStreamListener = Components.Constructor(
|
|||||||
"@mozilla.org/network/background-file-saver;1?mode=streamlistener",
|
"@mozilla.org/network/background-file-saver;1?mode=streamlistener",
|
||||||
"nsIBackgroundFileSaver");
|
"nsIBackgroundFileSaver");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given value is a primitive string or a String object.
|
||||||
|
*/
|
||||||
|
function isString(aValue) {
|
||||||
|
// We cannot use the "instanceof" operator reliably across module boundaries.
|
||||||
|
return (typeof aValue == "string") ||
|
||||||
|
(typeof aValue == "object" && "charAt" in aValue);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Download
|
//// Download
|
||||||
|
|
||||||
@ -422,6 +433,71 @@ Download.prototype = {
|
|||||||
}
|
}
|
||||||
this._notifyChange();
|
this._notifyChange();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a static representation of the current object state.
|
||||||
|
*
|
||||||
|
* @return A JavaScript object that can be serialized to JSON.
|
||||||
|
*/
|
||||||
|
toSerializable: function ()
|
||||||
|
{
|
||||||
|
let serializable = {
|
||||||
|
source: this.source.toSerializable(),
|
||||||
|
target: this.target.toSerializable(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simplify the representation for the most common saver type. If the saver
|
||||||
|
// is an object instead of a simple string, we can't simplify it because we
|
||||||
|
// need to persist all its properties, not only "type". This may happen for
|
||||||
|
// savers of type "copy" as well as other types.
|
||||||
|
let saver = this.saver.toSerializable();
|
||||||
|
if (saver !== "copy") {
|
||||||
|
serializable.saver = saver;
|
||||||
|
}
|
||||||
|
|
||||||
|
return serializable;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Download object from a serializable representation. This
|
||||||
|
* function is used by the createDownload method of Downloads.jsm when a new
|
||||||
|
* Download object is requested, thus some properties may refer to live objects
|
||||||
|
* in place of their serializable representations.
|
||||||
|
*
|
||||||
|
* @param aSerializable
|
||||||
|
* An object with the following fields:
|
||||||
|
* {
|
||||||
|
* source: DownloadSource object, or its serializable representation.
|
||||||
|
* See DownloadSource.fromSerializable for details.
|
||||||
|
* target: DownloadTarget object, or its serializable representation.
|
||||||
|
* See DownloadTarget.fromSerializable for details.
|
||||||
|
* saver: Serializable representation of a DownloadSaver object. See
|
||||||
|
* DownloadSaver.fromSerializable for details. If omitted,
|
||||||
|
* defaults to "copy".
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @return The newly created Download object.
|
||||||
|
*/
|
||||||
|
Download.fromSerializable = function (aSerializable) {
|
||||||
|
let download = new Download();
|
||||||
|
if (aSerializable.source instanceof DownloadSource) {
|
||||||
|
download.source = aSerializable.source;
|
||||||
|
} else {
|
||||||
|
download.source = DownloadSource.fromSerializable(aSerializable.source);
|
||||||
|
}
|
||||||
|
if (aSerializable.target instanceof DownloadTarget) {
|
||||||
|
download.target = aSerializable.target;
|
||||||
|
} else {
|
||||||
|
download.target = DownloadTarget.fromSerializable(aSerializable.target);
|
||||||
|
}
|
||||||
|
if ("saver" in aSerializable) {
|
||||||
|
download.saver = DownloadSaver.fromSerializable(aSerializable.saver);
|
||||||
|
} else {
|
||||||
|
download.saver = DownloadSaver.fromSerializable("copy");
|
||||||
|
}
|
||||||
|
download.saver.download = download;
|
||||||
|
return download;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -434,20 +510,20 @@ function DownloadSource() { }
|
|||||||
|
|
||||||
DownloadSource.prototype = {
|
DownloadSource.prototype = {
|
||||||
/**
|
/**
|
||||||
* The nsIURI for the download source.
|
* String containing the URI for the download source.
|
||||||
*/
|
*/
|
||||||
uri: null,
|
url: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether the download originated from a private window. This
|
* Indicates whether the download originated from a private window. This
|
||||||
* determines the context of the network request that is made to retrieve the
|
* determines the context of the network request that is made to retrieve the
|
||||||
* resource.
|
* resource.
|
||||||
*/
|
*/
|
||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The nsIURI for the referrer of the download source, or null if no referrer
|
* String containing the referrer URI of the download source, or null if no
|
||||||
* should be sent or the download source is not HTTP.
|
* referrer should be sent or the download source is not HTTP.
|
||||||
*/
|
*/
|
||||||
referrer: null,
|
referrer: null,
|
||||||
|
|
||||||
@ -456,19 +532,60 @@ DownloadSource.prototype = {
|
|||||||
*
|
*
|
||||||
* @return A JavaScript object that can be serialized to JSON.
|
* @return A JavaScript object that can be serialized to JSON.
|
||||||
*/
|
*/
|
||||||
serialize: function DS_serialize()
|
toSerializable: function ()
|
||||||
{
|
{
|
||||||
let serialized = { uri: this.uri.spec };
|
// Simplify the representation if we don't have other details.
|
||||||
|
if (!this.isPrivate && !this.referrer) {
|
||||||
|
return this.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
let serializable = { url: this.url };
|
||||||
if (this.isPrivate) {
|
if (this.isPrivate) {
|
||||||
serialized.isPrivate = true;
|
serializable.isPrivate = true;
|
||||||
}
|
}
|
||||||
if (this.referrer) {
|
if (this.referrer) {
|
||||||
serialized.referrer = this.referrer.spec;
|
serializable.referrer = this.referrer;
|
||||||
}
|
}
|
||||||
return serialized;
|
return serializable;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DownloadSource object from its serializable representation.
|
||||||
|
*
|
||||||
|
* @param aSerializable
|
||||||
|
* Serializable representation of a DownloadSource object. This may be a
|
||||||
|
* string containing the URI for the download source, an nsIURI, or an
|
||||||
|
* object with the following properties:
|
||||||
|
* {
|
||||||
|
* url: String containing the URI for the download source.
|
||||||
|
* isPrivate: Indicates whether the download originated from a private
|
||||||
|
* window. If omitted, the download is public.
|
||||||
|
* referrer: String containing the referrer URI of the download source.
|
||||||
|
* Can be omitted or null if no referrer should be sent or
|
||||||
|
* the download source is not HTTP.
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @return The newly created DownloadSource object.
|
||||||
|
*/
|
||||||
|
DownloadSource.fromSerializable = function (aSerializable) {
|
||||||
|
let source = new DownloadSource();
|
||||||
|
if (isString(aSerializable)) {
|
||||||
|
source.url = aSerializable;
|
||||||
|
} else if (aSerializable instanceof Ci.nsIURI) {
|
||||||
|
source.url = aSerializable.spec;
|
||||||
|
} else {
|
||||||
|
source.url = aSerializable.url;
|
||||||
|
if ("isPrivate" in aSerializable) {
|
||||||
|
source.isPrivate = aSerializable.isPrivate;
|
||||||
|
}
|
||||||
|
if ("referrer" in aSerializable) {
|
||||||
|
source.referrer = aSerializable.referrer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// DownloadTarget
|
//// DownloadTarget
|
||||||
|
|
||||||
@ -480,21 +597,50 @@ function DownloadTarget() { }
|
|||||||
|
|
||||||
DownloadTarget.prototype = {
|
DownloadTarget.prototype = {
|
||||||
/**
|
/**
|
||||||
* The nsIFile for the download target.
|
* String containing the path of the target file.
|
||||||
*/
|
*/
|
||||||
file: null,
|
path: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a static representation of the current object state.
|
* Returns a static representation of the current object state.
|
||||||
*
|
*
|
||||||
* @return A JavaScript object that can be serialized to JSON.
|
* @return A JavaScript object that can be serialized to JSON.
|
||||||
*/
|
*/
|
||||||
serialize: function DT_serialize()
|
toSerializable: function ()
|
||||||
{
|
{
|
||||||
return { file: this.file.path };
|
// Simplify the representation since we don't have other details for now.
|
||||||
|
return this.path;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DownloadTarget object from its serializable representation.
|
||||||
|
*
|
||||||
|
* @param aSerializable
|
||||||
|
* Serializable representation of a DownloadTarget object. This may be a
|
||||||
|
* string containing the path of the target file, an nsIFile, or an
|
||||||
|
* object with the following properties:
|
||||||
|
* {
|
||||||
|
* path: String containing the path of the target file.
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @return The newly created DownloadTarget object.
|
||||||
|
*/
|
||||||
|
DownloadTarget.fromSerializable = function (aSerializable) {
|
||||||
|
let target = new DownloadTarget();
|
||||||
|
if (isString(aSerializable)) {
|
||||||
|
target.path = aSerializable;
|
||||||
|
} else if (aSerializable instanceof Ci.nsIFile) {
|
||||||
|
// Read the "path" property of nsIFile after checking the object type.
|
||||||
|
target.path = aSerializable.path;
|
||||||
|
} else {
|
||||||
|
// Read the "path" property of the serializable DownloadTarget
|
||||||
|
// representation.
|
||||||
|
target.path = aSerializable.path;
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// DownloadError
|
//// DownloadError
|
||||||
|
|
||||||
@ -610,12 +756,39 @@ DownloadSaver.prototype = {
|
|||||||
*
|
*
|
||||||
* @return A JavaScript object that can be serialized to JSON.
|
* @return A JavaScript object that can be serialized to JSON.
|
||||||
*/
|
*/
|
||||||
serialize: function DS_serialize()
|
toSerializable: function ()
|
||||||
{
|
{
|
||||||
throw new Error("Not implemented.");
|
throw new Error("Not implemented.");
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DownloadSaver object from its serializable representation.
|
||||||
|
*
|
||||||
|
* @param aSerializable
|
||||||
|
* Serializable representation of a DownloadSaver object. If no initial
|
||||||
|
* state information for the saver object is needed, can be a string
|
||||||
|
* representing the class of the download operation, for example "copy".
|
||||||
|
*
|
||||||
|
* @return The newly created DownloadSaver object.
|
||||||
|
*/
|
||||||
|
DownloadSaver.fromSerializable = function (aSerializable) {
|
||||||
|
let serializable = isString(aSerializable) ? { type: aSerializable }
|
||||||
|
: aSerializable;
|
||||||
|
let saver;
|
||||||
|
switch (serializable.type) {
|
||||||
|
case "copy":
|
||||||
|
saver = DownloadCopySaver.fromSerializable(serializable);
|
||||||
|
break;
|
||||||
|
case "legacy":
|
||||||
|
saver = DownloadLegacySaver.fromSerializable(serializable);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Unrecoginzed download saver type.");
|
||||||
|
}
|
||||||
|
return saver;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// DownloadCopySaver
|
//// DownloadCopySaver
|
||||||
|
|
||||||
@ -665,15 +838,16 @@ DownloadCopySaver.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Set the target file, that will be deleted if the download fails.
|
// Set the target file, that will be deleted if the download fails.
|
||||||
backgroundFileSaver.setTarget(download.target.file, false);
|
backgroundFileSaver.setTarget(new FileUtils.File(download.target.path),
|
||||||
|
false);
|
||||||
|
|
||||||
// Create a channel from the source, and listen to progress notifications.
|
// Create a channel from the source, and listen to progress notifications.
|
||||||
let channel = NetUtil.newChannel(download.source.uri);
|
let channel = NetUtil.newChannel(NetUtil.newURI(download.source.url));
|
||||||
if (channel instanceof Ci.nsIPrivateBrowsingChannel) {
|
if (channel instanceof Ci.nsIPrivateBrowsingChannel) {
|
||||||
channel.setPrivate(download.source.isPrivate);
|
channel.setPrivate(download.source.isPrivate);
|
||||||
}
|
}
|
||||||
if (channel instanceof Ci.nsIHttpChannel) {
|
if (channel instanceof Ci.nsIHttpChannel && download.source.referrer) {
|
||||||
channel.referrer = download.source.referrer;
|
channel.referrer = NetUtil.newURI(download.source.referrer);
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.notificationCallbacks = {
|
channel.notificationCallbacks = {
|
||||||
@ -747,14 +921,29 @@ DownloadCopySaver.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements "DownloadSaver.serialize".
|
* Implements "DownloadSaver.toSerializable".
|
||||||
*/
|
*/
|
||||||
serialize: function DCS_serialize()
|
toSerializable: function ()
|
||||||
{
|
{
|
||||||
return { type: "copy" };
|
// Simplify the representation since we don't have other details for now.
|
||||||
|
return "copy";
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DownloadCopySaver object, with its initial state derived from
|
||||||
|
* its serializable representation.
|
||||||
|
*
|
||||||
|
* @param aSerializable
|
||||||
|
* Serializable representation of a DownloadCopySaver object.
|
||||||
|
*
|
||||||
|
* @return The newly created DownloadCopySaver object.
|
||||||
|
*/
|
||||||
|
DownloadCopySaver.fromSerializable = function (aSerializable) {
|
||||||
|
// We don't have other state details for now.
|
||||||
|
return new DownloadCopySaver();
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// DownloadLegacySaver
|
//// DownloadLegacySaver
|
||||||
|
|
||||||
@ -872,7 +1061,7 @@ DownloadLegacySaver.prototype = {
|
|||||||
// empty file is created as expected.
|
// empty file is created as expected.
|
||||||
try {
|
try {
|
||||||
// This atomic operation is more efficient than an existence check.
|
// This atomic operation is more efficient than an existence check.
|
||||||
let file = yield OS.File.open(this.download.target.file.path,
|
let file = yield OS.File.open(this.download.target.path,
|
||||||
{ create: true });
|
{ create: true });
|
||||||
yield file.close();
|
yield file.close();
|
||||||
} catch (ex if ex instanceof OS.File.Error && ex.becauseExists) { }
|
} catch (ex if ex instanceof OS.File.Error && ex.becauseExists) { }
|
||||||
@ -898,3 +1087,12 @@ DownloadLegacySaver.prototype = {
|
|||||||
"Download canceled."));
|
"Download canceled."));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new DownloadLegacySaver object. This saver type has a
|
||||||
|
* deserializable form only when creating a new object in memory, because it
|
||||||
|
* cannot be serialized to disk.
|
||||||
|
*/
|
||||||
|
DownloadLegacySaver.fromSerializable = function () {
|
||||||
|
return new DownloadLegacySaver();
|
||||||
|
};
|
||||||
|
@ -29,6 +29,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore",
|
|||||||
"resource://gre/modules/DownloadStore.jsm");
|
"resource://gre/modules/DownloadStore.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||||
"resource://gre/modules/FileUtils.jsm");
|
"resource://gre/modules/FileUtils.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||||
|
"resource://gre/modules/NetUtil.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||||
"resource://gre/modules/osfile.jsm");
|
"resource://gre/modules/osfile.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
@ -254,7 +256,8 @@ this.DownloadIntegration = {
|
|||||||
// Log the event if required by parental controls settings.
|
// Log the event if required by parental controls settings.
|
||||||
if (isEnabled && gParentalControlsService.loggingEnabled) {
|
if (isEnabled && gParentalControlsService.loggingEnabled) {
|
||||||
gParentalControlsService.log(gParentalControlsService.ePCLog_FileDownload,
|
gParentalControlsService.log(gParentalControlsService.ePCLog_FileDownload,
|
||||||
shouldBlock, aDownload.source.uri, null);
|
shouldBlock,
|
||||||
|
NetUtil.newURI(aDownload.source.url), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(shouldBlock);
|
return Promise.resolve(shouldBlock);
|
||||||
|
@ -161,9 +161,9 @@ DownloadLegacyTransfer.prototype = {
|
|||||||
// wait for it to be available. This operation may cause the entire
|
// wait for it to be available. This operation may cause the entire
|
||||||
// download system to initialize before the object is created.
|
// download system to initialize before the object is created.
|
||||||
Downloads.createDownload({
|
Downloads.createDownload({
|
||||||
source: { uri: aSource, isPrivate: aIsPrivate },
|
source: { url: aSource.spec, isPrivate: aIsPrivate },
|
||||||
target: { file: aTarget.QueryInterface(Ci.nsIFileURL).file },
|
target: aTarget.QueryInterface(Ci.nsIFileURL).file,
|
||||||
saver: { type: "legacy" },
|
saver: "legacy",
|
||||||
}).then(function DLT_I_onDownload(aDownload) {
|
}).then(function DLT_I_onDownload(aDownload) {
|
||||||
// Now that the saver is available, hook up the cancellation handler.
|
// Now that the saver is available, hook up the cancellation handler.
|
||||||
aDownload.saver.deferCanceled.promise.then(() => {
|
aDownload.saver.deferCanceled.promise.then(() => {
|
||||||
|
@ -25,6 +25,8 @@ const Cr = Components.results;
|
|||||||
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||||
|
"resource://gre/modules/NetUtil.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||||
"resource://gre/modules/PlacesUtils.jsm");
|
"resource://gre/modules/PlacesUtils.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
@ -234,7 +236,8 @@ DownloadList.prototype = {
|
|||||||
//// nsINavHistoryObserver
|
//// nsINavHistoryObserver
|
||||||
|
|
||||||
onDeleteURI: function DL_onDeleteURI(aURI, aGUID) {
|
onDeleteURI: function DL_onDeleteURI(aURI, aGUID) {
|
||||||
this._removeWhere(download => aURI.equals(download.source.uri));
|
this._removeWhere(download => aURI.equals(NetUtil.newURI(
|
||||||
|
download.source.url)));
|
||||||
},
|
},
|
||||||
|
|
||||||
onClearHistory: function DL_onClearHistory() {
|
onClearHistory: function DL_onClearHistory() {
|
||||||
|
@ -7,6 +7,25 @@
|
|||||||
/**
|
/**
|
||||||
* Handles serialization of Download objects and persistence into a file, so
|
* Handles serialization of Download objects and persistence into a file, so
|
||||||
* that the state of downloads can be restored across sessions.
|
* that the state of downloads can be restored across sessions.
|
||||||
|
*
|
||||||
|
* The file is stored in JSON format, without indentation. With indentation
|
||||||
|
* applied, the file would look like this:
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* "list": [
|
||||||
|
* {
|
||||||
|
* "source": "http://www.example.com/download.txt",
|
||||||
|
* "target": "/home/user/Downloads/download.txt"
|
||||||
|
* },
|
||||||
|
* {
|
||||||
|
* "source": {
|
||||||
|
* "url": "http://www.example.com/download.txt",
|
||||||
|
* "referrer": "http://www.example.com/referrer.html"
|
||||||
|
* },
|
||||||
|
* "target": "/home/user/Downloads/download-2.txt"
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
@ -27,16 +46,11 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||||
"resource://gre/modules/Downloads.jsm");
|
"resource://gre/modules/Downloads.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
|
||||||
"resource://gre/modules/NetUtil.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||||
"resource://gre/modules/osfile.jsm")
|
"resource://gre/modules/osfile.jsm")
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
"resource://gre/modules/Task.jsm");
|
"resource://gre/modules/Task.jsm");
|
||||||
|
|
||||||
const LocalFile = Components.Constructor("@mozilla.org/file/local;1",
|
|
||||||
"nsIFile", "initWithPath");
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () {
|
XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () {
|
||||||
return new TextDecoder();
|
return new TextDecoder();
|
||||||
});
|
});
|
||||||
@ -95,19 +109,9 @@ DownloadStore.prototype = {
|
|||||||
let storeData = JSON.parse(gTextDecoder.decode(bytes));
|
let storeData = JSON.parse(gTextDecoder.decode(bytes));
|
||||||
|
|
||||||
// Create live downloads based on the static snapshot.
|
// Create live downloads based on the static snapshot.
|
||||||
for (let downloadData of storeData) {
|
for (let downloadData of storeData.list) {
|
||||||
try {
|
try {
|
||||||
let source = { uri: NetUtil.newURI(downloadData.source.uri) };
|
this.list.add(yield Downloads.createDownload(downloadData));
|
||||||
if ("referrer" in downloadData.source) {
|
|
||||||
source.referrer = NetUtil.newURI(downloadData.source.referrer);
|
|
||||||
}
|
|
||||||
let download = yield Downloads.createDownload({
|
|
||||||
source: source,
|
|
||||||
target: { file: new LocalFile(downloadData.target.file) },
|
|
||||||
saver: downloadData.saver,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.list.add(download);
|
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
// If an item is unrecognized, don't prevent others from being loaded.
|
// If an item is unrecognized, don't prevent others from being loaded.
|
||||||
Cu.reportError(ex);
|
Cu.reportError(ex);
|
||||||
@ -131,19 +135,15 @@ DownloadStore.prototype = {
|
|||||||
let downloads = yield this.list.getAll();
|
let downloads = yield this.list.getAll();
|
||||||
|
|
||||||
// Take a static snapshot of the current state of all the downloads.
|
// Take a static snapshot of the current state of all the downloads.
|
||||||
let storeData = [];
|
let storeData = { list: [] };
|
||||||
let atLeastOneDownload = false;
|
let atLeastOneDownload = false;
|
||||||
for (let download of downloads) {
|
for (let download of downloads) {
|
||||||
try {
|
try {
|
||||||
storeData.push({
|
storeData.list.push(download.toSerializable());
|
||||||
source: download.source.serialize(),
|
|
||||||
target: download.target.serialize(),
|
|
||||||
saver: download.saver.serialize(),
|
|
||||||
});
|
|
||||||
atLeastOneDownload = true;
|
atLeastOneDownload = true;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
// If an item cannot be serialized, don't prevent others from being
|
// If an item cannot be converted to a serializable form, don't
|
||||||
// saved.
|
// prevent others from being saved.
|
||||||
Cu.reportError(ex);
|
Cu.reportError(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "DownloadList",
|
|||||||
"resource://gre/modules/DownloadList.jsm");
|
"resource://gre/modules/DownloadList.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper",
|
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper",
|
||||||
"resource://gre/modules/DownloadUIHelper.jsm");
|
"resource://gre/modules/DownloadUIHelper.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
|
||||||
"resource://gre/modules/FileUtils.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
|
||||||
"resource://gre/modules/NetUtil.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
|
||||||
"resource://gre/modules/Services.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
"resource://gre/modules/Task.jsm");
|
"resource://gre/modules/Task.jsm");
|
||||||
|
|
||||||
@ -55,19 +49,29 @@ this.Downloads = {
|
|||||||
*
|
*
|
||||||
* @param aProperties
|
* @param aProperties
|
||||||
* Provides the initial properties for the newly created download.
|
* Provides the initial properties for the newly created download.
|
||||||
|
* This matches the serializable representation of a Download object.
|
||||||
|
* Some of the most common properties in this object include:
|
||||||
* {
|
* {
|
||||||
* source: {
|
* source: String containing the URI for the download source.
|
||||||
* uri: The nsIURI for the download source.
|
* Alternatively, may be an nsIURI, a DownloadSource object,
|
||||||
|
* or an object with the following properties:
|
||||||
|
* {
|
||||||
|
* url: String containing the URI for the download source.
|
||||||
* isPrivate: Indicates whether the download originated from a
|
* isPrivate: Indicates whether the download originated from a
|
||||||
* private window.
|
* private window. If omitted, the download is public.
|
||||||
|
* referrer: String containing the referrer URI of the download
|
||||||
|
* source. Can be omitted or null if no referrer should
|
||||||
|
* be sent or the download source is not HTTP.
|
||||||
* },
|
* },
|
||||||
* target: {
|
* target: String containing the path of the target file.
|
||||||
* file: The nsIFile for the download target.
|
* Alternatively, may be an nsIFile, a DownloadTarget object,
|
||||||
* },
|
* or an object with the following properties:
|
||||||
* saver: {
|
* {
|
||||||
* type: String representing the class of download operation
|
* path: String containing the path of the target file.
|
||||||
* handled by this saver object, for example "copy".
|
|
||||||
* },
|
* },
|
||||||
|
* saver: String representing the class of the download operation.
|
||||||
|
* If omitted, defaults to "copy". Alternatively, may be the
|
||||||
|
* serializable representation of a DownloadSaver object.
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
@ -76,31 +80,11 @@ this.Downloads = {
|
|||||||
*/
|
*/
|
||||||
createDownload: function D_createDownload(aProperties)
|
createDownload: function D_createDownload(aProperties)
|
||||||
{
|
{
|
||||||
return Task.spawn(function task_D_createDownload() {
|
try {
|
||||||
let download = new Download();
|
return Promise.resolve(Download.fromSerializable(aProperties));
|
||||||
|
} catch (ex) {
|
||||||
download.source = new DownloadSource();
|
return Promise.reject(ex);
|
||||||
download.source.uri = aProperties.source.uri;
|
}
|
||||||
if ("isPrivate" in aProperties.source) {
|
|
||||||
download.source.isPrivate = aProperties.source.isPrivate;
|
|
||||||
}
|
|
||||||
if ("referrer" in aProperties.source) {
|
|
||||||
download.source.referrer = aProperties.source.referrer;
|
|
||||||
}
|
|
||||||
download.target = new DownloadTarget();
|
|
||||||
download.target.file = aProperties.target.file;
|
|
||||||
|
|
||||||
// Support for different aProperties.saver values isn't implemented yet.
|
|
||||||
download.saver = aProperties.saver.type == "legacy"
|
|
||||||
? new DownloadLegacySaver()
|
|
||||||
: new DownloadCopySaver();
|
|
||||||
download.saver.download = download;
|
|
||||||
|
|
||||||
// This explicitly makes this function a generator for Task.jsm, so that
|
|
||||||
// exceptions in the above calls can be reported asynchronously.
|
|
||||||
yield;
|
|
||||||
throw new Task.Result(download);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,15 +95,17 @@ this.Downloads = {
|
|||||||
* reference to a Download object using the createDownload function.
|
* reference to a Download object using the createDownload function.
|
||||||
*
|
*
|
||||||
* @param aSource
|
* @param aSource
|
||||||
* The nsIURI or string containing the URI spec for the download
|
* String containing the URI for the download source. Alternatively,
|
||||||
* source, or alternative DownloadSource.
|
* may be an nsIURI or a DownloadSource object.
|
||||||
* @param aTarget
|
* @param aTarget
|
||||||
* The nsIFile or string containing the file path, or alternative
|
* String containing the path of the target file. Alternatively, may
|
||||||
* DownloadTarget.
|
* be an nsIFile or a DownloadTarget object.
|
||||||
* @param aOptions
|
* @param aOptions
|
||||||
* The object contains different additional options or null.
|
* An optional object used to control the behavior of this function.
|
||||||
* { isPrivate: Indicates whether the download originated from a
|
* You may pass an object with a subset of the following fields:
|
||||||
* private window.
|
* {
|
||||||
|
* isPrivate: Indicates whether the download originated from a
|
||||||
|
* private window.
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
@ -127,31 +113,13 @@ this.Downloads = {
|
|||||||
* @rejects JavaScript exception if the download failed.
|
* @rejects JavaScript exception if the download failed.
|
||||||
*/
|
*/
|
||||||
simpleDownload: function D_simpleDownload(aSource, aTarget, aOptions) {
|
simpleDownload: function D_simpleDownload(aSource, aTarget, aOptions) {
|
||||||
// Wrap the arguments into simple objects resembling DownloadSource and
|
|
||||||
// DownloadTarget, if they are not objects of that type already.
|
|
||||||
if (aSource instanceof Ci.nsIURI) {
|
|
||||||
aSource = { uri: aSource };
|
|
||||||
} else if (typeof aSource == "string" ||
|
|
||||||
(typeof aSource == "object" && "charAt" in aSource)) {
|
|
||||||
aSource = { uri: NetUtil.newURI(aSource) };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aSource && aOptions && ("isPrivate" in aOptions)) {
|
|
||||||
aSource.isPrivate = aOptions.isPrivate;
|
|
||||||
}
|
|
||||||
if (aTarget instanceof Ci.nsIFile) {
|
|
||||||
aTarget = { file: aTarget };
|
|
||||||
} else if (typeof aTarget == "string" ||
|
|
||||||
(typeof aTarget == "object" && "charAt" in aTarget)) {
|
|
||||||
aTarget = { file: new FileUtils.File(aTarget) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and start the actual download.
|
|
||||||
return this.createDownload({
|
return this.createDownload({
|
||||||
source: aSource,
|
source: aSource,
|
||||||
target: aTarget,
|
target: aTarget,
|
||||||
saver: { type: "copy" },
|
|
||||||
}).then(function D_SD_onSuccess(aDownload) {
|
}).then(function D_SD_onSuccess(aDownload) {
|
||||||
|
if (aOptions && ("isPrivate" in aOptions)) {
|
||||||
|
aDownload.source.isPrivate = aOptions.isPrivate;
|
||||||
|
}
|
||||||
return aDownload.start();
|
return aDownload.start();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
1105
toolkit/components/jsdownloads/test/unit/common_test_Download.js
Normal file
1105
toolkit/components/jsdownloads/test/unit/common_test_Download.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -51,51 +51,11 @@ const BinaryOutputStream = Components.Constructor(
|
|||||||
"nsIBinaryOutputStream",
|
"nsIBinaryOutputStream",
|
||||||
"setOutputStream")
|
"setOutputStream")
|
||||||
|
|
||||||
Object.defineProperty(this, "HTTP_BASE", {get: function() {
|
|
||||||
return "http://localhost:" + gHttpServer.identity.primaryPort;
|
|
||||||
}});
|
|
||||||
|
|
||||||
Object.defineProperty(this, "FAKE_BASE", {get: function() {
|
|
||||||
return "http://localhost:" + gFakeServerPort;
|
|
||||||
}});
|
|
||||||
|
|
||||||
Object.defineProperty(this, "TEST_REFERRER_URI", {get: function() {
|
|
||||||
return NetUtil.newURI(HTTP_BASE + "/referrer.html");
|
|
||||||
}});
|
|
||||||
|
|
||||||
Object.defineProperty(this, "TEST_SOURCE_URI", {get: function() {
|
|
||||||
return NetUtil.newURI(HTTP_BASE + "/source.txt");
|
|
||||||
}});
|
|
||||||
|
|
||||||
Object.defineProperty(this, "TEST_EMPTY_URI", {get: function() {
|
|
||||||
return NetUtil.newURI(HTTP_BASE + "/empty.txt");
|
|
||||||
}});
|
|
||||||
|
|
||||||
Object.defineProperty(this, "TEST_FAKE_SOURCE_URI", {get: function() {
|
|
||||||
return NetUtil.newURI(FAKE_BASE + "/source.txt");
|
|
||||||
}});
|
|
||||||
|
|
||||||
const TEST_EMPTY_NOPROGRESS_PATH = "/empty-noprogress.txt";
|
|
||||||
|
|
||||||
Object.defineProperty(this, "TEST_EMPTY_NOPROGRESS_URI", {get: function() {
|
|
||||||
return NetUtil.newURI(HTTP_BASE + TEST_EMPTY_NOPROGRESS_PATH);
|
|
||||||
}});
|
|
||||||
|
|
||||||
const TEST_INTERRUPTIBLE_PATH = "/interruptible.txt";
|
|
||||||
|
|
||||||
Object.defineProperty(this, "TEST_INTERRUPTIBLE_URI", {get: function() {
|
|
||||||
return NetUtil.newURI(HTTP_BASE + TEST_INTERRUPTIBLE_PATH);
|
|
||||||
}});
|
|
||||||
|
|
||||||
const TEST_INTERRUPTIBLE_GZIP_PATH = "/interruptible_gzip.txt";
|
|
||||||
|
|
||||||
Object.defineProperty(this, "TEST_INTERRUPTIBLE_GZIP_URI", {get: function() {
|
|
||||||
return NetUtil.newURI(HTTP_BASE + TEST_INTERRUPTIBLE_GZIP_PATH);
|
|
||||||
}});
|
|
||||||
|
|
||||||
const TEST_TARGET_FILE_NAME = "test-download.txt";
|
const TEST_TARGET_FILE_NAME = "test-download.txt";
|
||||||
const TEST_STORE_FILE_NAME = "test-downloads.json";
|
const TEST_STORE_FILE_NAME = "test-downloads.json";
|
||||||
|
|
||||||
|
const TEST_REFERRER_URL = "http://www.example.com/referrer.html";
|
||||||
|
|
||||||
const TEST_DATA_SHORT = "This test string is downloaded.";
|
const TEST_DATA_SHORT = "This test string is downloaded.";
|
||||||
// Generate using gzipCompressString in TelemetryPing.js.
|
// Generate using gzipCompressString in TelemetryPing.js.
|
||||||
const TEST_DATA_SHORT_GZIP_ENCODED_FIRST = [
|
const TEST_DATA_SHORT_GZIP_ENCODED_FIRST = [
|
||||||
@ -119,6 +79,20 @@ function run_test()
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Support functions
|
//// Support functions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpServer object initialized before tests start.
|
||||||
|
*/
|
||||||
|
let gHttpServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a file name, returns a string containing an URI that points to the file
|
||||||
|
* on the currently running instance of the test HTTP server.
|
||||||
|
*/
|
||||||
|
function httpUrl(aFileName) {
|
||||||
|
return "http://localhost:" + gHttpServer.identity.primaryPort + "/" +
|
||||||
|
aFileName;
|
||||||
|
}
|
||||||
|
|
||||||
// While the previous test file should have deleted all the temporary files it
|
// While the previous test file should have deleted all the temporary files it
|
||||||
// used, on Windows these might still be pending deletion on the physical file
|
// used, on Windows these might still be pending deletion on the physical file
|
||||||
// system. Thus, start from a new base number every time, to make a collision
|
// system. Thus, start from a new base number every time, to make a collision
|
||||||
@ -190,21 +164,101 @@ function promiseTimeout(aTime)
|
|||||||
/**
|
/**
|
||||||
* Creates a new Download object, setting a temporary file as the target.
|
* Creates a new Download object, setting a temporary file as the target.
|
||||||
*
|
*
|
||||||
* @param aSourceURI
|
* @param aSourceUrl
|
||||||
* The nsIURI for the download source, or null to use TEST_SOURCE_URI.
|
* String containing the URI for the download source, or null to use
|
||||||
|
* httpUrl("source.txt").
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
* @resolves The newly created Download object.
|
* @resolves The newly created Download object.
|
||||||
* @rejects JavaScript exception.
|
* @rejects JavaScript exception.
|
||||||
*/
|
*/
|
||||||
function promiseSimpleDownload(aSourceURI) {
|
function promiseNewDownload(aSourceUrl) {
|
||||||
return Downloads.createDownload({
|
return Downloads.createDownload({
|
||||||
source: { uri: aSourceURI || TEST_SOURCE_URI },
|
source: aSourceUrl || httpUrl("source.txt"),
|
||||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
target: getTempFile(TEST_TARGET_FILE_NAME),
|
||||||
saver: { type: "copy" },
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new download using the nsIWebBrowserPersist interface, and controls
|
||||||
|
* it using the legacy nsITransfer interface.
|
||||||
|
*
|
||||||
|
* @param aSourceUrl
|
||||||
|
* String containing the URI for the download source, or null to use
|
||||||
|
* httpUrl("source.txt").
|
||||||
|
* @param aOptions
|
||||||
|
* An optional object used to control the behavior of this function.
|
||||||
|
* You may pass an object with a subset of the following fields:
|
||||||
|
* {
|
||||||
|
* isPrivate: Boolean indicating whether the download originated from a
|
||||||
|
* private window.
|
||||||
|
* targetFile: nsIFile for the target, or null to use a temporary file.
|
||||||
|
* outPersist: Receives a reference to the created nsIWebBrowserPersist
|
||||||
|
* instance.
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @return {Promise}
|
||||||
|
* @resolves The Download object created as a consequence of controlling the
|
||||||
|
* download through the legacy nsITransfer interface.
|
||||||
|
* @rejects Never. The current test fails in case of exceptions.
|
||||||
|
*/
|
||||||
|
function promiseStartLegacyDownload(aSourceUrl, aOptions) {
|
||||||
|
let sourceURI = NetUtil.newURI(aSourceUrl || httpUrl("source.txt"));
|
||||||
|
let targetFile = (aOptions && aOptions.targetFile)
|
||||||
|
|| getTempFile(TEST_TARGET_FILE_NAME);
|
||||||
|
|
||||||
|
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
|
||||||
|
.createInstance(Ci.nsIWebBrowserPersist);
|
||||||
|
if (aOptions) {
|
||||||
|
aOptions.outPersist = persist;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply decoding if required by the "Content-Encoding" header.
|
||||||
|
persist.persistFlags &= ~Ci.nsIWebBrowserPersist.PERSIST_FLAGS_NO_CONVERSION;
|
||||||
|
|
||||||
|
// We must create the nsITransfer implementation using its class ID because
|
||||||
|
// the "@mozilla.org/transfer;1" contract is currently implemented in
|
||||||
|
// "toolkit/components/downloads". When the other folder is not included in
|
||||||
|
// builds anymore (bug 851471), we'll be able to use the contract ID.
|
||||||
|
let transfer =
|
||||||
|
Components.classesByID["{1b4c85df-cbdd-4bb6-b04e-613caece083c}"]
|
||||||
|
.createInstance(Ci.nsITransfer);
|
||||||
|
|
||||||
|
let deferred = Promise.defer();
|
||||||
|
|
||||||
|
let isPrivate = aOptions && aOptions.isPrivate;
|
||||||
|
let promise = isPrivate ? Downloads.getPrivateDownloadList()
|
||||||
|
: Downloads.getPublicDownloadList();
|
||||||
|
promise.then(function (aList) {
|
||||||
|
// Temporarily register a view that will get notified when the download we
|
||||||
|
// are controlling becomes visible in the list of downloads.
|
||||||
|
aList.addView({
|
||||||
|
onDownloadAdded: function (aDownload) {
|
||||||
|
aList.removeView(this);
|
||||||
|
|
||||||
|
// Remove the download to keep the list empty for the next test. This
|
||||||
|
// also allows the caller to register the "onchange" event directly.
|
||||||
|
aList.remove(aDownload);
|
||||||
|
|
||||||
|
// When the download object is ready, make it available to the caller.
|
||||||
|
deferred.resolve(aDownload);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize the components so they reference each other. This will cause
|
||||||
|
// the Download object to be created and added to the public downloads.
|
||||||
|
transfer.init(sourceURI, NetUtil.newURI(targetFile), null, null, null, null,
|
||||||
|
persist, isPrivate);
|
||||||
|
persist.progressListener = transfer;
|
||||||
|
|
||||||
|
// Start the actual download process.
|
||||||
|
persist.savePrivacyAwareURI(sourceURI, null, null, null, null, targetFile,
|
||||||
|
isPrivate);
|
||||||
|
}.bind(this)).then(null, do_report_unexpected_exception);
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new public DownloadList object.
|
* Returns a new public DownloadList object.
|
||||||
*
|
*
|
||||||
@ -234,8 +288,9 @@ function promiseNewPrivateDownloadList() {
|
|||||||
/**
|
/**
|
||||||
* Ensures that the given file contents are equal to the given string.
|
* Ensures that the given file contents are equal to the given string.
|
||||||
*
|
*
|
||||||
* @param aFile
|
* @param aPath
|
||||||
* nsIFile whose contents should be verified.
|
* String containing the path of the file whose contents should be
|
||||||
|
* verified.
|
||||||
* @param aExpectedContents
|
* @param aExpectedContents
|
||||||
* String containing the octets that are expected in the file.
|
* String containing the octets that are expected in the file.
|
||||||
*
|
*
|
||||||
@ -243,10 +298,11 @@ function promiseNewPrivateDownloadList() {
|
|||||||
* @resolves When the operation completes.
|
* @resolves When the operation completes.
|
||||||
* @rejects Never.
|
* @rejects Never.
|
||||||
*/
|
*/
|
||||||
function promiseVerifyContents(aFile, aExpectedContents)
|
function promiseVerifyContents(aPath, aExpectedContents)
|
||||||
{
|
{
|
||||||
let deferred = Promise.defer();
|
let deferred = Promise.defer();
|
||||||
NetUtil.asyncFetch(aFile, function(aInputStream, aStatus) {
|
let file = new FileUtils.File(aPath);
|
||||||
|
NetUtil.asyncFetch(file, function(aInputStream, aStatus) {
|
||||||
do_check_true(Components.isSuccessCode(aStatus));
|
do_check_true(Components.isSuccessCode(aStatus));
|
||||||
let contents = NetUtil.readInputStreamToString(aInputStream,
|
let contents = NetUtil.readInputStreamToString(aInputStream,
|
||||||
aInputStream.available());
|
aInputStream.available());
|
||||||
@ -265,17 +321,18 @@ function promiseVerifyContents(aFile, aExpectedContents)
|
|||||||
/**
|
/**
|
||||||
* Adds entry for download.
|
* Adds entry for download.
|
||||||
*
|
*
|
||||||
* @param aSourceURI
|
* @param aSourceUrl
|
||||||
* The nsIURI for the download source, or null to use TEST_SOURCE_URI.
|
* String containing the URI for the download source, or null to use
|
||||||
|
* httpUrl("source.txt").
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
* @rejects JavaScript exception.
|
* @rejects JavaScript exception.
|
||||||
*/
|
*/
|
||||||
function promiseAddDownloadToHistory(aSourceURI) {
|
function promiseAddDownloadToHistory(aSourceUrl) {
|
||||||
let deferred = Promise.defer();
|
let deferred = Promise.defer();
|
||||||
PlacesUtils.asyncHistory.updatePlaces(
|
PlacesUtils.asyncHistory.updatePlaces(
|
||||||
{
|
{
|
||||||
uri: aSourceURI || TEST_SOURCE_URI,
|
uri: NetUtil.newURI(aSourceUrl || httpUrl("source.txt")),
|
||||||
visits: [{
|
visits: [{
|
||||||
transitionType: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
|
transitionType: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
|
||||||
visitDate: Date.now()
|
visitDate: Date.now()
|
||||||
@ -304,7 +361,6 @@ function promiseAddDownloadToHistory(aSourceURI) {
|
|||||||
function startFakeServer()
|
function startFakeServer()
|
||||||
{
|
{
|
||||||
let serverSocket = new ServerSocket(-1, true, -1);
|
let serverSocket = new ServerSocket(-1, true, -1);
|
||||||
gFakeServerPort = serverSocket.port;
|
|
||||||
serverSocket.asyncListen({
|
serverSocket.asyncListen({
|
||||||
onSocketAccepted: function (aServ, aTransport) {
|
onSocketAccepted: function (aServ, aTransport) {
|
||||||
aTransport.close(Cr.NS_BINDING_ABORTED);
|
aTransport.close(Cr.NS_BINDING_ABORTED);
|
||||||
@ -326,10 +382,10 @@ function startFakeServer()
|
|||||||
* handlers, you may call "deferNextResponse" to get a reference to an object
|
* handlers, you may call "deferNextResponse" to get a reference to an object
|
||||||
* that allows you to control the next request.
|
* that allows you to control the next request.
|
||||||
*
|
*
|
||||||
* For example, the handler accessible at the TEST_INTERRUPTIBLE_URI address
|
* For example, the handler accessible at the httpUri("interruptible.txt")
|
||||||
* returns the TEST_DATA_SHORT text, then waits until the "resolve" method is
|
* address returns the TEST_DATA_SHORT text, then waits until the "resolve"
|
||||||
* called on the object returned by the function. At this point, the handler
|
* method is called on the object returned by the function. At this point, the
|
||||||
* sends the TEST_DATA_SHORT text again to complete the response.
|
* handler sends the TEST_DATA_SHORT text again to complete the response.
|
||||||
*
|
*
|
||||||
* You can also call the "reject" method on the returned object to interrupt the
|
* You can also call the "reject" method on the returned object to interrupt the
|
||||||
* response midway. Because of how the network layer is implemented, this does
|
* response midway. Because of how the network layer is implemented, this does
|
||||||
@ -429,9 +485,6 @@ function isValidDate(aDate) {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Initialization functions common to all tests
|
//// Initialization functions common to all tests
|
||||||
|
|
||||||
let gHttpServer;
|
|
||||||
let gFakeServerPort;
|
|
||||||
|
|
||||||
add_task(function test_common_initialize()
|
add_task(function test_common_initialize()
|
||||||
{
|
{
|
||||||
// Start the HTTP server.
|
// Start the HTTP server.
|
||||||
@ -439,7 +492,7 @@ add_task(function test_common_initialize()
|
|||||||
gHttpServer.registerDirectory("/", do_get_file("../data"));
|
gHttpServer.registerDirectory("/", do_get_file("../data"));
|
||||||
gHttpServer.start(-1);
|
gHttpServer.start(-1);
|
||||||
|
|
||||||
registerInterruptibleHandler(TEST_INTERRUPTIBLE_PATH,
|
registerInterruptibleHandler("/interruptible.txt",
|
||||||
function firstPart(aRequest, aResponse) {
|
function firstPart(aRequest, aResponse) {
|
||||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
aResponse.setHeader("Content-Type", "text/plain", false);
|
||||||
aResponse.setHeader("Content-Length", "" + (TEST_DATA_SHORT.length * 2),
|
aResponse.setHeader("Content-Length", "" + (TEST_DATA_SHORT.length * 2),
|
||||||
@ -449,13 +502,13 @@ add_task(function test_common_initialize()
|
|||||||
aResponse.write(TEST_DATA_SHORT);
|
aResponse.write(TEST_DATA_SHORT);
|
||||||
});
|
});
|
||||||
|
|
||||||
registerInterruptibleHandler(TEST_EMPTY_NOPROGRESS_PATH,
|
registerInterruptibleHandler("/empty-noprogress.txt",
|
||||||
function firstPart(aRequest, aResponse) {
|
function firstPart(aRequest, aResponse) {
|
||||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
aResponse.setHeader("Content-Type", "text/plain", false);
|
||||||
}, function secondPart(aRequest, aResponse) { });
|
}, function secondPart(aRequest, aResponse) { });
|
||||||
|
|
||||||
|
|
||||||
registerInterruptibleHandler(TEST_INTERRUPTIBLE_GZIP_PATH,
|
registerInterruptibleHandler("/interruptible_gzip.txt",
|
||||||
function firstPart(aRequest, aResponse) {
|
function firstPart(aRequest, aResponse) {
|
||||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
aResponse.setHeader("Content-Type", "text/plain", false);
|
||||||
aResponse.setHeader("Content-Encoding", "gzip", false);
|
aResponse.setHeader("Content-Encoding", "gzip", false);
|
||||||
|
@ -4,894 +4,15 @@
|
|||||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the objects defined in the "DownloadCore" module.
|
* Tests the main download interfaces using DownloadCopySaver.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Tests
|
//// Execution of common tests
|
||||||
|
|
||||||
/**
|
let gUseLegacySaver = false;
|
||||||
* Executes a download, started by constructing the simplest Download object.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_construction()
|
|
||||||
{
|
|
||||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
|
||||||
|
|
||||||
let download = yield Downloads.createDownload({
|
|
||||||
source: { uri: TEST_SOURCE_URI },
|
|
||||||
target: { file: targetFile },
|
|
||||||
saver: { type: "copy" },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Checks the generated DownloadSource and DownloadTarget properties.
|
|
||||||
do_check_true(download.source.uri.equals(TEST_SOURCE_URI));
|
|
||||||
do_check_eq(download.target.file, targetFile);
|
|
||||||
do_check_true(download.source.referrer === null);
|
|
||||||
|
|
||||||
// Starts the download and waits for completion.
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the referrer for downloads.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_referrer()
|
|
||||||
{
|
|
||||||
let source_path = "/test_download_referrer.txt";
|
|
||||||
let source_uri = NetUtil.newURI(HTTP_BASE + source_path);
|
|
||||||
let target_uri = getTempFile(TEST_TARGET_FILE_NAME);
|
|
||||||
|
|
||||||
function cleanup() {
|
|
||||||
gHttpServer.registerPathHandler(source_path, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_register_cleanup(cleanup);
|
|
||||||
|
|
||||||
gHttpServer.registerPathHandler(source_path, function (aRequest, aResponse) {
|
|
||||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
|
||||||
|
|
||||||
do_check_true(aRequest.hasHeader("Referer"));
|
|
||||||
do_check_eq(aRequest.getHeader("Referer"), TEST_REFERRER_URI.spec);
|
|
||||||
});
|
|
||||||
let download = yield Downloads.createDownload({
|
|
||||||
source: { uri: source_uri, referrer: TEST_REFERRER_URI },
|
|
||||||
target: { file: target_uri },
|
|
||||||
saver: { type: "copy" },
|
|
||||||
});
|
|
||||||
do_check_true(download.source.referrer.equals(TEST_REFERRER_URI));
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
download = yield Downloads.createDownload({
|
|
||||||
source: { uri: source_uri, referrer: TEST_REFERRER_URI, isPrivate: true },
|
|
||||||
target: { file: target_uri },
|
|
||||||
saver: { type: "copy" },
|
|
||||||
});
|
|
||||||
do_check_true(download.source.referrer.equals(TEST_REFERRER_URI));
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
// Test the download still works for non-HTTP channel with referrer.
|
|
||||||
source_uri = NetUtil.newURI("data:text/html,<html><body></body></html>");
|
|
||||||
download = yield Downloads.createDownload({
|
|
||||||
source: { uri: source_uri, referrer: TEST_REFERRER_URI },
|
|
||||||
target: { file: target_uri },
|
|
||||||
saver: { type: "copy" },
|
|
||||||
});
|
|
||||||
do_check_true(download.source.referrer.equals(TEST_REFERRER_URI));
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks initial and final state and progress for a successful download.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_initial_final_state()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload();
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_false(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
do_check_eq(download.progress, 0);
|
|
||||||
do_check_true(download.startTime === null);
|
|
||||||
|
|
||||||
// Starts the download and waits for completion.
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
do_check_true(isValidDate(download.startTime));
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the notification of the final download state.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_final_state_notified()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload();
|
|
||||||
|
|
||||||
let onchangeNotified = false;
|
|
||||||
let lastNotifiedStopped;
|
|
||||||
let lastNotifiedProgress;
|
|
||||||
download.onchange = function () {
|
|
||||||
onchangeNotified = true;
|
|
||||||
lastNotifiedStopped = download.stopped;
|
|
||||||
lastNotifiedProgress = download.progress;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Starts the download and waits for completion.
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
// The view should have been notified before the download completes.
|
|
||||||
do_check_true(onchangeNotified);
|
|
||||||
do_check_true(lastNotifiedStopped);
|
|
||||||
do_check_eq(lastNotifiedProgress, 100);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks intermediate progress for a successful download.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_intermediate_progress()
|
|
||||||
{
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
download.onchange = function () {
|
|
||||||
if (download.progress == 50) {
|
|
||||||
do_check_true(download.hasProgress);
|
|
||||||
do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
|
|
||||||
do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
|
|
||||||
|
|
||||||
// Continue after the first chunk of data is fully received.
|
|
||||||
deferResponse.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Starts the download and waits for completion.
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file,
|
|
||||||
TEST_DATA_SHORT + TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads a file with a "Content-Length" of 0 and checks the progress.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_empty_progress()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload(TEST_EMPTY_URI);
|
|
||||||
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.hasProgress);
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
|
|
||||||
do_check_eq(download.target.file.fileSize, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads an empty file with no "Content-Length" and checks the progress.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_empty_noprogress()
|
|
||||||
{
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
let promiseEmptyRequestReceived = promiseNextRequestReceived();
|
|
||||||
|
|
||||||
let download = yield promiseSimpleDownload(TEST_EMPTY_NOPROGRESS_URI);
|
|
||||||
|
|
||||||
download.onchange = function () {
|
|
||||||
if (!download.stopped) {
|
|
||||||
do_check_false(download.hasProgress);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Start the download, while waiting for the request to be received.
|
|
||||||
let promiseAttempt = download.start();
|
|
||||||
|
|
||||||
// Wait for the request to be received by the HTTP server, but don't allow the
|
|
||||||
// request to finish yet. Before checking the download state, wait for the
|
|
||||||
// events to be processed by the client.
|
|
||||||
yield promiseEmptyRequestReceived;
|
|
||||||
yield promiseExecuteSoon();
|
|
||||||
|
|
||||||
// Check that this download has no progress report.
|
|
||||||
do_check_false(download.stopped);
|
|
||||||
do_check_false(download.hasProgress);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
|
|
||||||
// Now allow the response to finish, and wait for the download to complete.
|
|
||||||
deferResponse.resolve();
|
|
||||||
yield promiseAttempt;
|
|
||||||
|
|
||||||
// Verify the state of the completed download.
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_false(download.hasProgress);
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
|
|
||||||
do_check_eq(download.target.file.fileSize, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the "start" method two times before the download is finished.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_start_twice()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
// Ensure that the download cannot complete before start is called twice.
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
|
|
||||||
// Call the start method two times.
|
|
||||||
let promiseAttempt1 = download.start();
|
|
||||||
let promiseAttempt2 = download.start();
|
|
||||||
|
|
||||||
// Allow the download to finish.
|
|
||||||
deferResponse.resolve();
|
|
||||||
|
|
||||||
// Both promises should now be resolved.
|
|
||||||
yield promiseAttempt1;
|
|
||||||
yield promiseAttempt2;
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file,
|
|
||||||
TEST_DATA_SHORT + TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels a download and verifies that its state is reported correctly.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_cancel_midway()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
try {
|
|
||||||
// Cancel the download after receiving the first part of the response.
|
|
||||||
let deferCancel = Promise.defer();
|
|
||||||
download.onchange = function () {
|
|
||||||
if (!download.stopped && !download.canceled && download.progress == 50) {
|
|
||||||
deferCancel.resolve(download.cancel());
|
|
||||||
|
|
||||||
// The state change happens immediately after calling "cancel", but
|
|
||||||
// temporary files or part files may still exist at this point.
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let promiseAttempt = download.start();
|
|
||||||
|
|
||||||
// Wait on the promise returned by the "cancel" method to ensure that the
|
|
||||||
// cancellation process finished and temporary files were removed.
|
|
||||||
yield deferCancel.promise;
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
do_check_false(download.target.file.exists());
|
|
||||||
|
|
||||||
// Progress properties are not reset by canceling.
|
|
||||||
do_check_eq(download.progress, 50);
|
|
||||||
do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
|
|
||||||
do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
|
|
||||||
|
|
||||||
// The promise returned by "start" should have been rejected meanwhile.
|
|
||||||
try {
|
|
||||||
yield promiseAttempt;
|
|
||||||
do_throw("The download should have been canceled.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error) {
|
|
||||||
do_check_false(ex.becauseSourceFailed);
|
|
||||||
do_check_false(ex.becauseTargetFailed);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
deferResponse.resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels a download right after starting it.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_cancel_immediately()
|
|
||||||
{
|
|
||||||
// Ensure that the download cannot complete before cancel is called.
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
try {
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
let promiseAttempt = download.start();
|
|
||||||
do_check_false(download.stopped);
|
|
||||||
|
|
||||||
let promiseCancel = download.cancel();
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
|
|
||||||
// At this point, we don't know whether the download has already stopped or
|
|
||||||
// is still waiting for cancellation. We can wait on the promise returned
|
|
||||||
// by the "start" method to know for sure.
|
|
||||||
try {
|
|
||||||
yield promiseAttempt;
|
|
||||||
do_throw("The download should have been canceled.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error) {
|
|
||||||
do_check_false(ex.becauseSourceFailed);
|
|
||||||
do_check_false(ex.becauseTargetFailed);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
do_check_false(download.target.file.exists());
|
|
||||||
|
|
||||||
// Check that the promise returned by the "cancel" method has been resolved.
|
|
||||||
yield promiseCancel;
|
|
||||||
} finally {
|
|
||||||
deferResponse.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Even if we canceled the download immediately, the HTTP request might have
|
|
||||||
// been made, and the internal HTTP handler might be waiting to process it.
|
|
||||||
// Thus, we process any pending events now, to avoid that the request is
|
|
||||||
// processed during the tests that follow, interfering with them.
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
yield promiseExecuteSoon();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels and restarts a download sequentially.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_cancel_midway_restart()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
// The first time, cancel the download midway.
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
try {
|
|
||||||
let deferCancel = Promise.defer();
|
|
||||||
download.onchange = function () {
|
|
||||||
if (!download.stopped && !download.canceled && download.progress == 50) {
|
|
||||||
deferCancel.resolve(download.cancel());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
download.start();
|
|
||||||
yield deferCancel.promise;
|
|
||||||
} finally {
|
|
||||||
deferResponse.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
|
|
||||||
// The second time, we'll provide the entire interruptible response.
|
|
||||||
download.onchange = null;
|
|
||||||
let promiseAttempt = download.start();
|
|
||||||
|
|
||||||
// Download state should have already been reset.
|
|
||||||
do_check_false(download.stopped);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
// For the following test, we rely on the network layer reporting its progress
|
|
||||||
// asynchronously. Otherwise, there is nothing stopping the restarted
|
|
||||||
// download from reaching the same progress as the first request already.
|
|
||||||
do_check_eq(download.progress, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
|
|
||||||
yield promiseAttempt;
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file,
|
|
||||||
TEST_DATA_SHORT + TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels a download right after starting it, then restarts it immediately.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_cancel_immediately_restart_immediately()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
// Ensure that the download cannot complete before cancel is called.
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
|
|
||||||
let promiseAttempt = download.start();
|
|
||||||
do_check_false(download.stopped);
|
|
||||||
|
|
||||||
download.cancel();
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
|
|
||||||
let promiseRestarted = download.start();
|
|
||||||
do_check_false(download.stopped);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
// For the following test, we rely on the network layer reporting its progress
|
|
||||||
// asynchronously. Otherwise, there is nothing stopping the restarted
|
|
||||||
// download from reaching the same progress as the first request already.
|
|
||||||
do_check_eq(download.hasProgress, false);
|
|
||||||
do_check_eq(download.progress, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
|
|
||||||
// Even if we canceled the download immediately, the HTTP request might have
|
|
||||||
// been made, and the internal HTTP handler might be waiting to process it.
|
|
||||||
// Thus, we process any pending events now, to avoid that the request is
|
|
||||||
// processed during the tests that follow, interfering with them.
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
yield promiseExecuteSoon();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the next request is now allowed to complete, regardless of whether
|
|
||||||
// the canceled request was received by the server or not.
|
|
||||||
deferResponse.resolve();
|
|
||||||
|
|
||||||
try {
|
|
||||||
yield promiseAttempt;
|
|
||||||
do_throw("The download should have been canceled.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error) {
|
|
||||||
do_check_false(ex.becauseSourceFailed);
|
|
||||||
do_check_false(ex.becauseTargetFailed);
|
|
||||||
}
|
|
||||||
|
|
||||||
yield promiseRestarted;
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file,
|
|
||||||
TEST_DATA_SHORT + TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels a download midway, then restarts it immediately.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_cancel_midway_restart_immediately()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
// The first time, cancel the download midway.
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
|
|
||||||
let deferMidway = Promise.defer();
|
|
||||||
download.onchange = function () {
|
|
||||||
if (!download.stopped && !download.canceled && download.progress == 50) {
|
|
||||||
do_check_eq(download.progress, 50);
|
|
||||||
deferMidway.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let promiseAttempt = download.start();
|
|
||||||
yield deferMidway.promise;
|
|
||||||
|
|
||||||
download.cancel();
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
|
|
||||||
let promiseRestarted = download.start();
|
|
||||||
do_check_false(download.stopped);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
// For the following test, we rely on the network layer reporting its progress
|
|
||||||
// asynchronously. Otherwise, there is nothing stopping the restarted
|
|
||||||
// download from reaching the same progress as the first request already.
|
|
||||||
do_check_eq(download.hasProgress, false);
|
|
||||||
do_check_eq(download.progress, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
|
|
||||||
deferResponse.resolve();
|
|
||||||
|
|
||||||
// The second request is allowed to complete.
|
|
||||||
try {
|
|
||||||
yield promiseAttempt;
|
|
||||||
do_throw("The download should have been canceled.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error) {
|
|
||||||
do_check_false(ex.becauseSourceFailed);
|
|
||||||
do_check_false(ex.becauseTargetFailed);
|
|
||||||
}
|
|
||||||
|
|
||||||
yield promiseRestarted;
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file,
|
|
||||||
TEST_DATA_SHORT + TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the "cancel" method on a successful download.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_cancel_successful()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload();
|
|
||||||
|
|
||||||
// Starts the download and waits for completion.
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
// The cancel method should succeed with no effect.
|
|
||||||
yield download.cancel();
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file, TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the "cancel" method two times in a row.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_cancel_twice()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
// Ensure that the download cannot complete before cancel is called.
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
try {
|
|
||||||
let promiseAttempt = download.start();
|
|
||||||
do_check_false(download.stopped);
|
|
||||||
|
|
||||||
let promiseCancel1 = download.cancel();
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
let promiseCancel2 = download.cancel();
|
|
||||||
|
|
||||||
try {
|
|
||||||
yield promiseAttempt;
|
|
||||||
do_throw("The download should have been canceled.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error) {
|
|
||||||
do_check_false(ex.becauseSourceFailed);
|
|
||||||
do_check_false(ex.becauseTargetFailed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both promises should now be resolved.
|
|
||||||
yield promiseCancel1;
|
|
||||||
yield promiseCancel2;
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_false(download.succeeded);
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
do_check_false(download.target.file.exists());
|
|
||||||
} finally {
|
|
||||||
deferResponse.resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks that whenSucceeded returns a promise that is resolved after a restart.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_whenSucceeded()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
// Ensure that the download cannot complete before cancel is called.
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
|
|
||||||
// Get a reference before the first download attempt.
|
|
||||||
let promiseSucceeded = download.whenSucceeded();
|
|
||||||
|
|
||||||
// Cancel the first download attempt.
|
|
||||||
download.start();
|
|
||||||
yield download.cancel();
|
|
||||||
|
|
||||||
deferResponse.resolve();
|
|
||||||
|
|
||||||
// The second request is allowed to complete.
|
|
||||||
download.start();
|
|
||||||
|
|
||||||
// Wait for the download to finish by waiting on the whenSucceeded promise.
|
|
||||||
yield promiseSucceeded;
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file,
|
|
||||||
TEST_DATA_SHORT + TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures download error details are reported on network failures.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_error_source()
|
|
||||||
{
|
|
||||||
let serverSocket = startFakeServer();
|
|
||||||
try {
|
|
||||||
let download = yield promiseSimpleDownload(TEST_FAKE_SOURCE_URI);
|
|
||||||
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
yield download.start();
|
|
||||||
do_throw("The download should have failed.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error && ex.becauseSourceFailed) {
|
|
||||||
// A specific error object is thrown when reading from the source fails.
|
|
||||||
}
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error !== null);
|
|
||||||
do_check_true(download.error.becauseSourceFailed);
|
|
||||||
do_check_false(download.error.becauseTargetFailed);
|
|
||||||
} finally {
|
|
||||||
serverSocket.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures download error details are reported on local writing failures.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_error_target()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload();
|
|
||||||
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
// Create a file without write access permissions before downloading.
|
|
||||||
download.target.file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
yield download.start();
|
|
||||||
do_throw("The download should have failed.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error && ex.becauseTargetFailed) {
|
|
||||||
// A specific error object is thrown when writing to the target fails.
|
|
||||||
}
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error !== null);
|
|
||||||
do_check_true(download.error.becauseTargetFailed);
|
|
||||||
do_check_false(download.error.becauseSourceFailed);
|
|
||||||
} finally {
|
|
||||||
// Restore the default permissions to allow deleting the file on Windows.
|
|
||||||
if (download.target.file.exists()) {
|
|
||||||
download.target.file.permissions = FileUtils.PERMS_FILE;
|
|
||||||
download.target.file.remove(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restarts a failed download.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_error_restart()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload();
|
|
||||||
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
// Create a file without write access permissions before downloading.
|
|
||||||
download.target.file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
|
|
||||||
|
|
||||||
try {
|
|
||||||
yield download.start();
|
|
||||||
do_throw("The download should have failed.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error && ex.becauseTargetFailed) {
|
|
||||||
// A specific error object is thrown when writing to the target fails.
|
|
||||||
} finally {
|
|
||||||
// Restore the default permissions to allow deleting the file on Windows.
|
|
||||||
if (download.target.file.exists()) {
|
|
||||||
download.target.file.permissions = FileUtils.PERMS_FILE;
|
|
||||||
|
|
||||||
// Also for Windows, rename the file before deleting. This makes the
|
|
||||||
// current file name available immediately for a new file, while deleting
|
|
||||||
// in place prevents creation of a file with the same name for some time.
|
|
||||||
let fileToRemove = download.target.file.clone();
|
|
||||||
fileToRemove.moveTo(null, fileToRemove.leafName + ".delete.tmp");
|
|
||||||
fileToRemove.remove(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restart the download and wait for completion.
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file, TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes download in both public and private modes.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_public_and_private()
|
|
||||||
{
|
|
||||||
let source_path = "/test_download_public_and_private.txt";
|
|
||||||
let source_uri = NetUtil.newURI(HTTP_BASE + source_path);
|
|
||||||
let testCount = 0;
|
|
||||||
|
|
||||||
// Apply pref to allow all cookies.
|
|
||||||
Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
|
|
||||||
|
|
||||||
function cleanup() {
|
|
||||||
Services.prefs.clearUserPref("network.cookie.cookieBehavior");
|
|
||||||
Services.cookies.removeAll();
|
|
||||||
gHttpServer.registerPathHandler(source_path, null);
|
|
||||||
}
|
|
||||||
do_register_cleanup(cleanup);
|
|
||||||
|
|
||||||
gHttpServer.registerPathHandler(source_path, function (aRequest, aResponse) {
|
|
||||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
|
||||||
|
|
||||||
if (testCount == 0) {
|
|
||||||
// No cookies should exist for first public download.
|
|
||||||
do_check_false(aRequest.hasHeader("Cookie"));
|
|
||||||
aResponse.setHeader("Set-Cookie", "foobar=1", false);
|
|
||||||
testCount++;
|
|
||||||
} else if (testCount == 1) {
|
|
||||||
// The cookie should exists for second public download.
|
|
||||||
do_check_true(aRequest.hasHeader("Cookie"));
|
|
||||||
do_check_eq(aRequest.getHeader("Cookie"), "foobar=1");
|
|
||||||
testCount++;
|
|
||||||
} else if (testCount == 2) {
|
|
||||||
// No cookies should exist for first private download.
|
|
||||||
do_check_false(aRequest.hasHeader("Cookie"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
|
||||||
yield Downloads.simpleDownload(source_uri, targetFile);
|
|
||||||
yield Downloads.simpleDownload(source_uri, targetFile);
|
|
||||||
let download = yield Downloads.createDownload({
|
|
||||||
source: { uri: source_uri, isPrivate: true },
|
|
||||||
target: { file: targetFile },
|
|
||||||
saver: { type: "copy" },
|
|
||||||
});
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the startTime gets updated even after a restart.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_cancel_immediately_restart_and_check_startTime()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload();
|
|
||||||
|
|
||||||
download.start();
|
|
||||||
let startTime = download.startTime;
|
|
||||||
do_check_true(isValidDate(download.startTime));
|
|
||||||
|
|
||||||
yield download.cancel();
|
|
||||||
do_check_eq(download.startTime.getTime(), startTime.getTime());
|
|
||||||
|
|
||||||
// Wait for a timeout.
|
|
||||||
yield promiseTimeout(10);
|
|
||||||
|
|
||||||
yield download.start();
|
|
||||||
do_check_true(download.startTime.getTime() > startTime.getTime());
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes download with content-encoding.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_with_content_encoding()
|
|
||||||
{
|
|
||||||
let source_path = "/test_download_with_content_encoding.txt";
|
|
||||||
let source_uri = NetUtil.newURI(HTTP_BASE + source_path);
|
|
||||||
|
|
||||||
function cleanup() {
|
|
||||||
gHttpServer.registerPathHandler(source_path, null);
|
|
||||||
}
|
|
||||||
do_register_cleanup(cleanup);
|
|
||||||
|
|
||||||
gHttpServer.registerPathHandler(source_path, function (aRequest, aResponse) {
|
|
||||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
|
||||||
aResponse.setHeader("Content-Encoding", "gzip", false);
|
|
||||||
aResponse.setHeader("Content-Length",
|
|
||||||
"" + TEST_DATA_SHORT_GZIP_ENCODED.length, false);
|
|
||||||
|
|
||||||
let bos = new BinaryOutputStream(aResponse.bodyOutputStream);
|
|
||||||
bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED,
|
|
||||||
TEST_DATA_SHORT_GZIP_ENCODED.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
let download = yield Downloads.createDownload({
|
|
||||||
source: { uri: source_uri },
|
|
||||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
|
||||||
saver: { type: "copy" },
|
|
||||||
});
|
|
||||||
yield download.start();
|
|
||||||
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
|
|
||||||
|
|
||||||
// Ensure the content matches the decoded test data.
|
|
||||||
yield promiseVerifyContents(download.target.file, TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels and restarts a download sequentially with content-encoding.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_cancel_midway_restart_with_content_encoding()
|
|
||||||
{
|
|
||||||
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_GZIP_URI);
|
|
||||||
|
|
||||||
// The first time, cancel the download midway.
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
try {
|
|
||||||
let deferCancel = Promise.defer();
|
|
||||||
download.onchange = function () {
|
|
||||||
if (!download.stopped && !download.canceled &&
|
|
||||||
download.currentBytes == TEST_DATA_SHORT_GZIP_ENCODED_FIRST.length) {
|
|
||||||
deferCancel.resolve(download.cancel());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
download.start();
|
|
||||||
yield deferCancel.promise;
|
|
||||||
} finally {
|
|
||||||
deferResponse.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
|
|
||||||
// The second time, we'll provide the entire interruptible response.
|
|
||||||
download.onchange = null;
|
|
||||||
yield download.start()
|
|
||||||
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file, TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download with parental controls enabled.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_blocked_parental_controls()
|
|
||||||
{
|
|
||||||
function cleanup() {
|
|
||||||
DownloadIntegration.shouldBlockInTest = false;
|
|
||||||
}
|
|
||||||
do_register_cleanup(cleanup);
|
|
||||||
DownloadIntegration.shouldBlockInTest = true;
|
|
||||||
|
|
||||||
let download = yield promiseSimpleDownload();
|
|
||||||
|
|
||||||
try {
|
|
||||||
yield download.start();
|
|
||||||
do_throw("The download should have blocked.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error && ex.becauseBlocked) {
|
|
||||||
do_check_true(ex.becauseBlockedByParentalControls);
|
|
||||||
}
|
|
||||||
cleanup();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
let scriptFile = do_get_file("common_test_Download.js");
|
||||||
|
Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
|
||||||
|
@ -10,370 +10,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Globals
|
//// Execution of common tests
|
||||||
|
|
||||||
/**
|
let gUseLegacySaver = true;
|
||||||
* Starts a new download using the nsIWebBrowserPersist interface, and controls
|
|
||||||
* it using the legacy nsITransfer interface.
|
|
||||||
*
|
|
||||||
* @param aSourceURI
|
|
||||||
* The nsIURI for the download source, or null to use TEST_SOURCE_URI.
|
|
||||||
* @param isPrivate
|
|
||||||
* Optional boolean indicates whether the download originated from a
|
|
||||||
* private window.
|
|
||||||
* @param aOutPersist
|
|
||||||
* Optional object that receives a reference to the created
|
|
||||||
* nsIWebBrowserPersist instance in the "value" property.
|
|
||||||
*
|
|
||||||
* @return {Promise}
|
|
||||||
* @resolves The Download object created as a consequence of controlling the
|
|
||||||
* download through the legacy nsITransfer interface.
|
|
||||||
* @rejects Never. The current test fails in case of exceptions.
|
|
||||||
*/
|
|
||||||
function promiseStartLegacyDownload(aSourceURI, aIsPrivate, aOutPersist) {
|
|
||||||
let sourceURI = aSourceURI || TEST_SOURCE_URI;
|
|
||||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
|
||||||
|
|
||||||
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
|
let scriptFile = do_get_file("common_test_Download.js");
|
||||||
.createInstance(Ci.nsIWebBrowserPersist);
|
Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
|
||||||
|
|
||||||
// We must create the nsITransfer implementation using its class ID because
|
|
||||||
// the "@mozilla.org/transfer;1" contract is currently implemented in
|
|
||||||
// "toolkit/components/downloads". When the other folder is not included in
|
|
||||||
// builds anymore (bug 851471), we'll be able to use the contract ID.
|
|
||||||
let transfer =
|
|
||||||
Components.classesByID["{1b4c85df-cbdd-4bb6-b04e-613caece083c}"]
|
|
||||||
.createInstance(Ci.nsITransfer);
|
|
||||||
|
|
||||||
if (aOutPersist) {
|
|
||||||
aOutPersist.value = persist;
|
|
||||||
}
|
|
||||||
|
|
||||||
let deferred = Promise.defer();
|
|
||||||
let promise = aIsPrivate ? Downloads.getPrivateDownloadList() :
|
|
||||||
Downloads.getPublicDownloadList();
|
|
||||||
promise.then(function (aList) {
|
|
||||||
// Temporarily register a view that will get notified when the download we
|
|
||||||
// are controlling becomes visible in the list of public downloads.
|
|
||||||
aList.addView({
|
|
||||||
onDownloadAdded: function (aDownload) {
|
|
||||||
aList.removeView(this);
|
|
||||||
|
|
||||||
// Remove the download to keep the list empty for the next test. This
|
|
||||||
// also allows the caller to register the "onchange" event directly.
|
|
||||||
aList.remove(aDownload);
|
|
||||||
|
|
||||||
// When the download object is ready, make it available to the caller.
|
|
||||||
deferred.resolve(aDownload);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize the components so they reference each other. This will cause
|
|
||||||
// the Download object to be created and added to the public downloads.
|
|
||||||
transfer.init(sourceURI, NetUtil.newURI(targetFile), null, null, null, null,
|
|
||||||
persist, aIsPrivate);
|
|
||||||
persist.progressListener = transfer;
|
|
||||||
|
|
||||||
// Start the actual download process.
|
|
||||||
persist.savePrivacyAwareURI(sourceURI, null, null, null, null, targetFile, aIsPrivate);
|
|
||||||
}.bind(this)).then(null, do_report_unexpected_exception);
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//// Tests
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a download controlled by the legacy nsITransfer interface.
|
|
||||||
*/
|
|
||||||
add_task(function test_basic()
|
|
||||||
{
|
|
||||||
let tempDirectory = FileUtils.getDir("TmpD", []);
|
|
||||||
|
|
||||||
let download = yield promiseStartLegacyDownload();
|
|
||||||
|
|
||||||
// Checks the generated DownloadSource and DownloadTarget properties.
|
|
||||||
do_check_true(download.source.uri.equals(TEST_SOURCE_URI));
|
|
||||||
do_check_true(download.target.file.parent.equals(tempDirectory));
|
|
||||||
|
|
||||||
// The download is already started, wait for completion and report any errors.
|
|
||||||
if (!download.stopped) {
|
|
||||||
yield download.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file, TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks final state and progress for a successful download.
|
|
||||||
*/
|
|
||||||
add_task(function test_final_state()
|
|
||||||
{
|
|
||||||
let download = yield promiseStartLegacyDownload();
|
|
||||||
|
|
||||||
// The download is already started, wait for completion and report any errors.
|
|
||||||
if (!download.stopped) {
|
|
||||||
yield download.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.succeeded);
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks intermediate progress for a successful download.
|
|
||||||
*/
|
|
||||||
add_task(function test_intermediate_progress()
|
|
||||||
{
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
|
|
||||||
let download = yield promiseStartLegacyDownload(TEST_INTERRUPTIBLE_URI);
|
|
||||||
|
|
||||||
let onchange = function () {
|
|
||||||
if (download.progress == 50) {
|
|
||||||
do_check_true(download.hasProgress);
|
|
||||||
do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
|
|
||||||
do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
|
|
||||||
|
|
||||||
// Continue after the first chunk of data is fully received.
|
|
||||||
deferResponse.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register for the notification, but also call the function directly in case
|
|
||||||
// the download already reached the expected progress.
|
|
||||||
download.onchange = onchange;
|
|
||||||
onchange();
|
|
||||||
|
|
||||||
// The download is already started, wait for completion and report any errors.
|
|
||||||
if (!download.stopped) {
|
|
||||||
yield download.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
|
|
||||||
yield promiseVerifyContents(download.target.file,
|
|
||||||
TEST_DATA_SHORT + TEST_DATA_SHORT);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads a file with a "Content-Length" of 0 and checks the progress.
|
|
||||||
*/
|
|
||||||
add_task(function test_empty_progress()
|
|
||||||
{
|
|
||||||
let download = yield promiseStartLegacyDownload(TEST_EMPTY_URI);
|
|
||||||
|
|
||||||
// The download is already started, wait for completion and report any errors.
|
|
||||||
if (!download.stopped) {
|
|
||||||
yield download.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.hasProgress);
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
|
|
||||||
do_check_eq(download.target.file.fileSize, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads an empty file with no "Content-Length" and checks the progress.
|
|
||||||
*/
|
|
||||||
add_task(function test_empty_noprogress()
|
|
||||||
{
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
let promiseEmptyRequestReceived = promiseNextRequestReceived();
|
|
||||||
|
|
||||||
let download = yield promiseStartLegacyDownload(TEST_EMPTY_NOPROGRESS_URI);
|
|
||||||
|
|
||||||
// Wait for the request to be received by the HTTP server, but don't allow the
|
|
||||||
// request to finish yet. Before checking the download state, wait for the
|
|
||||||
// events to be processed by the client.
|
|
||||||
yield promiseEmptyRequestReceived;
|
|
||||||
yield promiseExecuteSoon();
|
|
||||||
|
|
||||||
// Check that this download has no progress report.
|
|
||||||
do_check_false(download.stopped);
|
|
||||||
do_check_false(download.hasProgress);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
|
|
||||||
// Now allow the response to finish, and wait for the download to complete,
|
|
||||||
// while reporting any errors that may occur.
|
|
||||||
deferResponse.resolve();
|
|
||||||
if (!download.stopped) {
|
|
||||||
yield download.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the state of the completed download.
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_false(download.hasProgress);
|
|
||||||
do_check_eq(download.progress, 100);
|
|
||||||
do_check_eq(download.currentBytes, 0);
|
|
||||||
do_check_eq(download.totalBytes, 0);
|
|
||||||
|
|
||||||
do_check_eq(download.target.file.fileSize, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels a download and verifies that its state is reported correctly.
|
|
||||||
*/
|
|
||||||
add_task(function test_cancel_midway()
|
|
||||||
{
|
|
||||||
let deferResponse = deferNextResponse();
|
|
||||||
let outPersist = {};
|
|
||||||
let download = yield promiseStartLegacyDownload(TEST_INTERRUPTIBLE_URI, false,
|
|
||||||
outPersist);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Cancel the download after receiving the first part of the response.
|
|
||||||
let deferCancel = Promise.defer();
|
|
||||||
let onchange = function () {
|
|
||||||
if (!download.stopped && !download.canceled && download.progress == 50) {
|
|
||||||
deferCancel.resolve(download.cancel());
|
|
||||||
|
|
||||||
// The state change happens immediately after calling "cancel", but
|
|
||||||
// temporary files or part files may still exist at this point.
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register for the notification, but also call the function directly in
|
|
||||||
// case the download already reached the expected progress.
|
|
||||||
download.onchange = onchange;
|
|
||||||
onchange();
|
|
||||||
|
|
||||||
// Wait on the promise returned by the "cancel" method to ensure that the
|
|
||||||
// cancellation process finished and temporary files were removed.
|
|
||||||
yield deferCancel.promise;
|
|
||||||
|
|
||||||
// The nsIWebBrowserPersist instance should have been canceled now.
|
|
||||||
do_check_eq(outPersist.value.result, Cr.NS_ERROR_ABORT);
|
|
||||||
|
|
||||||
do_check_true(download.stopped);
|
|
||||||
do_check_true(download.canceled);
|
|
||||||
do_check_true(download.error === null);
|
|
||||||
|
|
||||||
do_check_false(download.target.file.exists());
|
|
||||||
|
|
||||||
// Progress properties are not reset by canceling.
|
|
||||||
do_check_eq(download.progress, 50);
|
|
||||||
do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
|
|
||||||
do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
|
|
||||||
} finally {
|
|
||||||
deferResponse.resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures download error details are reported for legacy downloads.
|
|
||||||
*/
|
|
||||||
add_task(function test_error()
|
|
||||||
{
|
|
||||||
let serverSocket = startFakeServer();
|
|
||||||
try {
|
|
||||||
let download = yield promiseStartLegacyDownload(TEST_FAKE_SOURCE_URI);
|
|
||||||
|
|
||||||
// We must check the download properties instead of calling the "start"
|
|
||||||
// method because the download has been started and may already be stopped.
|
|
||||||
let deferStopped = Promise.defer();
|
|
||||||
let onchange = function () {
|
|
||||||
if (download.stopped) {
|
|
||||||
deferStopped.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
download.onchange = onchange;
|
|
||||||
onchange();
|
|
||||||
yield deferStopped.promise;
|
|
||||||
|
|
||||||
// Check the properties now that the download stopped.
|
|
||||||
do_check_false(download.canceled);
|
|
||||||
do_check_true(download.error !== null);
|
|
||||||
do_check_true(download.error.becauseSourceFailed);
|
|
||||||
do_check_false(download.error.becauseTargetFailed);
|
|
||||||
} finally {
|
|
||||||
serverSocket.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes download in both public and private modes.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_public_and_private()
|
|
||||||
{
|
|
||||||
let source_path = "/test_download_public_and_private.txt";
|
|
||||||
let source_uri = NetUtil.newURI(HTTP_BASE + source_path);
|
|
||||||
let testCount = 0;
|
|
||||||
|
|
||||||
// Apply pref to allow all cookies.
|
|
||||||
Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
|
|
||||||
|
|
||||||
function cleanup() {
|
|
||||||
Services.prefs.clearUserPref("network.cookie.cookieBehavior");
|
|
||||||
Services.cookies.removeAll();
|
|
||||||
gHttpServer.registerPathHandler(source_path, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_register_cleanup(cleanup);
|
|
||||||
|
|
||||||
gHttpServer.registerPathHandler(source_path, function (aRequest, aResponse) {
|
|
||||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
|
||||||
|
|
||||||
if (testCount == 0) {
|
|
||||||
// No cookies should exist for first public download.
|
|
||||||
do_check_false(aRequest.hasHeader("Cookie"));
|
|
||||||
aResponse.setHeader("Set-Cookie", "foobar=1", false);
|
|
||||||
testCount++;
|
|
||||||
} else if (testCount == 1) {
|
|
||||||
// The cookie should exists for second public download.
|
|
||||||
do_check_true(aRequest.hasHeader("Cookie"));
|
|
||||||
do_check_eq(aRequest.getHeader("Cookie"), "foobar=1");
|
|
||||||
testCount++;
|
|
||||||
} else if (testCount == 2) {
|
|
||||||
// No cookies should exist for first private download.
|
|
||||||
do_check_false(aRequest.hasHeader("Cookie"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
|
||||||
yield Downloads.simpleDownload(source_uri, targetFile);
|
|
||||||
yield Downloads.simpleDownload(source_uri, targetFile);
|
|
||||||
let download = yield promiseStartLegacyDownload(source_uri, true);
|
|
||||||
// The download is already started, wait for completion and report any errors.
|
|
||||||
if (!download.stopped) {
|
|
||||||
yield download.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download with parental controls enabled.
|
|
||||||
*/
|
|
||||||
add_task(function test_download_blocked_parental_controls()
|
|
||||||
{
|
|
||||||
function cleanup() {
|
|
||||||
DownloadIntegration.shouldBlockInTest = false;
|
|
||||||
}
|
|
||||||
do_register_cleanup(cleanup);
|
|
||||||
DownloadIntegration.shouldBlockInTest = true;
|
|
||||||
|
|
||||||
let download = yield promiseStartLegacyDownload();
|
|
||||||
|
|
||||||
try {
|
|
||||||
yield download.start();
|
|
||||||
do_throw("The download should have blocked.");
|
|
||||||
} catch (ex if ex instanceof Downloads.Error && ex.becauseBlocked) {
|
|
||||||
do_check_true(ex.becauseBlockedByParentalControls);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_check_false(download.target.file.exists());
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
});
|
|
||||||
|
@ -34,14 +34,14 @@ add_task(function test_add_getAll()
|
|||||||
{
|
{
|
||||||
let list = yield promiseNewDownloadList();
|
let list = yield promiseNewDownloadList();
|
||||||
|
|
||||||
let downloadOne = yield promiseSimpleDownload();
|
let downloadOne = yield promiseNewDownload();
|
||||||
list.add(downloadOne);
|
list.add(downloadOne);
|
||||||
|
|
||||||
let itemsOne = yield list.getAll();
|
let itemsOne = yield list.getAll();
|
||||||
do_check_eq(itemsOne.length, 1);
|
do_check_eq(itemsOne.length, 1);
|
||||||
do_check_eq(itemsOne[0], downloadOne);
|
do_check_eq(itemsOne[0], downloadOne);
|
||||||
|
|
||||||
let downloadTwo = yield promiseSimpleDownload();
|
let downloadTwo = yield promiseNewDownload();
|
||||||
list.add(downloadTwo);
|
list.add(downloadTwo);
|
||||||
|
|
||||||
let itemsTwo = yield list.getAll();
|
let itemsTwo = yield list.getAll();
|
||||||
@ -60,14 +60,14 @@ add_task(function test_remove()
|
|||||||
{
|
{
|
||||||
let list = yield promiseNewDownloadList();
|
let list = yield promiseNewDownloadList();
|
||||||
|
|
||||||
list.add(yield promiseSimpleDownload());
|
list.add(yield promiseNewDownload());
|
||||||
list.add(yield promiseSimpleDownload());
|
list.add(yield promiseNewDownload());
|
||||||
|
|
||||||
let items = yield list.getAll();
|
let items = yield list.getAll();
|
||||||
list.remove(items[0]);
|
list.remove(items[0]);
|
||||||
|
|
||||||
// Removing an item that was never added should not raise an error.
|
// Removing an item that was never added should not raise an error.
|
||||||
list.remove(yield promiseSimpleDownload());
|
list.remove(yield promiseNewDownload());
|
||||||
|
|
||||||
items = yield list.getAll();
|
items = yield list.getAll();
|
||||||
do_check_eq(items.length, 1);
|
do_check_eq(items.length, 1);
|
||||||
@ -81,8 +81,8 @@ add_task(function test_notifications_add_remove()
|
|||||||
{
|
{
|
||||||
let list = yield promiseNewDownloadList();
|
let list = yield promiseNewDownloadList();
|
||||||
|
|
||||||
let downloadOne = yield promiseSimpleDownload();
|
let downloadOne = yield promiseNewDownload();
|
||||||
let downloadTwo = yield promiseSimpleDownload();
|
let downloadTwo = yield promiseNewDownload();
|
||||||
list.add(downloadOne);
|
list.add(downloadOne);
|
||||||
list.add(downloadTwo);
|
list.add(downloadTwo);
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ add_task(function test_notifications_add_remove()
|
|||||||
do_check_eq(addNotifications, 2);
|
do_check_eq(addNotifications, 2);
|
||||||
|
|
||||||
// Check that we receive add notifications for new elements.
|
// Check that we receive add notifications for new elements.
|
||||||
list.add(yield promiseSimpleDownload());
|
list.add(yield promiseNewDownload());
|
||||||
do_check_eq(addNotifications, 3);
|
do_check_eq(addNotifications, 3);
|
||||||
|
|
||||||
// Check that we receive remove notifications.
|
// Check that we receive remove notifications.
|
||||||
@ -125,7 +125,7 @@ add_task(function test_notifications_add_remove()
|
|||||||
|
|
||||||
// We should not receive add notifications after the view is removed.
|
// We should not receive add notifications after the view is removed.
|
||||||
list.removeView(viewOne);
|
list.removeView(viewOne);
|
||||||
list.add(yield promiseSimpleDownload());
|
list.add(yield promiseNewDownload());
|
||||||
do_check_eq(addNotifications, 3);
|
do_check_eq(addNotifications, 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -136,8 +136,8 @@ add_task(function test_notifications_change()
|
|||||||
{
|
{
|
||||||
let list = yield promiseNewDownloadList();
|
let list = yield promiseNewDownloadList();
|
||||||
|
|
||||||
let downloadOne = yield promiseSimpleDownload();
|
let downloadOne = yield promiseNewDownload();
|
||||||
let downloadTwo = yield promiseSimpleDownload();
|
let downloadTwo = yield promiseNewDownload();
|
||||||
list.add(downloadOne);
|
list.add(downloadOne);
|
||||||
list.add(downloadTwo);
|
list.add(downloadTwo);
|
||||||
|
|
||||||
@ -174,11 +174,11 @@ add_task(function test_history_expiration()
|
|||||||
|
|
||||||
// Add expirable visit for downloads.
|
// Add expirable visit for downloads.
|
||||||
yield promiseAddDownloadToHistory();
|
yield promiseAddDownloadToHistory();
|
||||||
yield promiseAddDownloadToHistory(TEST_INTERRUPTIBLE_URI);
|
yield promiseAddDownloadToHistory(httpUrl("interruptible.txt"));
|
||||||
|
|
||||||
let list = yield promiseNewDownloadList();
|
let list = yield promiseNewDownloadList();
|
||||||
let downloadOne = yield promiseSimpleDownload();
|
let downloadOne = yield promiseNewDownload();
|
||||||
let downloadTwo = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
let downloadTwo = yield promiseNewDownload(httpUrl("interruptible.txt"));
|
||||||
list.add(downloadOne);
|
list.add(downloadOne);
|
||||||
list.add(downloadTwo);
|
list.add(downloadTwo);
|
||||||
|
|
||||||
@ -221,8 +221,8 @@ add_task(function test_history_clear()
|
|||||||
yield promiseAddDownloadToHistory();
|
yield promiseAddDownloadToHistory();
|
||||||
|
|
||||||
let list = yield promiseNewDownloadList();
|
let list = yield promiseNewDownloadList();
|
||||||
let downloadOne = yield promiseSimpleDownload();
|
let downloadOne = yield promiseNewDownload();
|
||||||
let downloadTwo = yield promiseSimpleDownload();
|
let downloadTwo = yield promiseNewDownload();
|
||||||
list.add(downloadOne);
|
list.add(downloadOne);
|
||||||
list.add(downloadTwo);
|
list.add(downloadTwo);
|
||||||
|
|
||||||
|
@ -49,12 +49,11 @@ add_task(function test_save_reload()
|
|||||||
let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
|
let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
|
||||||
storeForSave.path);
|
storeForSave.path);
|
||||||
|
|
||||||
listForSave.add(yield promiseSimpleDownload(TEST_SOURCE_URI));
|
listForSave.add(yield promiseNewDownload(httpUrl("source.txt")));
|
||||||
listForSave.add(yield Downloads.createDownload({
|
listForSave.add(yield Downloads.createDownload({
|
||||||
source: { uri: TEST_EMPTY_URI,
|
source: { url: httpUrl("empty.txt"),
|
||||||
referrer: TEST_REFERRER_URI },
|
referrer: TEST_REFERRER_URL },
|
||||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
target: getTempFile(TEST_TARGET_FILE_NAME),
|
||||||
saver: { type: "copy" },
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
yield storeForSave.save();
|
yield storeForSave.save();
|
||||||
@ -71,16 +70,12 @@ add_task(function test_save_reload()
|
|||||||
do_check_neq(itemsForSave[i], itemsForLoad[i]);
|
do_check_neq(itemsForSave[i], itemsForLoad[i]);
|
||||||
|
|
||||||
// The reloaded downloads have the same properties.
|
// The reloaded downloads have the same properties.
|
||||||
do_check_true(itemsForSave[i].source.uri.equals(
|
do_check_eq(itemsForSave[i].source.url,
|
||||||
itemsForLoad[i].source.uri));
|
itemsForLoad[i].source.url);
|
||||||
if (itemsForSave[i].source.referrer) {
|
do_check_eq(itemsForSave[i].source.referrer,
|
||||||
do_check_true(itemsForSave[i].source.referrer.equals(
|
itemsForLoad[i].source.referrer);
|
||||||
itemsForLoad[i].source.referrer));
|
do_check_eq(itemsForSave[i].target.path,
|
||||||
} else {
|
itemsForLoad[i].target.path);
|
||||||
do_check_true(itemsForLoad[i].source.referrer === null);
|
|
||||||
}
|
|
||||||
do_check_true(itemsForSave[i].target.file.equals(
|
|
||||||
itemsForLoad[i].target.file));
|
|
||||||
do_check_eq(itemsForSave[i].saver.type,
|
do_check_eq(itemsForSave[i].saver.type,
|
||||||
itemsForLoad[i].saver.type);
|
itemsForLoad[i].saver.type);
|
||||||
}
|
}
|
||||||
@ -129,19 +124,17 @@ add_task(function test_load_string_predefined()
|
|||||||
let [list, store] = yield promiseNewListAndStore();
|
let [list, store] = yield promiseNewListAndStore();
|
||||||
|
|
||||||
// The platform-dependent file name should be generated dynamically.
|
// The platform-dependent file name should be generated dynamically.
|
||||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||||
let filePathLiteral = JSON.stringify(targetFile.path);
|
let filePathLiteral = JSON.stringify(targetPath);
|
||||||
let sourceUriLiteral = JSON.stringify(TEST_SOURCE_URI.spec);
|
let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
|
||||||
let emptyUriLiteral = JSON.stringify(TEST_EMPTY_URI.spec);
|
let emptyUriLiteral = JSON.stringify(httpUrl("empty.txt"));
|
||||||
let referrerUriLiteral = JSON.stringify(TEST_REFERRER_URI.spec);
|
let referrerUriLiteral = JSON.stringify(TEST_REFERRER_URL);
|
||||||
|
|
||||||
let string = "[{\"source\":{\"uri\":" + sourceUriLiteral + "}," +
|
let string = "{\"list\":[{\"source\":" + sourceUriLiteral + "," +
|
||||||
"\"target\":{\"file\":" + filePathLiteral + "}," +
|
"\"target\":" + filePathLiteral + "}," +
|
||||||
"\"saver\":{\"type\":\"copy\"}}," +
|
"{\"source\":{\"url\":" + emptyUriLiteral + "," +
|
||||||
"{\"source\":{\"uri\":" + emptyUriLiteral + "," +
|
|
||||||
"\"referrer\":" + referrerUriLiteral + "}," +
|
"\"referrer\":" + referrerUriLiteral + "}," +
|
||||||
"\"target\":{\"file\":" + filePathLiteral + "}," +
|
"\"target\":" + filePathLiteral + "}]}";
|
||||||
"\"saver\":{\"type\":\"copy\"}}]";
|
|
||||||
|
|
||||||
yield OS.File.writeAtomic(store.path,
|
yield OS.File.writeAtomic(store.path,
|
||||||
new TextEncoder().encode(string),
|
new TextEncoder().encode(string),
|
||||||
@ -153,12 +146,12 @@ add_task(function test_load_string_predefined()
|
|||||||
|
|
||||||
do_check_eq(items.length, 2);
|
do_check_eq(items.length, 2);
|
||||||
|
|
||||||
do_check_true(items[0].source.uri.equals(TEST_SOURCE_URI));
|
do_check_eq(items[0].source.url, httpUrl("source.txt"));
|
||||||
do_check_true(items[0].target.file.equals(targetFile));
|
do_check_eq(items[0].target.path, targetPath);
|
||||||
|
|
||||||
do_check_true(items[1].source.uri.equals(TEST_EMPTY_URI));
|
do_check_eq(items[1].source.url, httpUrl("empty.txt"));
|
||||||
do_check_true(items[1].source.referrer.equals(TEST_REFERRER_URI));
|
do_check_eq(items[1].source.referrer, TEST_REFERRER_URL);
|
||||||
do_check_true(items[1].target.file.equals(targetFile));
|
do_check_eq(items[1].target.path, targetPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,15 +162,15 @@ add_task(function test_load_string_unrecognized()
|
|||||||
let [list, store] = yield promiseNewListAndStore();
|
let [list, store] = yield promiseNewListAndStore();
|
||||||
|
|
||||||
// The platform-dependent file name should be generated dynamically.
|
// The platform-dependent file name should be generated dynamically.
|
||||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||||
let filePathLiteral = JSON.stringify(targetFile.path);
|
let filePathLiteral = JSON.stringify(targetPath);
|
||||||
let sourceUriLiteral = JSON.stringify(TEST_SOURCE_URI.spec);
|
let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
|
||||||
|
|
||||||
let string = "[{\"source\":null," +
|
let string = "{\"list\":[{\"source\":null," +
|
||||||
"\"target\":null}," +
|
"\"target\":null}," +
|
||||||
"{\"source\":{\"uri\":" + sourceUriLiteral + "}," +
|
"{\"source\":{\"url\":" + sourceUriLiteral + "}," +
|
||||||
"\"target\":{\"file\":" + filePathLiteral + "}," +
|
"\"target\":{\"path\":" + filePathLiteral + "}," +
|
||||||
"\"saver\":{\"type\":\"copy\"}}]";
|
"\"saver\":{\"type\":\"copy\"}}]}";
|
||||||
|
|
||||||
yield OS.File.writeAtomic(store.path,
|
yield OS.File.writeAtomic(store.path,
|
||||||
new TextEncoder().encode(string),
|
new TextEncoder().encode(string),
|
||||||
@ -189,8 +182,8 @@ add_task(function test_load_string_unrecognized()
|
|||||||
|
|
||||||
do_check_eq(items.length, 1);
|
do_check_eq(items.length, 1);
|
||||||
|
|
||||||
do_check_true(items[0].source.uri.equals(TEST_SOURCE_URI));
|
do_check_eq(items[0].source.url, httpUrl("source.txt"));
|
||||||
do_check_true(items[0].target.file.equals(targetFile));
|
do_check_eq(items[0].target.path, targetPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,8 +193,8 @@ add_task(function test_load_string_malformed()
|
|||||||
{
|
{
|
||||||
let [list, store] = yield promiseNewListAndStore();
|
let [list, store] = yield promiseNewListAndStore();
|
||||||
|
|
||||||
let string = "[{\"source\":null,\"target\":null}," +
|
let string = "{\"list\":[{\"source\":null,\"target\":null}," +
|
||||||
"{\"source\":{\"uri\":\"about:blank\"}}";
|
"{\"source\":{\"url\":\"about:blank\"}}}";
|
||||||
|
|
||||||
yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
|
yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
|
||||||
{ tmpPath: store.path + ".tmp" });
|
{ tmpPath: store.path + ".tmp" });
|
||||||
|
@ -20,21 +20,20 @@ add_task(function test_createDownload()
|
|||||||
{
|
{
|
||||||
// Creates a simple Download object without starting the download.
|
// Creates a simple Download object without starting the download.
|
||||||
yield Downloads.createDownload({
|
yield Downloads.createDownload({
|
||||||
source: { uri: NetUtil.newURI("about:blank") },
|
source: { url: "about:blank" },
|
||||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
|
||||||
saver: { type: "copy" },
|
saver: { type: "copy" },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests createDownload for private download.
|
* Tests createDownload for private download.
|
||||||
*/
|
*/
|
||||||
add_task(function test_createDownload_private()
|
add_task(function test_createDownload_private()
|
||||||
{
|
{
|
||||||
let download = yield Downloads.createDownload({
|
let download = yield Downloads.createDownload({
|
||||||
source: { uri: NetUtil.newURI("about:blank"),
|
source: { url: "about:blank", isPrivate: true },
|
||||||
isPrivate: true },
|
target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
|
||||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
|
||||||
saver: { type: "copy" }
|
saver: { type: "copy" }
|
||||||
});
|
});
|
||||||
do_check_true(download.source.isPrivate);
|
do_check_true(download.source.isPrivate);
|
||||||
@ -45,21 +44,20 @@ add_task(function test_createDownload_private()
|
|||||||
*/
|
*/
|
||||||
add_task(function test_createDownload_public()
|
add_task(function test_createDownload_public()
|
||||||
{
|
{
|
||||||
let uri = NetUtil.newURI("about:blank");
|
let tempPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||||
let tempFile = getTempFile(TEST_TARGET_FILE_NAME);
|
|
||||||
let download = yield Downloads.createDownload({
|
let download = yield Downloads.createDownload({
|
||||||
source: { uri: uri, isPrivate: false },
|
source: { url: "about:blank", isPrivate: false },
|
||||||
target: { file: tempFile },
|
target: { path: tempPath },
|
||||||
saver: { type: "copy" }
|
saver: { type: "copy" }
|
||||||
});
|
});
|
||||||
do_check_false(download.source.isPrivate);
|
do_check_false(download.source.isPrivate);
|
||||||
|
|
||||||
download = yield Downloads.createDownload({
|
download = yield Downloads.createDownload({
|
||||||
source: { uri: uri },
|
source: { url: "about:blank" },
|
||||||
target: { file: tempFile },
|
target: { path: tempPath },
|
||||||
saver: { type: "copy" }
|
saver: { type: "copy" }
|
||||||
});
|
});
|
||||||
do_check_true(!download.source.isPrivate);
|
do_check_false(download.source.isPrivate);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,8 +66,9 @@ add_task(function test_createDownload_public()
|
|||||||
add_task(function test_simpleDownload_uri_file_arguments()
|
add_task(function test_simpleDownload_uri_file_arguments()
|
||||||
{
|
{
|
||||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||||
yield Downloads.simpleDownload(TEST_SOURCE_URI, targetFile);
|
yield Downloads.simpleDownload(NetUtil.newURI(httpUrl("source.txt")),
|
||||||
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
|
targetFile);
|
||||||
|
yield promiseVerifyContents(targetFile.path, TEST_DATA_SHORT);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,10 +76,10 @@ add_task(function test_simpleDownload_uri_file_arguments()
|
|||||||
*/
|
*/
|
||||||
add_task(function test_simpleDownload_object_arguments()
|
add_task(function test_simpleDownload_object_arguments()
|
||||||
{
|
{
|
||||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||||
yield Downloads.simpleDownload({ uri: TEST_SOURCE_URI },
|
yield Downloads.simpleDownload({ url: httpUrl("source.txt") },
|
||||||
{ file: targetFile });
|
{ path: targetPath });
|
||||||
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
|
yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,15 +87,15 @@ add_task(function test_simpleDownload_object_arguments()
|
|||||||
*/
|
*/
|
||||||
add_task(function test_simpleDownload_string_arguments()
|
add_task(function test_simpleDownload_string_arguments()
|
||||||
{
|
{
|
||||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||||
yield Downloads.simpleDownload(TEST_SOURCE_URI.spec,
|
yield Downloads.simpleDownload(httpUrl("source.txt"),
|
||||||
targetFile.path);
|
targetPath);
|
||||||
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
|
yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
|
||||||
|
|
||||||
targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||||
yield Downloads.simpleDownload(new String(TEST_SOURCE_URI.spec),
|
yield Downloads.simpleDownload(new String(httpUrl("source.txt")),
|
||||||
new String(targetFile.path));
|
new String(targetPath));
|
||||||
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
|
yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user