Merge b2g-inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 20 Oct 2014 18:14:19 -0700
changeset 211366 bef7bff71ada987996aecd4c737fded957e7621a
parent 211364 39e79a5090c8c2e0494fbe5838eba7015601baa6 (current diff)
parent 211365 d917fc3dd79e3ff0f651fc539ef149f2a30b9ef3 (diff)
child 211370 290f799b4f58a39e19f9e1044754724973ab9463
push id50691
push userkwierso@gmail.com
push dateTue, 21 Oct 2014 02:08:21 +0000
treeherdermozilla-inbound@0808729b24e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge b2g-inbound to m-c a=merge
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -243,25 +243,26 @@ ContactManager.prototype = {
         access = "unknown";
       }
 
     // Shortcut for ALLOW_ACTION so we avoid a parent roundtrip
     let principal = this._window.document.nodePrincipal;
     let type = "contacts-" + access;
     let permValue =
       Services.perms.testExactPermissionFromPrincipal(principal, type);
+    DEBUG && debug("Existing permission " + permValue);
     if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
       if (aAllowCallback) {
         aAllowCallback();
       }
       return;
     } else if (permValue == Ci.nsIPermissionManager.DENY_ACTION ||
                permValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
       if (aCancelCallback) {
-        aCancelCallback();
+        aCancelCallback("PERMISSION_DENIED");
       }
       return;
     }
 
     // Create an array with a single nsIContentPermissionType element.
     type = {
       type: "contacts",
       access: access,
@@ -271,26 +272,24 @@ ContactManager.prototype = {
     let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
     typeArray.appendElement(type, false);
 
     // create a nsIContentPermissionRequest
     let request = {
       types: typeArray,
       principal: principal,
       QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
-      allow: aAllowCallback ||
-             function() {
-               if (DEBUG)
-                 debug("Default allow contacts callback. " + access +"\n");
-             },
-      cancel: aCancelCallback ||
-              function() {
-                if (DEBUG)
-                  debug("Default cancel contacts callback. " + access +"\n");
-              },
+      allow: function() {
+        aAllowCallback && aAllowCallback();
+        DEBUG && debug("Permission granted. Access " + access +"\n");
+      },
+      cancel: function() {
+        aCancelCallback && aCancelCallback("PERMISSION_DENIED");
+        DEBUG && debug("Permission denied. Access " + access +"\n");
+      },
       window: this._window
     };
 
     // Using askPermission from nsIDOMWindowUtils that takes care of the
     // remoting if needed.
     let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIDOMWindowUtils);
     windowUtils.askPermission(request);
@@ -331,30 +330,47 @@ ContactManager.prototype = {
     newContact.id = aContact.id;
     newContact.published = aContact.published;
     newContact.updated = aContact.updated;
 
     if (DEBUG) debug("send: " + JSON.stringify(newContact));
 
     let options = { contact: newContact, reason: reason };
     let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contact:Save", {requestID: requestID, options: options});
-    }.bind(this)
-    this.askPermission(reason, request, allowCallback);
+      cpmm.sendAsyncMessage("Contact:Save", {
+        requestID: requestID,
+        options: options
+      });
+    }.bind(this);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
+    };
+
+    this.askPermission(reason, request, allowCallback, cancelCallback);
     return request;
   },
 
   find: function(aOptions) {
     if (DEBUG) debug("find! " + JSON.stringify(aOptions));
     let request = this.createRequest();
     let options = { findOptions: aOptions };
+
     let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:Find", {requestID: this.getRequestId({request: request, reason: "find"}), options: options});
-    }.bind(this)
-    this.askPermission("find", request, allowCallback);
+      cpmm.sendAsyncMessage("Contacts:Find", {
+        requestID: this.getRequestId({request: request, reason: "find"}),
+        options: options
+      });
+    }.bind(this);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
+    };
+
+    this.askPermission("find", request, allowCallback, cancelCallback);
     return request;
   },
 
   createCursor: function CM_createCursor(aRequest) {
     let data = {
       cursor: Services.DOMRequest.createCursor(this._window, function() {
         this.handleContinue(id);
       }.bind(this)),
@@ -364,21 +380,29 @@ ContactManager.prototype = {
     let id = this.getRequestId(data);
     if (DEBUG) debug("saved cursor id: " + id);
     return [id, data.cursor];
   },
 
   getAll: function CM_getAll(aOptions) {
     if (DEBUG) debug("getAll: " + JSON.stringify(aOptions));
     let [cursorId, cursor] = this.createCursor();
+
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contacts:GetAll", {
-        cursorId: cursorId, findOptions: aOptions});
+        cursorId: cursorId,
+        findOptions: aOptions
+      });
     }.bind(this);
