bug 983747 - Add 'download' method to Browser API r=kanru,paolo
This commit is contained in:
@@ -135,6 +135,7 @@ function BrowserElementParent(frameLoader, hasRemoteFrame, isPendingFrame) {
|
|||||||
defineNoReturnMethod('goForward', this._goForward);
|
defineNoReturnMethod('goForward', this._goForward);
|
||||||
defineNoReturnMethod('reload', this._reload);
|
defineNoReturnMethod('reload', this._reload);
|
||||||
defineNoReturnMethod('stop', this._stop);
|
defineNoReturnMethod('stop', this._stop);
|
||||||
|
defineMethod('download', this._download);
|
||||||
defineDOMRequestMethod('purgeHistory', 'purge-history');
|
defineDOMRequestMethod('purgeHistory', 'purge-history');
|
||||||
defineMethod('getScreenshot', this._getScreenshot);
|
defineMethod('getScreenshot', this._getScreenshot);
|
||||||
defineMethod('addNextPaintListener', this._addNextPaintListener);
|
defineMethod('addNextPaintListener', this._addNextPaintListener);
|
||||||
@@ -620,6 +621,106 @@ BrowserElementParent.prototype = {
|
|||||||
this._sendAsyncMsg('stop');
|
this._sendAsyncMsg('stop');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_download: function(_url, _options) {
|
||||||
|
let ioService =
|
||||||
|
Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
|
||||||
|
let uri = ioService.newURI(_url, null, null);
|
||||||
|
let url = uri.QueryInterface(Ci.nsIURL);
|
||||||
|
|
||||||
|
// Ensure we have _options, we always use it to send the filename.
|
||||||
|
_options = _options || {};
|
||||||
|
if (!_options.filename) {
|
||||||
|
_options.filename = url.fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('_options = ' + uneval(_options));
|
||||||
|
|
||||||
|
// Ensure we have a filename.
|
||||||
|
if (!_options.filename) {
|
||||||
|
throw Components.Exception("Invalid argument", Cr.NS_ERROR_INVALID_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
let interfaceRequestor =
|
||||||
|
this._frameLoader.loadContext.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||||
|
let req = Services.DOMRequest.createRequest(this._window);
|
||||||
|
|
||||||
|
function DownloadListener() {
|
||||||
|
debug('DownloadListener Constructor');
|
||||||
|
}
|
||||||
|
DownloadListener.prototype = {
|
||||||
|
extListener: null,
|
||||||
|
onStartRequest: function(aRequest, aContext) {
|
||||||
|
debug('DownloadListener - onStartRequest');
|
||||||
|
let extHelperAppSvc =
|
||||||
|
Cc['@mozilla.org/uriloader/external-helper-app-service;1'].
|
||||||
|
getService(Ci.nsIExternalHelperAppService);
|
||||||
|
let channel = aRequest.QueryInterface(Ci.nsIChannel);
|
||||||
|
|
||||||
|
this.extListener =
|
||||||
|
extHelperAppSvc.doContent(
|
||||||
|
channel.contentType,
|
||||||
|
aRequest,
|
||||||
|
interfaceRequestor,
|
||||||
|
true);
|
||||||
|
this.extListener.onStartRequest(aRequest, aContext);
|
||||||
|
},
|
||||||
|
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||||
|
debug('DownloadListener - onStopRequest (aStatusCode = ' +
|
||||||
|
aStatusCode + ')');
|
||||||
|
if (aStatusCode == Cr.NS_OK) {
|
||||||
|
// Everything looks great.
|
||||||
|
debug('DownloadListener - Download Successful.');
|
||||||
|
this.services.DOMRequest.fireSuccess(this.req, aStatusCode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// In case of failure, we'll simply return the failure status code.
|
||||||
|
debug('DownloadListener - Download Failed!');
|
||||||
|
this.services.DOMRequest.fireError(this.req, aStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.extListener) {
|
||||||
|
this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDataAvailable: function(aRequest, aContext, aInputStream,
|
||||||
|
aOffset, aCount) {
|
||||||
|
this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
|
||||||
|
aOffset, aCount);
|
||||||
|
},
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener,
|
||||||
|
Ci.nsIRequestObserver])
|
||||||
|
};
|
||||||
|
|
||||||
|
let channel = ioService.newChannelFromURI(url);
|
||||||
|
|
||||||
|
// XXX We would set private browsing information prior to calling this.
|
||||||
|
channel.notificationCallbacks = interfaceRequestor;
|
||||||
|
|
||||||
|
// Since we're downloading our own local copy we'll want to bypass the
|
||||||
|
// cache and local cache if the channel let's us specify this.
|
||||||
|
let flags = Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS |
|
||||||
|
Ci.nsIChannel.LOAD_BYPASS_CACHE;
|
||||||
|
if (channel instanceof Ci.nsICachingChannel) {
|
||||||
|
debug('This is a caching channel. Forcing bypass.');
|
||||||
|
flags |= Ci.nsICachingChannel.LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.loadFlags |= flags;
|
||||||
|
|
||||||
|
if (channel instanceof Ci.nsIHttpChannel) {
|
||||||
|
debug('Setting HTTP referrer = ' + this._window.document.documentURIObject);
|
||||||
|
channel.referrer = this._window.document.documentURIObject;
|
||||||
|
if (channel instanceof Ci.nsIHttpChannelInternal) {
|
||||||
|
channel.forceAllowThirdPartyCookie = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set-up complete, let's get things started.
|
||||||
|
channel.asyncOpen(new DownloadListener(), null);
|
||||||
|
|
||||||
|
return req;
|
||||||
|
},
|
||||||
|
|
||||||
_getScreenshot: function(_width, _height, _mimeType) {
|
_getScreenshot: function(_width, _height, _mimeType) {
|
||||||
let width = parseInt(_width);
|
let width = parseInt(_width);
|
||||||
let height = parseInt(_height);
|
let height = parseInt(_height);
|
||||||
|
|||||||
37
dom/browser-element/mochitest/browserElement_Download.js
Normal file
37
dom/browser-element/mochitest/browserElement_Download.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/* Any copyright is dedicated to the public domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Bug 983747 - Test 'download' method on iframe.
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
browserElementTestHelpers.setEnabledPref(true);
|
||||||
|
browserElementTestHelpers.addPermission();
|
||||||
|
|
||||||
|
var iframe;
|
||||||
|
var downloadURL = 'http://test/tests/dom/browser-element/mochitest/file_download_bin.sjs';
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
iframe = document.createElement('iframe');
|
||||||
|
SpecialPowers.wrap(iframe).mozbrowser = true;
|
||||||
|
|
||||||
|
iframe.addEventListener('mozbrowserloadend', loadend);
|
||||||
|
iframe.src = 'data:text/html,<html><body>hello</body></html>';
|
||||||
|
iframe.setAttribute('remote', 'true');
|
||||||
|
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadend() {
|
||||||
|
var req = iframe.download(downloadURL, { filename: 'test.bin' });
|
||||||
|
req.onsuccess = function() {
|
||||||
|
ok(true, 'Download finished as expected.');
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
req.onerror = function() {
|
||||||
|
ok(false, 'Expected no error, got ' + req.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener('testready', runTest);
|
||||||
4
dom/browser-element/mochitest/file_download_bin.sjs
Normal file
4
dom/browser-element/mochitest/file_download_bin.sjs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
function handleRequest(request, response) {
|
||||||
|
response.setHeader("Content-Type", "application/octet-stream", false);
|
||||||
|
response.write("BIN");
|
||||||
|
}
|
||||||
@@ -30,6 +30,8 @@ skip-if = (toolkit == 'gonk' && !debug)
|
|||||||
[test_browserElement_oop_DOMRequestError.html]
|
[test_browserElement_oop_DOMRequestError.html]
|
||||||
[test_browserElement_oop_DataURI.html]
|
[test_browserElement_oop_DataURI.html]
|
||||||
[test_browserElement_oop_DocumentFirstPaint.html]
|
[test_browserElement_oop_DocumentFirstPaint.html]
|
||||||
|
[test_browserElement_oop_Download.html]
|
||||||
|
disabled = bug 1022281
|
||||||
[test_browserElement_oop_ErrorSecurity.html]
|
[test_browserElement_oop_ErrorSecurity.html]
|
||||||
skip-if = (toolkit == 'gonk' && !debug)
|
skip-if = (toolkit == 'gonk' && !debug)
|
||||||
[test_browserElement_oop_FirstPaint.html]
|
[test_browserElement_oop_FirstPaint.html]
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ support-files =
|
|||||||
browserElement_DOMRequestError.js
|
browserElement_DOMRequestError.js
|
||||||
browserElement_DataURI.js
|
browserElement_DataURI.js
|
||||||
browserElement_DocumentFirstPaint.js
|
browserElement_DocumentFirstPaint.js
|
||||||
|
browserElement_Download.js
|
||||||
browserElement_ErrorSecurity.js
|
browserElement_ErrorSecurity.js
|
||||||
browserElement_ExposableURI.js
|
browserElement_ExposableURI.js
|
||||||
browserElement_FirstPaint.js
|
browserElement_FirstPaint.js
|
||||||
@@ -96,6 +97,7 @@ support-files =
|
|||||||
file_browserElement_XFrameOptionsSameOrigin.html
|
file_browserElement_XFrameOptionsSameOrigin.html
|
||||||
file_bug709759.sjs
|
file_bug709759.sjs
|
||||||
file_bug741717.sjs
|
file_bug741717.sjs
|
||||||
|
file_download_bin.sjs
|
||||||
file_empty.html
|
file_empty.html
|
||||||
file_empty_script.js
|
file_empty_script.js
|
||||||
file_focus.html
|
file_focus.html
|
||||||
@@ -134,6 +136,8 @@ skip-if = buildapp == 'b2g'
|
|||||||
[test_browserElement_inproc_DOMRequestError.html]
|
[test_browserElement_inproc_DOMRequestError.html]
|
||||||
[test_browserElement_inproc_DataURI.html]
|
[test_browserElement_inproc_DataURI.html]
|
||||||
[test_browserElement_inproc_DocumentFirstPaint.html]
|
[test_browserElement_inproc_DocumentFirstPaint.html]
|
||||||
|
[test_browserElement_inproc_Download.html]
|
||||||
|
disabled = bug 1022281
|
||||||
[test_browserElement_inproc_ExposableURI.html]
|
[test_browserElement_inproc_ExposableURI.html]
|
||||||
[test_browserElement_inproc_FirstPaint.html]
|
[test_browserElement_inproc_FirstPaint.html]
|
||||||
[test_browserElement_inproc_ForwardName.html]
|
[test_browserElement_inproc_ForwardName.html]
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test for Bug 983747</title>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="application/javascript;version=1.7" src="browserElement_Download.js">
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test for Bug 983747</title>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="application/javascript;version=1.7" src="browserElement_Download.js">
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1391,8 +1391,18 @@ this.DownloadSaver.prototype = {
|
|||||||
// The start time is always available when we reach this point.
|
// The start time is always available when we reach this point.
|
||||||
let startPRTime = this.download.startTime.getTime() * 1000;
|
let startPRTime = this.download.startTime.getTime() * 1000;
|
||||||
|
|
||||||
|
try {
|
||||||
gDownloadHistory.addDownload(sourceUri, referrerUri, startPRTime,
|
gDownloadHistory.addDownload(sourceUri, referrerUri, startPRTime,
|
||||||
targetUri);
|
targetUri);
|
||||||
|
}
|
||||||
|
catch(ex if ex instanceof Components.Exception &&
|
||||||
|
ex.result == Cr.NS_ERROR_NOT_AVAILABLE) {
|
||||||
|
//
|
||||||
|
// Under normal operation the download history service may not
|
||||||
|
// be available. We don't want all downloads that are public to fail
|
||||||
|
// when this happens so we'll ignore this error and this error only!
|
||||||
|
//
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user