Bug 957592. Expose download API properties based on permission. r=bz

This commit is contained in:
Ghislain 'Aus' Lacroix 2014-01-24 11:53:05 -08:00
parent 31e2c39c23
commit dd08be1bd2
8 changed files with 101 additions and 34 deletions

View File

@ -865,9 +865,6 @@ pref("media.webspeech.synth.enabled", true);
pref("dom.mozDownloads.enabled", true);
pref("dom.downloads.max_retention_days", 7);
// Downloads API
pref("dom.mozDownloads.enabled", true);
// Inactivity time in milliseconds after which we shut down the OS.File worker.
pref("osfile.reset_worker_delay", 5000);

View File

@ -1916,6 +1916,27 @@ Navigator::HasDataStoreSupport(JSContext* cx, JSObject* aGlobal)
return status == nsIPrincipal::APP_STATUS_CERTIFIED;
}
/* static */
bool
Navigator::HasDownloadsSupport(JSContext* aCx, JSObject* aGlobal)
{
// We'll need a rooted object so that GC doesn't make it go away while
// we're calling CheckIsChrome.
JS::Rooted<JSObject*> global(aCx, aGlobal);
// Because of the way this API must be implemented, it will interact with
// objects attached to a chrome window. We always want to allow this.
if (ThreadsafeCheckIsChrome(aCx, global)) {
return true;
}
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(global);
return win &&
CheckPermission(win, "downloads") &&
Preferences::GetBool("dom.mozDownloads.enabled");
}
/* static */
already_AddRefed<nsPIDOMWindow>
Navigator::GetWindowFromGlobal(JSObject* aGlobal)

View File

@ -290,6 +290,8 @@ public:
static bool HasDataStoreSupport(JSContext* cx, JSObject* aGlobal);
static bool HasDownloadsSupport(JSContext* aCx, JSObject* aGlobal);
nsPIDOMWindow* GetParentObject() const
{
return GetWindow();

View File

@ -206,12 +206,12 @@ function DOMDownloadImpl() {
this.currentBytes = 0;
this.url = null;
this.path = null;
this.state = "stopped";
this.contentType = null;
/* fields that require getters/setters */
this._error = null;
this._startTime = new Date();
this._state = "stopped";
/* private fields */
this.id = null;
@ -270,6 +270,25 @@ DOMDownloadImpl.prototype = {
}
},
get state() {
return this._state;
},
// We require a setter here to simplify the internals of the Download Manager
// since we actually pass dummy JSON objects to the child process and update
// them. This is the case for all other setters for read-only attributes
// implemented in this object.
set state(aState) {
// We need to ensure that XPCOM consumers of this API respect the enum
// values as well.
if (["downloading",
"stopped",
"succeeded",
"finalized"].indexOf(aState) != -1) {
this._state = aState;
}
},
_init: function(aWindow, aDownload) {
this._window = aWindow;
this.id = aDownload.id;

View File

@ -9,9 +9,6 @@ function getQuery(request) {
return query;
}
// Timer used to handle the request response.
var timer = null;
function handleResponse() {
// Is this a rate limited response?
if (this.state.rate > 0) {
@ -26,7 +23,24 @@ function handleResponse() {
(bytesToWrite > this.state.rate) ? this.state.rate : bytesToWrite;
for (let i = 0; i < bytesToWrite; i++) {
this.response.write("0");
try {
this.response.bodyOutputStream.write("0", 1);
} catch (e) {
// Connection was closed by client.
if (e == Components.results.NS_ERROR_NOT_AVAILABLE) {
// There's no harm in calling this multiple times.
this.response.finish();
// It's possible that our timer wasn't cancelled in time
// and we'll be called again.
if (this.timer) {
this.timer.cancel();
this.timer = null;
}
return;
}
}
}
// Update the number of bytes we've sent to the client.
@ -47,12 +61,19 @@ function handleResponse() {
this.response.finish();
// All done sending, go ahead and cancel our repeating timer.
timer.cancel();
this.timer.cancel();
// Clear the timer.
this.timer = null;
}
function handleRequest(request, response) {
var query = getQuery(request);
// sending at a specific rate requires our response to be asynchronous so
// we handle all requests asynchronously. See handleResponse().
response.processAsync();
// Default status when responding.
var version = "1.1";
var statusCode = 200;
@ -120,20 +141,17 @@ function handleRequest(request, response) {
totalBytes: size,
sentBytes: 0,
rate: rate
}
},
timer: null
};
// The notify implementation for the timer.
context.notify = handleResponse.bind(context);
timer =
context.timer =
Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
// sending at a specific rate requires our response to be asynchronous so
// we handle all requests asynchronously. See handleResponse().
response.processAsync();
// generate the content.
response.setStatusLine(version, statusCode, description);
response.setHeader("Content-Type", contentType, false);
@ -143,8 +161,10 @@ function handleRequest(request, response) {
response.setHeader("Content-Length", size.toString(), false);
// initialize the timer and start writing out the response.
timer.initWithCallback(context,
1000,
Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
context.timer.initWithCallback(
context,
1000,
Components.interfaces.nsITimer.TYPE_REPEATING_SLACK
);
}

View File

@ -326,12 +326,6 @@ var interfaceNamesInGlobalScope =
"DOMTokenList",
// IMPORTANT: Do not change this list without review from a DOM peer!
"DOMTransactionEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "DOMDownload", b2g: true, pref: "dom.mozDownloads.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "DOMDownloadManager", b2g: true, pref: "dom.mozDownloads.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "DownloadEvent", b2g: true, pref: "dom.mozDownloads.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"DragEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -5,7 +5,7 @@
*/
[Constructor(DOMString type, optional DownloadEventInit eventInitDict),
Pref="dom.mozDownloads.enabled"]
Func="Navigator::HasDownloadsSupport"]
interface DownloadEvent : Event
{
readonly attribute DOMDownload? download;

View File

@ -4,7 +4,26 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[NavigatorProperty="mozDownloadManager",
// Represents the state of a download.
// "downloading": The resource is actively transfering.
// "stopped" : No network tranfer is happening.
// "succeeded" : The resource has been downloaded successfully.
// "finalized" : We won't try to download this resource, but the DOM
// object is still alive.
enum DownloadState {
"downloading",
"stopped",
"succeeded",
"finalized"
};
//
// XXXTODO: When we have a generic way to do feature detection in marketplace
// we will *STOP* using the pref and use the function like DOMDownload
// and DownloadEvent.
//
[NoInterfaceObject,
NavigatorProperty="mozDownloadManager",
JSImplementation="@mozilla.org/downloads/manager;1",
Pref="dom.mozDownloads.enabled"]
interface DOMDownloadManager : EventTarget {
@ -24,7 +43,7 @@ interface DOMDownloadManager : EventTarget {
};
[JSImplementation="@mozilla.org/downloads/download;1",
Pref="dom.mozDownloads.enabled"]
Func="Navigator::HasDownloadsSupport"]
interface DOMDownload : EventTarget {
// The full size of the resource.
readonly attribute long totalBytes;
@ -39,13 +58,8 @@ interface DOMDownload : EventTarget {
// is complete.
readonly attribute DOMString path;
// The state of the download. Can be any of:
// "downloading": The resource is actively transfering.
// "stopped" : No network tranfer is happening.
// "succeeded" : The resource has been downloaded successfully.
// "finalized" : We won't try to download this resource, but the DOM
// object is still alive.
readonly attribute DOMString state;
// The state of the download.
readonly attribute DownloadState state;
// The mime type for this resource.
readonly attribute DOMString contentType;