mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
bug 915036 - Implement DownloadSource.adjustChannel callback to support POST requests r=Paolo
MozReview-Commit-ID: 1RplqGhjtn6 --HG-- extra : rebase_source : 72c1300be889a61740cf6eca9c9e21fb979504a7
This commit is contained in:
parent
e4fa3c53f8
commit
1975d67b88
@ -1105,8 +1105,9 @@ this.Download.prototype = {
|
||||
};
|
||||
|
||||
let saver = this.saver.toSerializable();
|
||||
if (!saver) {
|
||||
// If we are unable to serialize the saver, we won't persist the download.
|
||||
if (!serializable.source || !saver) {
|
||||
// If we are unable to serialize either the source or the saver,
|
||||
// we won't persist the download.
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1275,6 +1276,23 @@ this.DownloadSource.prototype = {
|
||||
*/
|
||||
referrer: null,
|
||||
|
||||
/**
|
||||
* For downloads handled by the (default) DownloadCopySaver, this function
|
||||
* can adjust the network channel before it is opened, for example to change
|
||||
* the HTTP headers or to upload a stream as POST data.
|
||||
*
|
||||
* @note If this is defined this object will not be serializable, thus the
|
||||
* Download object will not be persisted across sessions.
|
||||
*
|
||||
* @param aChannel
|
||||
* The nsIChannel to be adjusted.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the channel has been adjusted and can be opened.
|
||||
* @rejects JavaScript exception that will cause the download to fail.
|
||||
*/
|
||||
adjustChannel: null,
|
||||
|
||||
/**
|
||||
* Returns a static representation of the current object state.
|
||||
*
|
||||
@ -1282,6 +1300,11 @@ this.DownloadSource.prototype = {
|
||||
*/
|
||||
toSerializable: function ()
|
||||
{
|
||||
if (this.adjustChannel) {
|
||||
// If the callback was used, we can't reproduce this across sessions.
|
||||
return null;
|
||||
}
|
||||
|
||||
// Simplify the representation if we don't have other details.
|
||||
if (!this.isPrivate && !this.referrer && !this._unknownProperties) {
|
||||
return this.url;
|
||||
@ -1314,6 +1337,10 @@ this.DownloadSource.prototype = {
|
||||
* 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.
|
||||
* adjustChannel: For downloads handled by (default) DownloadCopySaver,
|
||||
* this function can adjust the network channel before
|
||||
* it is opened, for example to change the HTTP headers
|
||||
* or to upload a stream as POST data. Optional.
|
||||
* }
|
||||
*
|
||||
* @return The newly created DownloadSource object.
|
||||
@ -1338,6 +1365,9 @@ this.DownloadSource.fromSerializable = function (aSerializable) {
|
||||
if ("referrer" in aSerializable) {
|
||||
source.referrer = aSerializable.referrer;
|
||||
}
|
||||
if ("adjustChannel" in aSerializable) {
|
||||
source.adjustChannel = aSerializable.adjustChannel;
|
||||
}
|
||||
|
||||
deserializeUnknownProperties(source, aSerializable, property =>
|
||||
property != "url" && property != "isPrivate" && property != "referrer");
|
||||
@ -2012,6 +2042,11 @@ this.DownloadCopySaver.prototype = {
|
||||
onStatus: function () { },
|
||||
};
|
||||
|
||||
// If the callback was set, handle it now before opening the channel.
|
||||
if (download.source.adjustChannel) {
|
||||
yield download.source.adjustChannel(channel);
|
||||
}
|
||||
|
||||
// Open the channel, directing output to the background file saver.
|
||||
backgroundFileSaver.QueryInterface(Ci.nsIStreamListener);
|
||||
channel.asyncOpen2({
|
||||
@ -2843,4 +2878,3 @@ this.DownloadPDFSaver.prototype = {
|
||||
this.DownloadPDFSaver.fromSerializable = function (aSerializable) {
|
||||
return new DownloadPDFSaver();
|
||||
};
|
||||
|
||||
|
@ -340,6 +340,58 @@ add_task(function* test_referrer()
|
||||
cleanup();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks the adjustChannel callback for downloads.
|
||||
*/
|
||||
add_task(function* test_adjustChannel()
|
||||
{
|
||||
const sourcePath = "/test_post.txt";
|
||||
const sourceUrl = httpUrl("test_post.txt");
|
||||
const targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
|
||||
const customHeader = { name: "X-Answer", value: "42" };
|
||||
const postData = "Don't Panic";
|
||||
|
||||
function cleanup() {
|
||||
gHttpServer.registerPathHandler(sourcePath, null);
|
||||
}
|
||||
do_register_cleanup(cleanup);
|
||||
|
||||
gHttpServer.registerPathHandler(sourcePath, aRequest => {
|
||||
do_check_eq(aRequest.method, "POST");
|
||||
|
||||
do_check_true(aRequest.hasHeader(customHeader.name));
|
||||
do_check_eq(aRequest.getHeader(customHeader.name), customHeader.value);
|
||||
|
||||
const stream = aRequest.bodyInputStream;
|
||||
const body = NetUtil.readInputStreamToString(stream, stream.available());
|
||||
do_check_eq(body, postData);
|
||||
});
|
||||
|
||||
function adjustChannel(channel) {
|
||||
channel.QueryInterface(Ci.nsIHttpChannel);
|
||||
channel.setRequestHeader(customHeader.name, customHeader.value, false);
|
||||
|
||||
const stream = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
stream.setData(postData, postData.length);
|
||||
|
||||
channel.QueryInterface(Ci.nsIUploadChannel2);
|
||||
channel.explicitSetUploadStream(stream, null, -1, "POST", false);
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const download = yield Downloads.createDownload({
|
||||
source: { url: sourceUrl, adjustChannel },
|
||||
target: targetPath,
|
||||
});
|
||||
do_check_eq(download.source.adjustChannel, adjustChannel);
|
||||
do_check_eq(download.toSerializable(), null);
|
||||
yield download.start();
|
||||
|
||||
cleanup();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks initial and final state and progress for a successful download.
|
||||
*/
|
||||
|
@ -66,6 +66,15 @@ add_task(function* test_save_reload()
|
||||
});
|
||||
listForSave.add(pdfDownload);
|
||||
|
||||
// If we used a callback to adjust the channel, the download should
|
||||
// not be serialized because we can't recreate it across sessions.
|
||||
let adjustedDownload = yield Downloads.createDownload({
|
||||
source: { url: httpUrl("empty.txt"),
|
||||
adjustChannel: () => Promise.resolve() },
|
||||
target: getTempFile(TEST_TARGET_FILE_NAME),
|
||||
});
|
||||
listForSave.add(adjustedDownload);
|
||||
|
||||
let legacyDownload = yield promiseStartLegacyDownload();
|
||||
yield legacyDownload.cancel();
|
||||
listForSave.add(legacyDownload);
|
||||
@ -73,7 +82,8 @@ add_task(function* test_save_reload()
|
||||
yield storeForSave.save();
|
||||
yield storeForLoad.load();
|
||||
|
||||
// Remove the PDF download because it should not appear in this list.
|
||||
// Remove the PDF and adjusted downloads because they should not appear here.
|
||||
listForSave.remove(adjustedDownload);
|
||||
listForSave.remove(pdfDownload);
|
||||
|
||||
let itemsForSave = yield listForSave.getAll();
|
||||
|
Loading…
Reference in New Issue
Block a user