Bug 851454 - Define the format of "downloads.json" and of the parameters of createDownload. r=enn

This commit is contained in:
Paolo Amadini 2013-07-26 15:30:35 +02:00
parent 0148c7188e
commit cd2fb25f6a
12 changed files with 504 additions and 363 deletions

View File

@ -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();
};

View File

@ -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);

View File

@ -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(() => {

View File

@ -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() {

View File

@ -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);
}
}

View File

@ -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();
});
},

View File

@ -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,18 +164,18 @@ 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 promiseSimpleDownload(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),
});
}
@ -234,8 +208,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 +218,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 +241,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 +281,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 +302,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 +405,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 +412,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 +422,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);

View File

@ -17,23 +17,23 @@
*/
add_task(function test_download_construction()
{
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
let download = yield Downloads.createDownload({
source: { uri: TEST_SOURCE_URI },
target: { file: targetFile },
source: { url: httpUrl("source.txt") },
target: { path: targetPath },
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_eq(download.source.url, httpUrl("source.txt"));
do_check_eq(download.target.path, targetPath);
do_check_true(download.source.referrer === null);
// Starts the download and waits for completion.
yield download.start();
yield promiseVerifyContents(targetFile, TEST_DATA_SHORT);
yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
});
/**
@ -41,46 +41,44 @@ add_task(function test_download_construction()
*/
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);
let sourcePath = "/test_download_referrer.txt";
let sourceUrl = httpUrl("test_download_referrer.txt");
let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
function cleanup() {
gHttpServer.registerPathHandler(source_path, null);
gHttpServer.registerPathHandler(sourcePath, null);
}
do_register_cleanup(cleanup);
gHttpServer.registerPathHandler(source_path, function (aRequest, aResponse) {
gHttpServer.registerPathHandler(sourcePath, 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);
do_check_eq(aRequest.getHeader("Referer"), TEST_REFERRER_URL);
});
let download = yield Downloads.createDownload({
source: { uri: source_uri, referrer: TEST_REFERRER_URI },
target: { file: target_uri },
saver: { type: "copy" },
source: { url: sourceUrl, referrer: TEST_REFERRER_URL },
target: targetPath,
});
do_check_true(download.source.referrer.equals(TEST_REFERRER_URI));
do_check_eq(download.source.referrer, TEST_REFERRER_URL);
yield download.start();
download = yield Downloads.createDownload({
source: { uri: source_uri, referrer: TEST_REFERRER_URI, isPrivate: true },
target: { file: target_uri },
saver: { type: "copy" },
source: { url: sourceUrl, referrer: TEST_REFERRER_URL,
isPrivate: true },
target: targetPath,
});
do_check_true(download.source.referrer.equals(TEST_REFERRER_URI));
do_check_eq(download.source.referrer, TEST_REFERRER_URL);
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>");
sourceUrl = "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" },
source: { url: sourceUrl, referrer: TEST_REFERRER_URL },
target: targetPath,
});
do_check_true(download.source.referrer.equals(TEST_REFERRER_URI));
do_check_eq(download.source.referrer, TEST_REFERRER_URL);
yield download.start();
cleanup();
@ -143,7 +141,7 @@ add_task(function test_download_intermediate_progress()
{
let deferResponse = deferNextResponse();
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
download.onchange = function () {
if (download.progress == 50) {
@ -162,7 +160,7 @@ add_task(function test_download_intermediate_progress()
do_check_true(download.stopped);
do_check_eq(download.progress, 100);
yield promiseVerifyContents(download.target.file,
yield promiseVerifyContents(download.target.path,
TEST_DATA_SHORT + TEST_DATA_SHORT);
});
@ -171,7 +169,7 @@ add_task(function test_download_intermediate_progress()
*/
add_task(function test_download_empty_progress()
{
let download = yield promiseSimpleDownload(TEST_EMPTY_URI);
let download = yield promiseSimpleDownload(httpUrl("empty.txt"));
yield download.start();
@ -181,7 +179,7 @@ add_task(function test_download_empty_progress()
do_check_eq(download.currentBytes, 0);
do_check_eq(download.totalBytes, 0);
do_check_eq(download.target.file.fileSize, 0);
do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
});
/**
@ -192,7 +190,7 @@ add_task(function test_download_empty_noprogress()
let deferResponse = deferNextResponse();
let promiseEmptyRequestReceived = promiseNextRequestReceived();
let download = yield promiseSimpleDownload(TEST_EMPTY_NOPROGRESS_URI);
let download = yield promiseSimpleDownload(httpUrl("empty-noprogress.txt"));
download.onchange = function () {
if (!download.stopped) {
@ -228,7 +226,7 @@ add_task(function test_download_empty_noprogress()
do_check_eq(download.currentBytes, 0);
do_check_eq(download.totalBytes, 0);
do_check_eq(download.target.file.fileSize, 0);
do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
});
/**
@ -236,7 +234,7 @@ add_task(function test_download_empty_noprogress()
*/
add_task(function test_download_start_twice()
{
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
// Ensure that the download cannot complete before start is called twice.
let deferResponse = deferNextResponse();
@ -257,7 +255,7 @@ add_task(function test_download_start_twice()
do_check_false(download.canceled);
do_check_true(download.error === null);
yield promiseVerifyContents(download.target.file,
yield promiseVerifyContents(download.target.path,
TEST_DATA_SHORT + TEST_DATA_SHORT);
});
@ -266,7 +264,7 @@ add_task(function test_download_start_twice()
*/
add_task(function test_download_cancel_midway()
{
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
let deferResponse = deferNextResponse();
try {
@ -292,7 +290,7 @@ add_task(function test_download_cancel_midway()
do_check_true(download.canceled);
do_check_true(download.error === null);
do_check_false(download.target.file.exists());
do_check_false(yield OS.File.exists(download.target.path));
// Progress properties are not reset by canceling.
do_check_eq(download.progress, 50);
@ -320,7 +318,7 @@ 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 download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
let promiseAttempt = download.start();
do_check_false(download.stopped);
@ -343,7 +341,7 @@ add_task(function test_download_cancel_immediately()
do_check_true(download.canceled);
do_check_true(download.error === null);
do_check_false(download.target.file.exists());
do_check_false(yield OS.File.exists(download.target.path));
// Check that the promise returned by the "cancel" method has been resolved.
yield promiseCancel;
@ -365,7 +363,7 @@ add_task(function test_download_cancel_immediately()
*/
add_task(function test_download_cancel_midway_restart()
{
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
// The first time, cancel the download midway.
let deferResponse = deferNextResponse();
@ -407,7 +405,7 @@ add_task(function test_download_cancel_midway_restart()
do_check_false(download.canceled);
do_check_true(download.error === null);
yield promiseVerifyContents(download.target.file,
yield promiseVerifyContents(download.target.path,
TEST_DATA_SHORT + TEST_DATA_SHORT);
});
@ -416,7 +414,7 @@ add_task(function test_download_cancel_midway_restart()
*/
add_task(function test_download_cancel_immediately_restart_immediately()
{
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
// Ensure that the download cannot complete before cancel is called.
let deferResponse = deferNextResponse();
@ -467,7 +465,7 @@ add_task(function test_download_cancel_immediately_restart_immediately()
do_check_false(download.canceled);
do_check_true(download.error === null);
yield promiseVerifyContents(download.target.file,
yield promiseVerifyContents(download.target.path,
TEST_DATA_SHORT + TEST_DATA_SHORT);
});
@ -476,7 +474,7 @@ add_task(function test_download_cancel_immediately_restart_immediately()
*/
add_task(function test_download_cancel_midway_restart_immediately()
{
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
// The first time, cancel the download midway.
let deferResponse = deferNextResponse();
@ -525,7 +523,7 @@ add_task(function test_download_cancel_midway_restart_immediately()
do_check_false(download.canceled);
do_check_true(download.error === null);
yield promiseVerifyContents(download.target.file,
yield promiseVerifyContents(download.target.path,
TEST_DATA_SHORT + TEST_DATA_SHORT);
});
@ -547,7 +545,7 @@ add_task(function test_download_cancel_successful()
do_check_false(download.canceled);
do_check_true(download.error === null);
yield promiseVerifyContents(download.target.file, TEST_DATA_SHORT);
yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
});
/**
@ -555,7 +553,7 @@ add_task(function test_download_cancel_successful()
*/
add_task(function test_download_cancel_twice()
{
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
// Ensure that the download cannot complete before cancel is called.
let deferResponse = deferNextResponse();
@ -584,7 +582,7 @@ add_task(function test_download_cancel_twice()
do_check_true(download.canceled);
do_check_true(download.error === null);
do_check_false(download.target.file.exists());
do_check_false(yield OS.File.exists(download.target.path));
} finally {
deferResponse.resolve();
}
@ -595,7 +593,7 @@ add_task(function test_download_cancel_twice()
*/
add_task(function test_download_whenSucceeded()
{
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_URI);
let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
// Ensure that the download cannot complete before cancel is called.
let deferResponse = deferNextResponse();
@ -620,7 +618,7 @@ add_task(function test_download_whenSucceeded()
do_check_false(download.canceled);
do_check_true(download.error === null);
yield promiseVerifyContents(download.target.file,
yield promiseVerifyContents(download.target.path,
TEST_DATA_SHORT + TEST_DATA_SHORT);
});
@ -631,7 +629,9 @@ add_task(function test_download_error_source()
{
let serverSocket = startFakeServer();
try {
let download = yield promiseSimpleDownload(TEST_FAKE_SOURCE_URI);
let sourceUrl = "http://localhost:" + serverSocket.port + "/source.txt";
let download = yield promiseSimpleDownload(sourceUrl);
do_check_true(download.error === null);
@ -662,7 +662,8 @@ add_task(function test_download_error_target()
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);
let targetFile = new FileUtils.File(download.target.path);
targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
try {
try {
yield download.start();
@ -678,9 +679,9 @@ add_task(function test_download_error_target()
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);
if (targetFile.exists()) {
targetFile.permissions = FileUtils.PERMS_FILE;
targetFile.remove(false);
}
}
});
@ -695,7 +696,8 @@ add_task(function test_download_error_restart()
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);
let targetFile = new FileUtils.File(download.target.path);
targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
try {
yield download.start();
@ -704,15 +706,14 @@ add_task(function test_download_error_restart()
// 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;
if (targetFile.exists()) {
targetFile.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);
targetFile.moveTo(null, targetFile.leafName + ".delete.tmp");
targetFile.remove(false);
}
}
@ -725,7 +726,7 @@ add_task(function test_download_error_restart()
do_check_true(download.error === null);
do_check_eq(download.progress, 100);
yield promiseVerifyContents(download.target.file, TEST_DATA_SHORT);
yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
});
/**
@ -733,8 +734,8 @@ add_task(function test_download_error_restart()
*/
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 sourcePath = "/test_download_public_and_private.txt";
let sourceUrl = httpUrl("test_download_public_and_private.txt");
let testCount = 0;
// Apply pref to allow all cookies.
@ -743,11 +744,11 @@ add_task(function test_download_public_and_private()
function cleanup() {
Services.prefs.clearUserPref("network.cookie.cookieBehavior");
Services.cookies.removeAll();
gHttpServer.registerPathHandler(source_path, null);
gHttpServer.registerPathHandler(sourcePath, null);
}
do_register_cleanup(cleanup);
gHttpServer.registerPathHandler(source_path, function (aRequest, aResponse) {
gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
aResponse.setHeader("Content-Type", "text/plain", false);
if (testCount == 0) {
@ -767,12 +768,11 @@ add_task(function test_download_public_and_private()
});
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
yield Downloads.simpleDownload(source_uri, targetFile);
yield Downloads.simpleDownload(source_uri, targetFile);
yield Downloads.simpleDownload(sourceUrl, targetFile);
yield Downloads.simpleDownload(sourceUrl, targetFile);
let download = yield Downloads.createDownload({
source: { uri: source_uri, isPrivate: true },
target: { file: targetFile },
saver: { type: "copy" },
source: { url: sourceUrl, isPrivate: true },
target: targetFile,
});
yield download.start();
@ -805,15 +805,15 @@ add_task(function test_download_cancel_immediately_restart_and_check_startTime()
*/
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);
let sourcePath = "/test_download_with_content_encoding.txt";
let sourceUrl = httpUrl("test_download_with_content_encoding.txt");
function cleanup() {
gHttpServer.registerPathHandler(source_path, null);
gHttpServer.registerPathHandler(sourcePath, null);
}
do_register_cleanup(cleanup);
gHttpServer.registerPathHandler(source_path, function (aRequest, aResponse) {
gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
aResponse.setHeader("Content-Type", "text/plain", false);
aResponse.setHeader("Content-Encoding", "gzip", false);
aResponse.setHeader("Content-Length",
@ -825,9 +825,8 @@ add_task(function test_download_with_content_encoding()
});
let download = yield Downloads.createDownload({
source: { uri: source_uri },
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
saver: { type: "copy" },
source: sourceUrl,
target: getTempFile(TEST_TARGET_FILE_NAME),
});
yield download.start();
@ -835,7 +834,7 @@ add_task(function test_download_with_content_encoding()
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);
yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
});
/**
@ -843,7 +842,7 @@ add_task(function test_download_with_content_encoding()
*/
add_task(function test_download_cancel_midway_restart_with_content_encoding()
{
let download = yield promiseSimpleDownload(TEST_INTERRUPTIBLE_GZIP_URI);
let download = yield promiseSimpleDownload(httpUrl("interruptible_gzip.txt"));
// The first time, cancel the download midway.
let deferResponse = deferNextResponse();
@ -870,7 +869,7 @@ add_task(function test_download_cancel_midway_restart_with_content_encoding()
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);
yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
});
/**

View File

@ -16,8 +16,9 @@
* 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 aSourceUrl
* String containing the URI for the download source, or null to use
* httpUrl("source.txt").
* @param isPrivate
* Optional boolean indicates whether the download originated from a
* private window.
@ -30,8 +31,8 @@
* 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;
function promiseStartLegacyDownload(aSourceUrl, aIsPrivate, aOutPersist) {
let sourceURI = NetUtil.newURI(aSourceUrl || httpUrl("source.txt"));
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
@ -94,15 +95,16 @@ add_task(function test_basic()
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));
do_check_eq(download.source.url, httpUrl("source.txt"));
do_check_true(new FileUtils.File(download.target.path).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);
yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
});
/**
@ -131,7 +133,7 @@ add_task(function test_intermediate_progress()
{
let deferResponse = deferNextResponse();
let download = yield promiseStartLegacyDownload(TEST_INTERRUPTIBLE_URI);
let download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"));
let onchange = function () {
if (download.progress == 50) {
@ -157,7 +159,7 @@ add_task(function test_intermediate_progress()
do_check_true(download.stopped);
do_check_eq(download.progress, 100);
yield promiseVerifyContents(download.target.file,
yield promiseVerifyContents(download.target.path,
TEST_DATA_SHORT + TEST_DATA_SHORT);
});
@ -166,7 +168,7 @@ add_task(function test_intermediate_progress()
*/
add_task(function test_empty_progress()
{
let download = yield promiseStartLegacyDownload(TEST_EMPTY_URI);
let download = yield promiseStartLegacyDownload(httpUrl("empty.txt"));
// The download is already started, wait for completion and report any errors.
if (!download.stopped) {
@ -179,7 +181,7 @@ add_task(function test_empty_progress()
do_check_eq(download.currentBytes, 0);
do_check_eq(download.totalBytes, 0);
do_check_eq(download.target.file.fileSize, 0);
do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
});
/**
@ -190,7 +192,8 @@ add_task(function test_empty_noprogress()
let deferResponse = deferNextResponse();
let promiseEmptyRequestReceived = promiseNextRequestReceived();
let download = yield promiseStartLegacyDownload(TEST_EMPTY_NOPROGRESS_URI);
let download = yield promiseStartLegacyDownload(
httpUrl("empty-noprogress.txt"));
// 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
@ -218,7 +221,7 @@ add_task(function test_empty_noprogress()
do_check_eq(download.currentBytes, 0);
do_check_eq(download.totalBytes, 0);
do_check_eq(download.target.file.fileSize, 0);
do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
});
/**
@ -228,8 +231,8 @@ add_task(function test_cancel_midway()
{
let deferResponse = deferNextResponse();
let outPersist = {};
let download = yield promiseStartLegacyDownload(TEST_INTERRUPTIBLE_URI, false,
outPersist);
let download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"),
false, outPersist);
try {
// Cancel the download after receiving the first part of the response.
@ -260,7 +263,7 @@ add_task(function test_cancel_midway()
do_check_true(download.canceled);
do_check_true(download.error === null);
do_check_false(download.target.file.exists());
do_check_false(yield OS.File.exists(download.target.path));
// Progress properties are not reset by canceling.
do_check_eq(download.progress, 50);
@ -278,7 +281,9 @@ add_task(function test_error()
{
let serverSocket = startFakeServer();
try {
let download = yield promiseStartLegacyDownload(TEST_FAKE_SOURCE_URI);
let sourceUrl = "http://localhost:" + serverSocket.port + "/source.txt";
let download = yield promiseStartLegacyDownload(sourceUrl);
// We must check the download properties instead of calling the "start"
// method because the download has been started and may already be stopped.
@ -307,8 +312,8 @@ add_task(function test_error()
*/
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 sourcePath = "/test_download_public_and_private.txt";
let sourceUrl = httpUrl("test_download_public_and_private.txt");
let testCount = 0;
// Apply pref to allow all cookies.
@ -317,12 +322,12 @@ add_task(function test_download_public_and_private()
function cleanup() {
Services.prefs.clearUserPref("network.cookie.cookieBehavior");
Services.cookies.removeAll();
gHttpServer.registerPathHandler(source_path, null);
gHttpServer.registerPathHandler(sourcePath, null);
}
do_register_cleanup(cleanup);
gHttpServer.registerPathHandler(source_path, function (aRequest, aResponse) {
gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
aResponse.setHeader("Content-Type", "text/plain", false);
if (testCount == 0) {
@ -342,9 +347,9 @@ add_task(function test_download_public_and_private()
});
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);
yield Downloads.simpleDownload(sourceUrl, targetFile);
yield Downloads.simpleDownload(sourceUrl, targetFile);
let download = yield promiseStartLegacyDownload(sourceUrl, true);
// The download is already started, wait for completion and report any errors.
if (!download.stopped) {
yield download.start();
@ -373,7 +378,7 @@ add_task(function test_download_blocked_parental_controls()
do_check_true(ex.becauseBlockedByParentalControls);
}
do_check_false(download.target.file.exists());
do_check_false(yield OS.File.exists(download.target.path));
cleanup();
});

View File

@ -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 downloadTwo = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
list.add(downloadOne);
list.add(downloadTwo);

View File

@ -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 promiseSimpleDownload(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" });

View File

@ -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);
});
/**