mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to birch.
This commit is contained in:
commit
6522fca953
@ -728,18 +728,6 @@ const gFormSubmitObserver = {
|
||||
|
||||
var gBrowserInit = {
|
||||
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");
|
||||
|
||||
var mustLoadSidebar = false;
|
||||
@ -780,6 +768,7 @@ var gBrowserInit = {
|
||||
new nsBrowserAccess();
|
||||
|
||||
// set default character set if provided
|
||||
// window.arguments[1]: character set (string)
|
||||
if ("arguments" in window && window.arguments.length > 1 && window.arguments[1]) {
|
||||
if (window.arguments[1].startsWith("charset=")) {
|
||||
var arrayArgComponents = window.arguments[1].split("=");
|
||||
@ -946,7 +935,7 @@ var gBrowserInit = {
|
||||
retrieveToolbarIconsizesFromTheme();
|
||||
|
||||
// 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);
|
||||
|
||||
this._loadHandled = true;
|
||||
@ -957,7 +946,7 @@ var gBrowserInit = {
|
||||
this._boundDelayedStartup = null;
|
||||
},
|
||||
|
||||
_delayedStartup: function(uriToLoad, mustLoadSidebar) {
|
||||
_delayedStartup: function(mustLoadSidebar) {
|
||||
let tmp = {};
|
||||
Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", tmp);
|
||||
let TelemetryTimestamps = tmp.TelemetryTimestamps;
|
||||
@ -976,6 +965,7 @@ var gBrowserInit = {
|
||||
socialBrowser.addEventListener("MozApplicationManifest",
|
||||
OfflineApps, false);
|
||||
|
||||
let uriToLoad = this._getUriToLoad();
|
||||
var isLoadingBlank = isBlankPageURL(uriToLoad);
|
||||
|
||||
// This pageshow listener needs to be registered before we may call
|
||||
@ -1012,6 +1002,9 @@ var gBrowserInit = {
|
||||
|
||||
gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);
|
||||
}
|
||||
// window.arguments[2]: referrer (nsIURI)
|
||||
// [3]: postData (nsIInputStream)
|
||||
// [4]: allowThirdPartyFixup (bool)
|
||||
else if (window.arguments.length >= 3) {
|
||||
loadURI(uriToLoad, window.arguments[2], window.arguments[3] || null,
|
||||
window.arguments[4] || false);
|
||||
@ -1293,6 +1286,31 @@ var gBrowserInit = {
|
||||
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() {
|
||||
// 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
|
||||
|
@ -10,7 +10,7 @@
|
||||
* - 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
|
||||
{
|
||||
/**
|
||||
@ -23,10 +23,24 @@ interface nsISessionStartup: nsISupports
|
||||
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();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* NO_SESSION There is no data available from the previous session
|
||||
|
@ -162,15 +162,6 @@ SessionStartup.prototype = {
|
||||
else
|
||||
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);
|
||||
|
||||
if (this._sessionType != Ci.nsISessionStartup.NO_SESSION)
|
||||
@ -204,14 +195,6 @@ SessionStartup.prototype = {
|
||||
if (this._sessionType != Ci.nsISessionStartup.NO_SESSION)
|
||||
Services.obs.removeObserver(this, "browser:purge-session-history");
|
||||
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":
|
||||
Services.obs.removeObserver(this, "sessionstore-windows-restored");
|
||||
// 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 ................*/
|
||||
|
||||
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
|
||||
*/
|
||||
doRestore: function sss_doRestore() {
|
||||
this._ensureInitialized();
|
||||
return this._willRestore();
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether there is a pending session restore.
|
||||
* @returns bool
|
||||
*/
|
||||
_willRestore: function () {
|
||||
return this._sessionType == Ci.nsISessionStartup.RECOVER_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.
|
||||
*/
|
||||
|
@ -18,7 +18,7 @@ const DEFAULT_UA = Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||
const MAX_OVERRIDE_FOR_HOST_CACHE_SIZE = 250;
|
||||
|
||||
var gPrefBranch;
|
||||
var gOverrides;
|
||||
var gOverrides = new Map;
|
||||
var gOverrideForHostCache = new Map;
|
||||
var gInitialized = false;
|
||||
var gOverrideFunctions = [
|
||||
@ -63,10 +63,10 @@ this.UserAgentOverrides = {
|
||||
|
||||
override = null;
|
||||
|
||||
for (let domain in gOverrides) {
|
||||
for (let [domain, userAgent] of gOverrides) {
|
||||
if (host == domain ||
|
||||
host.endsWith("." + domain)) {
|
||||
override = gOverrides[domain];
|
||||
override = userAgent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -93,23 +93,30 @@ this.UserAgentOverrides = {
|
||||
};
|
||||
|
||||
function buildOverrides() {
|
||||
gOverrides = {};
|
||||
gOverrides.clear();
|
||||
gOverrideForHostCache.clear();
|
||||
|
||||
if (!Services.prefs.getBoolPref(PREF_OVERRIDES_ENABLED))
|
||||
return;
|
||||
|
||||
let builtUAs = new Map;
|
||||
let domains = gPrefBranch.getChildList("");
|
||||
|
||||
for (let domain of domains) {
|
||||
let override = gPrefBranch.getCharPref(domain);
|
||||
let userAgent = builtUAs.get(override);
|
||||
|
||||
let [search, replace] = override.split("#", 2);
|
||||
if (search && replace) {
|
||||
gOverrides[domain] = DEFAULT_UA.replace(new RegExp(search, "g"), replace);
|
||||
} else {
|
||||
gOverrides[domain] = override;
|
||||
if (userAgent === undefined) {
|
||||
let [search, replace] = override.split("#", 2);
|
||||
if (search && replace) {
|
||||
userAgent = DEFAULT_UA.replace(new RegExp(search, "g"), replace);
|
||||
} 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",
|
||||
"resource://gre/modules/DownloadIntegration.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
@ -69,6 +71,15 @@ const BackgroundFileSaverStreamListener = Components.Constructor(
|
||||
"@mozilla.org/network/background-file-saver;1?mode=streamlistener",
|
||||
"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
|
||||
|
||||
@ -422,6 +433,71 @@ Download.prototype = {
|
||||
}
|
||||
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 = {
|
||||
/**
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
isPrivate: false,
|
||||
|
||||
/**
|
||||
* The nsIURI for the referrer of the download source, or null if no referrer
|
||||
* should be sent or the download source is not HTTP.
|
||||
* String containing the referrer URI of the download source, or null if no
|
||||
* referrer should be sent or the download source is not HTTP.
|
||||
*/
|
||||
referrer: null,
|
||||
|
||||
@ -456,19 +532,60 @@ DownloadSource.prototype = {
|
||||
*
|
||||
* @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) {
|
||||
serialized.isPrivate = true;
|
||||
serializable.isPrivate = true;
|
||||
}
|
||||
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
|
||||
|
||||
@ -480,21 +597,50 @@ function DownloadTarget() { }
|
||||
|
||||
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.
|
||||
*
|
||||
* @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
|
||||
|
||||
@ -610,12 +756,39 @@ DownloadSaver.prototype = {
|
||||
*
|
||||
* @return A JavaScript object that can be serialized to JSON.
|
||||
*/
|
||||
serialize: function DS_serialize()
|
||||
toSerializable: function ()
|
||||
{
|
||||
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
|
||||
|
||||
@ -665,15 +838,16 @@ DownloadCopySaver.prototype = {
|
||||
};
|
||||
|
||||
// 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.
|
||||
let channel = NetUtil.newChannel(download.source.uri);
|
||||
let channel = NetUtil.newChannel(NetUtil.newURI(download.source.url));
|
||||
if (channel instanceof Ci.nsIPrivateBrowsingChannel) {
|
||||
channel.setPrivate(download.source.isPrivate);
|
||||
}
|
||||
if (channel instanceof Ci.nsIHttpChannel) {
|
||||
channel.referrer = download.source.referrer;
|
||||
if (channel instanceof Ci.nsIHttpChannel && download.source.referrer) {
|
||||
channel.referrer = NetUtil.newURI(download.source.referrer);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@ -872,7 +1061,7 @@ DownloadLegacySaver.prototype = {
|
||||
// empty file is created as expected.
|
||||
try {
|
||||
// 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 });
|
||||
yield file.close();
|
||||
} catch (ex if ex instanceof OS.File.Error && ex.becauseExists) { }
|
||||
@ -898,3 +1087,12 @@ DownloadLegacySaver.prototype = {
|
||||
"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");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
@ -254,7 +256,8 @@ this.DownloadIntegration = {
|
||||
// Log the event if required by parental controls settings.
|
||||
if (isEnabled && gParentalControlsService.loggingEnabled) {
|
||||
gParentalControlsService.log(gParentalControlsService.ePCLog_FileDownload,
|
||||
shouldBlock, aDownload.source.uri, null);
|
||||
shouldBlock,
|
||||
NetUtil.newURI(aDownload.source.url), null);
|
||||
}
|
||||
|
||||
return Promise.resolve(shouldBlock);
|
||||
|
@ -161,9 +161,9 @@ DownloadLegacyTransfer.prototype = {
|
||||
// wait for it to be available. This operation may cause the entire
|
||||
// download system to initialize before the object is created.
|
||||
Downloads.createDownload({
|
||||
source: { uri: aSource, isPrivate: aIsPrivate },
|
||||
target: { file: aTarget.QueryInterface(Ci.nsIFileURL).file },
|
||||
saver: { type: "legacy" },
|
||||
source: { url: aSource.spec, isPrivate: aIsPrivate },
|
||||
target: aTarget.QueryInterface(Ci.nsIFileURL).file,
|
||||
saver: "legacy",
|
||||
}).then(function DLT_I_onDownload(aDownload) {
|
||||
// Now that the saver is available, hook up the cancellation handler.
|
||||
aDownload.saver.deferCanceled.promise.then(() => {
|
||||
|
@ -25,6 +25,8 @@ const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
@ -234,7 +236,8 @@ DownloadList.prototype = {
|
||||
//// nsINavHistoryObserver
|
||||
|
||||
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() {
|
||||
|
@ -7,6 +7,25 @@
|
||||
/**
|
||||
* Handles serialization of Download objects and persistence into a file, so
|
||||
* 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";
|
||||
@ -27,16 +46,11 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||
"resource://gre/modules/Downloads.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm")
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
const LocalFile = Components.Constructor("@mozilla.org/file/local;1",
|
||||
"nsIFile", "initWithPath");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () {
|
||||
return new TextDecoder();
|
||||
});
|
||||
@ -95,19 +109,9 @@ DownloadStore.prototype = {
|
||||
let storeData = JSON.parse(gTextDecoder.decode(bytes));
|
||||
|
||||
// Create live downloads based on the static snapshot.
|
||||
for (let downloadData of storeData) {
|
||||
for (let downloadData of storeData.list) {
|
||||
try {
|
||||
let source = { uri: NetUtil.newURI(downloadData.source.uri) };
|
||||
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);
|
||||
this.list.add(yield Downloads.createDownload(downloadData));
|
||||
} catch (ex) {
|
||||
// If an item is unrecognized, don't prevent others from being loaded.
|
||||
Cu.reportError(ex);
|
||||
@ -131,19 +135,15 @@ DownloadStore.prototype = {
|
||||
let downloads = yield this.list.getAll();
|
||||
|
||||
// Take a static snapshot of the current state of all the downloads.
|
||||
let storeData = [];
|
||||
let storeData = { list: [] };
|
||||
let atLeastOneDownload = false;
|
||||
for (let download of downloads) {
|
||||
try {
|
||||
storeData.push({
|
||||
source: download.source.serialize(),
|
||||
target: download.target.serialize(),
|
||||
saver: download.saver.serialize(),
|
||||
});
|
||||
storeData.list.push(download.toSerializable());
|
||||
atLeastOneDownload = true;
|
||||
} catch (ex) {
|
||||
// If an item cannot be serialized, don't prevent others from being
|
||||
// saved.
|
||||
// If an item cannot be converted to a serializable form, don't
|
||||
// prevent others from being saved.
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
|
@ -31,14 +31,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "DownloadList",
|
||||
"resource://gre/modules/DownloadList.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper",
|
||||
"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",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
@ -55,19 +49,29 @@ this.Downloads = {
|
||||
*
|
||||
* @param aProperties
|
||||
* 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: {
|
||||
* uri: The nsIURI for the download source.
|
||||
* source: String containing the URI 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
|
||||
* 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: {
|
||||
* file: The nsIFile for the download target.
|
||||
* },
|
||||
* saver: {
|
||||
* type: String representing the class of download operation
|
||||
* handled by this saver object, for example "copy".
|
||||
* target: String containing the path of the target file.
|
||||
* Alternatively, may be an nsIFile, a DownloadTarget object,
|
||||
* or an object with the following properties:
|
||||
* {
|
||||
* path: String containing the path of the target file.
|
||||
* },
|
||||
* 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}
|
||||
@ -76,31 +80,11 @@ this.Downloads = {
|
||||
*/
|
||||
createDownload: function D_createDownload(aProperties)
|
||||
{
|
||||
return Task.spawn(function task_D_createDownload() {
|
||||
let download = new Download();
|
||||
|
||||
download.source = new DownloadSource();
|
||||
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);
|
||||
});
|
||||
try {
|
||||
return Promise.resolve(Download.fromSerializable(aProperties));
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -111,15 +95,17 @@ this.Downloads = {
|
||||
* reference to a Download object using the createDownload function.
|
||||
*
|
||||
* @param aSource
|
||||
* The nsIURI or string containing the URI spec for the download
|
||||
* source, or alternative DownloadSource.
|
||||
* String containing the URI for the download source. Alternatively,
|
||||
* may be an nsIURI or a DownloadSource object.
|
||||
* @param aTarget
|
||||
* The nsIFile or string containing the file path, or alternative
|
||||
* DownloadTarget.
|
||||
* String containing the path of the target file. Alternatively, may
|
||||
* be an nsIFile or a DownloadTarget object.
|
||||
* @param aOptions
|
||||
* The object contains different additional options or null.
|
||||
* { isPrivate: Indicates whether the download originated from a
|
||||
* private window.
|
||||
* An optional object used to control the behavior of this function.
|
||||
* You may pass an object with a subset of the following fields:
|
||||
* {
|
||||
* isPrivate: Indicates whether the download originated from a
|
||||
* private window.
|
||||
* }
|
||||
*
|
||||
* @return {Promise}
|
||||
@ -127,31 +113,13 @@ this.Downloads = {
|
||||
* @rejects JavaScript exception if the download failed.
|
||||
*/
|
||||
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({
|
||||
source: aSource,
|
||||
target: aTarget,
|
||||
saver: { type: "copy" },
|
||||
}).then(function D_SD_onSuccess(aDownload) {
|
||||
if (aOptions && ("isPrivate" in aOptions)) {
|
||||
aDownload.source.isPrivate = aOptions.isPrivate;
|
||||
}
|
||||
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",
|
||||
"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_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.";
|
||||
// Generate using gzipCompressString in TelemetryPing.js.
|
||||
const TEST_DATA_SHORT_GZIP_ENCODED_FIRST = [
|
||||
@ -119,6 +79,20 @@ function run_test()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// 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
|
||||
// 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
|
||||
@ -190,21 +164,101 @@ function promiseTimeout(aTime)
|
||||
/**
|
||||
* Creates a new Download object, setting a temporary file as the target.
|
||||
*
|
||||
* @param aSourceURI
|
||||
* The nsIURI for the download source, or null to use TEST_SOURCE_URI.
|
||||
* @param aSourceUrl
|
||||
* String containing the URI for the download source, or null to use
|
||||
* httpUrl("source.txt").
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The newly created Download object.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
function promiseSimpleDownload(aSourceURI) {
|
||||
function promiseNewDownload(aSourceUrl) {
|
||||
return Downloads.createDownload({
|
||||
source: { uri: aSourceURI || TEST_SOURCE_URI },
|
||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
||||
saver: { type: "copy" },
|
||||
source: aSourceUrl || httpUrl("source.txt"),
|
||||
target: getTempFile(TEST_TARGET_FILE_NAME),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -234,8 +288,9 @@ function promiseNewPrivateDownloadList() {
|
||||
/**
|
||||
* Ensures that the given file contents are equal to the given string.
|
||||
*
|
||||
* @param aFile
|
||||
* nsIFile whose contents should be verified.
|
||||
* @param aPath
|
||||
* String containing the path of the file whose contents should be
|
||||
* verified.
|
||||
* @param aExpectedContents
|
||||
* String containing the octets that are expected in the file.
|
||||
*
|
||||
@ -243,10 +298,11 @@ function promiseNewPrivateDownloadList() {
|
||||
* @resolves When the operation completes.
|
||||
* @rejects Never.
|
||||
*/
|
||||
function promiseVerifyContents(aFile, aExpectedContents)
|
||||
function promiseVerifyContents(aPath, aExpectedContents)
|
||||
{
|
||||
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));
|
||||
let contents = NetUtil.readInputStreamToString(aInputStream,
|
||||
aInputStream.available());
|
||||
@ -265,17 +321,18 @@ function promiseVerifyContents(aFile, aExpectedContents)
|
||||
/**
|
||||
* Adds entry for download.
|
||||
*
|
||||
* @param aSourceURI
|
||||
* The nsIURI for the download source, or null to use TEST_SOURCE_URI.
|
||||
* @param aSourceUrl
|
||||
* String containing the URI for the download source, or null to use
|
||||
* httpUrl("source.txt").
|
||||
*
|
||||
* @return {Promise}
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
function promiseAddDownloadToHistory(aSourceURI) {
|
||||
function promiseAddDownloadToHistory(aSourceUrl) {
|
||||
let deferred = Promise.defer();
|
||||
PlacesUtils.asyncHistory.updatePlaces(
|
||||
{
|
||||
uri: aSourceURI || TEST_SOURCE_URI,
|
||||
uri: NetUtil.newURI(aSourceUrl || httpUrl("source.txt")),
|
||||
visits: [{
|
||||
transitionType: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
|
||||
visitDate: Date.now()
|
||||
@ -304,7 +361,6 @@ function promiseAddDownloadToHistory(aSourceURI) {
|
||||
function startFakeServer()
|
||||
{
|
||||
let serverSocket = new ServerSocket(-1, true, -1);
|
||||
gFakeServerPort = serverSocket.port;
|
||||
serverSocket.asyncListen({
|
||||
onSocketAccepted: function (aServ, aTransport) {
|
||||
aTransport.close(Cr.NS_BINDING_ABORTED);
|
||||
@ -326,10 +382,10 @@ function startFakeServer()
|
||||
* handlers, you may call "deferNextResponse" to get a reference to an object
|
||||
* that allows you to control the next request.
|
||||
*
|
||||
* For example, the handler accessible at the TEST_INTERRUPTIBLE_URI address
|
||||
* returns the TEST_DATA_SHORT text, then waits until the "resolve" method is
|
||||
* called on the object returned by the function. At this point, the handler
|
||||
* sends the TEST_DATA_SHORT text again to complete the response.
|
||||
* For example, the handler accessible at the httpUri("interruptible.txt")
|
||||
* address returns the TEST_DATA_SHORT text, then waits until the "resolve"
|
||||
* method is called on the object returned by the function. At this point, the
|
||||
* 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
|
||||
* 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
|
||||
|
||||
let gHttpServer;
|
||||
let gFakeServerPort;
|
||||
|
||||
add_task(function test_common_initialize()
|
||||
{
|
||||
// Start the HTTP server.
|
||||
@ -439,7 +492,7 @@ add_task(function test_common_initialize()
|
||||
gHttpServer.registerDirectory("/", do_get_file("../data"));
|
||||
gHttpServer.start(-1);
|
||||
|
||||
registerInterruptibleHandler(TEST_INTERRUPTIBLE_PATH,
|
||||
registerInterruptibleHandler("/interruptible.txt",
|
||||
function firstPart(aRequest, aResponse) {
|
||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
||||
aResponse.setHeader("Content-Length", "" + (TEST_DATA_SHORT.length * 2),
|
||||
@ -449,13 +502,13 @@ add_task(function test_common_initialize()
|
||||
aResponse.write(TEST_DATA_SHORT);
|
||||
});
|
||||
|
||||
registerInterruptibleHandler(TEST_EMPTY_NOPROGRESS_PATH,
|
||||
registerInterruptibleHandler("/empty-noprogress.txt",
|
||||
function firstPart(aRequest, aResponse) {
|
||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
||||
}, function secondPart(aRequest, aResponse) { });
|
||||
|
||||
|
||||
registerInterruptibleHandler(TEST_INTERRUPTIBLE_GZIP_PATH,
|
||||
registerInterruptibleHandler("/interruptible_gzip.txt",
|
||||
function firstPart(aRequest, aResponse) {
|
||||
aResponse.setHeader("Content-Type", "text/plain", false);
|
||||
aResponse.setHeader("Content-Encoding", "gzip", false);
|
||||
|
@ -4,894 +4,15 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests the objects defined in the "DownloadCore" module.
|
||||
* Tests the main download interfaces using DownloadCopySaver.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Tests
|
||||
//// Execution of common tests
|
||||
|
||||
/**
|
||||
* 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 gUseLegacySaver = false;
|
||||
|
||||
let scriptFile = do_get_file("common_test_Download.js");
|
||||
Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
|
||||
|
@ -10,370 +10,9 @@
|
||||
"use strict";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
//// Execution of common tests
|
||||
|
||||
/**
|
||||
* 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 gUseLegacySaver = true;
|
||||
|
||||
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
|
||||
.createInstance(Ci.nsIWebBrowserPersist);
|
||||
|
||||
// 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();
|
||||
});
|
||||
let scriptFile = do_get_file("common_test_Download.js");
|
||||
Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
|
||||
|
@ -34,14 +34,14 @@ add_task(function test_add_getAll()
|
||||
{
|
||||
let list = yield promiseNewDownloadList();
|
||||
|
||||
let downloadOne = yield promiseSimpleDownload();
|
||||
let downloadOne = yield promiseNewDownload();
|
||||
list.add(downloadOne);
|
||||
|
||||
let itemsOne = yield list.getAll();
|
||||
do_check_eq(itemsOne.length, 1);
|
||||
do_check_eq(itemsOne[0], downloadOne);
|
||||
|
||||
let downloadTwo = yield promiseSimpleDownload();
|
||||
let downloadTwo = yield promiseNewDownload();
|
||||
list.add(downloadTwo);
|
||||
|
||||
let itemsTwo = yield list.getAll();
|
||||
@ -60,14 +60,14 @@ add_task(function test_remove()
|
||||
{
|
||||
let list = yield promiseNewDownloadList();
|
||||
|
||||
list.add(yield promiseSimpleDownload());
|
||||
list.add(yield promiseSimpleDownload());
|
||||
list.add(yield promiseNewDownload());
|
||||
list.add(yield promiseNewDownload());
|
||||
|
||||
let items = yield list.getAll();
|
||||
list.remove(items[0]);
|
||||
|
||||
// Removing an item that was never added should not raise an error.
|
||||
list.remove(yield promiseSimpleDownload());
|
||||
list.remove(yield promiseNewDownload());
|
||||
|
||||
items = yield list.getAll();
|
||||
do_check_eq(items.length, 1);
|
||||
@ -81,8 +81,8 @@ add_task(function test_notifications_add_remove()
|
||||
{
|
||||
let list = yield promiseNewDownloadList();
|
||||
|
||||
let downloadOne = yield promiseSimpleDownload();
|
||||
let downloadTwo = yield promiseSimpleDownload();
|
||||
let downloadOne = yield promiseNewDownload();
|
||||
let downloadTwo = yield promiseNewDownload();
|
||||
list.add(downloadOne);
|
||||
list.add(downloadTwo);
|
||||
|
||||
@ -103,7 +103,7 @@ add_task(function test_notifications_add_remove()
|
||||
do_check_eq(addNotifications, 2);
|
||||
|
||||
// Check that we receive add notifications for new elements.
|
||||
list.add(yield promiseSimpleDownload());
|
||||
list.add(yield promiseNewDownload());
|
||||
do_check_eq(addNotifications, 3);
|
||||
|
||||
// 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.
|
||||
list.removeView(viewOne);
|
||||
list.add(yield promiseSimpleDownload());
|
||||
list.add(yield promiseNewDownload());
|
||||
do_check_eq(addNotifications, 3);
|
||||
});
|
||||
|
||||
@ -136,8 +136,8 @@ add_task(function test_notifications_change()
|
||||
{
|
||||
let list = yield promiseNewDownloadList();
|
||||
|
||||
let downloadOne = yield promiseSimpleDownload();
|
||||
let downloadTwo = yield promiseSimpleDownload();
|
||||
let downloadOne = yield promiseNewDownload();
|
||||
let downloadTwo = yield promiseNewDownload();
|
||||
list.add(downloadOne);
|
||||
list.add(downloadTwo);
|
||||
|
||||
@ -174,11 +174,11 @@ add_task(function test_history_expiration()
|
||||
|
||||
// Add expirable visit for downloads.
|
||||
yield promiseAddDownloadToHistory();
|
||||
yield promiseAddDownloadToHistory(TEST_INTERRUPTIBLE_URI);
|
||||
yield promiseAddDownloadToHistory(httpUrl("interruptible.txt"));
|
||||
|
||||
let list = yield promiseNewDownloadList();
|
||||
let downloadOne = yield promiseSimpleDownload();
|
||||
let downloadTwo = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
|
||||
let downloadOne = yield promiseNewDownload();
|
||||
let downloadTwo = yield promiseNewDownload(httpUrl("interruptible.txt"));
|
||||
list.add(downloadOne);
|
||||
list.add(downloadTwo);
|
||||
|
||||
@ -221,8 +221,8 @@ add_task(function test_history_clear()
|
||||
yield promiseAddDownloadToHistory();
|
||||
|
||||
let list = yield promiseNewDownloadList();
|
||||
let downloadOne = yield promiseSimpleDownload();
|
||||
let downloadTwo = yield promiseSimpleDownload();
|
||||
let downloadOne = yield promiseNewDownload();
|
||||
let downloadTwo = yield promiseNewDownload();
|
||||
list.add(downloadOne);
|
||||
list.add(downloadTwo);
|
||||
|
||||
|
@ -49,12 +49,11 @@ add_task(function test_save_reload()
|
||||
let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
|
||||
storeForSave.path);
|
||||
|
||||
listForSave.add(yield promiseSimpleDownload(TEST_SOURCE_URI));
|
||||
listForSave.add(yield promiseNewDownload(httpUrl("source.txt")));
|
||||
listForSave.add(yield Downloads.createDownload({
|
||||
source: { uri: TEST_EMPTY_URI,
|
||||
referrer: TEST_REFERRER_URI },
|
||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
||||
saver: { type: "copy" },
|
||||
source: { url: httpUrl("empty.txt"),
|
||||
referrer: TEST_REFERRER_URL },
|
||||
target: getTempFile(TEST_TARGET_FILE_NAME),
|
||||
}));
|
||||
|
||||
yield storeForSave.save();
|
||||
@ -71,16 +70,12 @@ add_task(function test_save_reload()
|
||||
do_check_neq(itemsForSave[i], itemsForLoad[i]);
|
||||
|
||||
// The reloaded downloads have the same properties.
|
||||
do_check_true(itemsForSave[i].source.uri.equals(
|
||||
itemsForLoad[i].source.uri));
|
||||
if (itemsForSave[i].source.referrer) {
|
||||
do_check_true(itemsForSave[i].source.referrer.equals(
|
||||
itemsForLoad[i].source.referrer));
|
||||
} else {
|
||||
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].source.url,
|
||||
itemsForLoad[i].source.url);
|
||||
do_check_eq(itemsForSave[i].source.referrer,
|
||||
itemsForLoad[i].source.referrer);
|
||||
do_check_eq(itemsForSave[i].target.path,
|
||||
itemsForLoad[i].target.path);
|
||||
do_check_eq(itemsForSave[i].saver.type,
|
||||
itemsForLoad[i].saver.type);
|
||||
}
|
||||
@ -129,19 +124,17 @@ add_task(function test_load_string_predefined()
|
||||
let [list, store] = yield promiseNewListAndStore();
|
||||
|
||||
// The platform-dependent file name should be generated dynamically.
|
||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||
let filePathLiteral = JSON.stringify(targetFile.path);
|
||||
let sourceUriLiteral = JSON.stringify(TEST_SOURCE_URI.spec);
|
||||
let emptyUriLiteral = JSON.stringify(TEST_EMPTY_URI.spec);
|
||||
let referrerUriLiteral = JSON.stringify(TEST_REFERRER_URI.spec);
|
||||
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||
let filePathLiteral = JSON.stringify(targetPath);
|
||||
let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
|
||||
let emptyUriLiteral = JSON.stringify(httpUrl("empty.txt"));
|
||||
let referrerUriLiteral = JSON.stringify(TEST_REFERRER_URL);
|
||||
|
||||
let string = "[{\"source\":{\"uri\":" + sourceUriLiteral + "}," +
|
||||
"\"target\":{\"file\":" + filePathLiteral + "}," +
|
||||
"\"saver\":{\"type\":\"copy\"}}," +
|
||||
"{\"source\":{\"uri\":" + emptyUriLiteral + "," +
|
||||
let string = "{\"list\":[{\"source\":" + sourceUriLiteral + "," +
|
||||
"\"target\":" + filePathLiteral + "}," +
|
||||
"{\"source\":{\"url\":" + emptyUriLiteral + "," +
|
||||
"\"referrer\":" + referrerUriLiteral + "}," +
|
||||
"\"target\":{\"file\":" + filePathLiteral + "}," +
|
||||
"\"saver\":{\"type\":\"copy\"}}]";
|
||||
"\"target\":" + filePathLiteral + "}]}";
|
||||
|
||||
yield OS.File.writeAtomic(store.path,
|
||||
new TextEncoder().encode(string),
|
||||
@ -153,12 +146,12 @@ add_task(function test_load_string_predefined()
|
||||
|
||||
do_check_eq(items.length, 2);
|
||||
|
||||
do_check_true(items[0].source.uri.equals(TEST_SOURCE_URI));
|
||||
do_check_true(items[0].target.file.equals(targetFile));
|
||||
do_check_eq(items[0].source.url, httpUrl("source.txt"));
|
||||
do_check_eq(items[0].target.path, targetPath);
|
||||
|
||||
do_check_true(items[1].source.uri.equals(TEST_EMPTY_URI));
|
||||
do_check_true(items[1].source.referrer.equals(TEST_REFERRER_URI));
|
||||
do_check_true(items[1].target.file.equals(targetFile));
|
||||
do_check_eq(items[1].source.url, httpUrl("empty.txt"));
|
||||
do_check_eq(items[1].source.referrer, TEST_REFERRER_URL);
|
||||
do_check_eq(items[1].target.path, targetPath);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -169,15 +162,15 @@ add_task(function test_load_string_unrecognized()
|
||||
let [list, store] = yield promiseNewListAndStore();
|
||||
|
||||
// The platform-dependent file name should be generated dynamically.
|
||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||
let filePathLiteral = JSON.stringify(targetFile.path);
|
||||
let sourceUriLiteral = JSON.stringify(TEST_SOURCE_URI.spec);
|
||||
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||
let filePathLiteral = JSON.stringify(targetPath);
|
||||
let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
|
||||
|
||||
let string = "[{\"source\":null," +
|
||||
let string = "{\"list\":[{\"source\":null," +
|
||||
"\"target\":null}," +
|
||||
"{\"source\":{\"uri\":" + sourceUriLiteral + "}," +
|
||||
"\"target\":{\"file\":" + filePathLiteral + "}," +
|
||||
"\"saver\":{\"type\":\"copy\"}}]";
|
||||
"{\"source\":{\"url\":" + sourceUriLiteral + "}," +
|
||||
"\"target\":{\"path\":" + filePathLiteral + "}," +
|
||||
"\"saver\":{\"type\":\"copy\"}}]}";
|
||||
|
||||
yield OS.File.writeAtomic(store.path,
|
||||
new TextEncoder().encode(string),
|
||||
@ -189,8 +182,8 @@ add_task(function test_load_string_unrecognized()
|
||||
|
||||
do_check_eq(items.length, 1);
|
||||
|
||||
do_check_true(items[0].source.uri.equals(TEST_SOURCE_URI));
|
||||
do_check_true(items[0].target.file.equals(targetFile));
|
||||
do_check_eq(items[0].source.url, httpUrl("source.txt"));
|
||||
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 string = "[{\"source\":null,\"target\":null}," +
|
||||
"{\"source\":{\"uri\":\"about:blank\"}}";
|
||||
let string = "{\"list\":[{\"source\":null,\"target\":null}," +
|
||||
"{\"source\":{\"url\":\"about:blank\"}}}";
|
||||
|
||||
yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
|
||||
{ tmpPath: store.path + ".tmp" });
|
||||
|
@ -20,21 +20,20 @@ add_task(function test_createDownload()
|
||||
{
|
||||
// Creates a simple Download object without starting the download.
|
||||
yield Downloads.createDownload({
|
||||
source: { uri: NetUtil.newURI("about:blank") },
|
||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
||||
source: { url: "about:blank" },
|
||||
target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
|
||||
saver: { type: "copy" },
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests createDownload for private download.
|
||||
* Tests createDownload for private download.
|
||||
*/
|
||||
add_task(function test_createDownload_private()
|
||||
{
|
||||
let download = yield Downloads.createDownload({
|
||||
source: { uri: NetUtil.newURI("about:blank"),
|
||||
isPrivate: true },
|
||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
||||
source: { url: "about:blank", isPrivate: true },
|
||||
target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
|
||||
saver: { type: "copy" }
|
||||
});
|
||||
do_check_true(download.source.isPrivate);
|
||||
@ -45,21 +44,20 @@ add_task(function test_createDownload_private()
|
||||
*/
|
||||
add_task(function test_createDownload_public()
|
||||
{
|
||||
let uri = NetUtil.newURI("about:blank");
|
||||
let tempFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||
let tempPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||
let download = yield Downloads.createDownload({
|
||||
source: { uri: uri, isPrivate: false },
|
||||
target: { file: tempFile },
|
||||
source: { url: "about:blank", isPrivate: false },
|
||||
target: { path: tempPath },
|
||||
saver: { type: "copy" }
|
||||
});
|
||||
do_check_false(download.source.isPrivate);
|
||||
|
||||
download = yield Downloads.createDownload({
|
||||
source: { uri: uri },
|
||||
target: { file: tempFile },
|
||||
source: { url: "about:blank" },
|
||||
target: { path: tempPath },
|
||||
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()
|
||||
{
|
||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||
yield Downloads.simpleDownload(TEST_SOURCE_URI, targetFile);
|
||||
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
|
||||
yield Downloads.simpleDownload(NetUtil.newURI(httpUrl("source.txt")),
|
||||
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()
|
||||
{
|
||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||
yield Downloads.simpleDownload({ uri: TEST_SOURCE_URI },
|
||||
{ file: targetFile });
|
||||
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
|
||||
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||
yield Downloads.simpleDownload({ url: httpUrl("source.txt") },
|
||||
{ path: targetPath });
|
||||
yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -88,15 +87,15 @@ add_task(function test_simpleDownload_object_arguments()
|
||||
*/
|
||||
add_task(function test_simpleDownload_string_arguments()
|
||||
{
|
||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||
yield Downloads.simpleDownload(TEST_SOURCE_URI.spec,
|
||||
targetFile.path);
|
||||
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
|
||||
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||
yield Downloads.simpleDownload(httpUrl("source.txt"),
|
||||
targetPath);
|
||||
yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
|
||||
|
||||
targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||
yield Downloads.simpleDownload(new String(TEST_SOURCE_URI.spec),
|
||||
new String(targetFile.path));
|
||||
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
|
||||
targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||
yield Downloads.simpleDownload(new String(httpUrl("source.txt")),
|
||||
new String(targetPath));
|
||||
yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
|
||||
});
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user