-    this.askPermission("find", cursor, allowCallback);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(cursor, reason);
+    };
+
+    this.askPermission("find", cursor, allowCallback, cancelCallback);
     return cursor;
   },
 
   nextTick: function nextTick(aCallback) {
     Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
   },
 
   handleContinue: function CM_handleContinue(aCursorId) {
@@ -407,62 +431,80 @@ ContactManager.prototype = {
     } else if (!aRecordOrId || !aRecordOrId.id) {
       Services.DOMRequest.fireErrorAsync(request, true);
       return request;
     } else {
       id = aRecordOrId.id;
     }
 
     let options = { id: id };
+
     let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contact:Remove", {requestID: this.getRequestId({request: request, reason: "remove"}), options: options});
+      cpmm.sendAsyncMessage("Contact:Remove", {
+        requestID: this.getRequestId({request: request, reason: "remove"}),
+        options: options
+      });
     }.bind(this);
-    this.askPermission("remove", request, allowCallback);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
+    };
+
+    this.askPermission("remove", request, allowCallback, cancelCallback);
     return request;
   },
 
   clear: function() {
     if (DEBUG) debug("clear");
     let request = this.createRequest();
     let options = {};
+
     let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:Clear", {requestID: this.getRequestId({request: request, reason: "remove"}), options: options});
+      cpmm.sendAsyncMessage("Contacts:Clear", {
+        requestID: this.getRequestId({request: request, reason: "remove"}),
+        options: options
+      });
     }.bind(this);
-    this.askPermission("remove", request, allowCallback);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
+    };
+
+    this.askPermission("remove", request, allowCallback, cancelCallback);
     return request;
   },
 
   getRevision: function() {
     let request = this.createRequest();
 
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contacts:GetRevision", {
         requestID: this.getRequestId({ request: request })
       });
     }.bind(this);
 
-    let cancelCallback = function() {
-      Services.DOMRequest.fireError(request, "");
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
     };
 
     this.askPermission("revision", request, allowCallback, cancelCallback);
     return request;
   },
 
   getCount: function() {
     let request = this.createRequest();
 
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contacts:GetCount", {
         requestID: this.getRequestId({ request: request })
       });
     }.bind(this);
 
-    let cancelCallback = function() {
-      Services.DOMRequest.fireError(request, "");
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
     };
 
     this.askPermission("count", request, allowCallback, cancelCallback);
     return request;
   },
 
   init: function(aWindow) {
     // DOMRequestIpcHelper.initHelper sets this._window
--- a/dom/contacts/tests/mochitest.ini
+++ b/dom/contacts/tests/mochitest.ini
@@ -16,9 +16,9 @@ skip-if = (toolkit == 'gonk' && debug) #
 [test_contacts_international.html]
 [test_contacts_substringmatching.html]
 [test_contacts_substringmatchingVE.html]
 [test_contacts_substringmatchingCL.html]
 [test_migration.html]
   support-files =
     test_migration_chrome.js
   skip-if = os == "android"
-
+[test_permission_denied.html]
new file mode 100644
--- /dev/null
+++ b/dom/contacts/tests/test_permission_denied.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1081873
+-->
+<head>
+  <title>Test for Bug 1081873</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081873">Mozilla Bug 1081873</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+"use strict";
+
+SpecialPowers.addPermission("contacts-write", false, document);
+SpecialPowers.addPermission("contacts-read", false, document);
+SpecialPowers.addPermission("contacts-create", false, document);
+
+function onUnexpectedSuccess() {
+  ok(false, "Unexpected success");
+  next();
+}
+
+function onExpectedError(event) {
+  is(event.target.error.name, PERMISSION_DENIED, "Expected PERMISSION_DENIED");
+  next();
+}
+
+const PERMISSION_DENIED = "PERMISSION_DENIED";
+
+var index = 0;
+
+function next() {
+  info("Step " + index);
+  if (index >= steps.length) {
+    ok(false, "Shouldn't get here!");
+    return;
+  }
+  try {
+    var i = index++;
+    steps[i]();
+  } catch(ex) {
+    ok(false, "Caught exception", ex);
+  }
+}
+
+var steps = [
+  function() {
+    ok(true, "Add contact without permission");
+    var req = navigator.mozContacts.save(new mozContact({}));
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Find contact without permission");
+    var req = navigator.mozContacts.find({});
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Get all contacts without permission");
+    var req = navigator.mozContacts.getAll();
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Remove contact without permission");
+    var req = navigator.mozContacts.remove("aId");
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Clear contacts without permission");
+    var req = navigator.mozContacts.clear();
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Get revision without permission");
+    var req = navigator.mozContacts.getRevision();
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Get count without permission");
+    var req = navigator.mozContacts.getCount();
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = function() {
+      is(req.error.name, PERMISSION_DENIED, "Expected PERMISSION_DENIED");
+      SimpleTest.finish();
+    };
+  }
+];
+
+SimpleTest.waitForExplicitFinish();
+
+const DENY = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
+var interval = setInterval(function() {
+  if (!SpecialPowers.testPermission("contacts-read", DENY, document) ||
+      !SpecialPowers.testPermission("contacts-write", DENY, document) ||
+      !SpecialPowers.testPermission("contacts-create", DENY, document)) {
+    return;
+  }
+  clearInterval(interval);
+  next();
+}, 1000);
+
+</script>
+</pre>
+</body>
+</html>