Bug 1451991 - Devtools: Localstorage didn't list item whose key names "key" r?nchevobbe draft
authorMike Ratcliffe <mratcliffe@mozilla.com>
Sat, 14 Apr 2018 00:33:42 +0100
changeset 784396 c159cdda599b1bdff62e023b45ee5bc1db8730e9
parent 782003 6547c27303bc4d8961b11e656751e839807d65c7
push id106928
push userbmo:mratcliffe@mozilla.com
push dateWed, 18 Apr 2018 15:40:57 +0000
reviewersnchevobbe
bugs1451991
milestone61.0a1
Bug 1451991 - Devtools: Localstorage didn't list item whose key names "key" r?nchevobbe MozReview-Commit-ID: 3AQC47GKud0
devtools/client/storage/test/browser_storage_basic.js
devtools/client/storage/test/browser_storage_basic_usercontextid_1.js
devtools/client/storage/test/browser_storage_delete_all.js
devtools/client/storage/test/browser_storage_delete_tree.js
devtools/client/storage/test/browser_storage_delete_usercontextid.js
devtools/client/storage/test/browser_storage_dom_cache_disabled.js
devtools/client/storage/test/storage-listings.html
devtools/server/actors/storage.js
--- a/devtools/client/storage/test/browser_storage_basic.js
+++ b/devtools/client/storage/test/browser_storage_basic.js
@@ -43,23 +43,23 @@ const testCases = [
       getCookieId("c4", ".example.org", "/"),
       getCookieId("sc1", "sectest1.example.org",
         "/browser/devtools/client/storage/test/"),
       getCookieId("sc2", "sectest1.example.org",
         "/browser/devtools/client/storage/test/")
     ]
   ],
   [["localStorage", "http://test1.example.org"],
-   ["ls1", "ls2"]],
+   ["key", "ls1", "ls2"]],
   [["localStorage", "http://sectest1.example.org"],
    ["iframe-u-ls1"]],
   [["localStorage", "https://sectest1.example.org"],
    ["iframe-s-ls1"]],
   [["sessionStorage", "http://test1.example.org"],
-   ["ss1"]],
+   ["key", "ss1"]],
   [["sessionStorage", "http://sectest1.example.org"],
    ["iframe-u-ss1", "iframe-u-ss2"]],
   [["sessionStorage", "https://sectest1.example.org"],
    ["iframe-s-ss1"]],
   [["indexedDB", "http://test1.example.org"],
    ["idb1 (default)", "idb2 (default)"]],
   [["indexedDB", "http://test1.example.org", "idb1 (default)"],
    ["obj1", "obj2"]],
--- a/devtools/client/storage/test/browser_storage_basic_usercontextid_1.js
+++ b/devtools/client/storage/test/browser_storage_basic_usercontextid_1.js
@@ -28,23 +28,23 @@ const testCases = [
       getCookieId("c4", ".example.org", "/"),
       getCookieId("sc1", "sectest1.example.org",
         "/browser/devtools/client/storage/test/"),
       getCookieId("sc2", "sectest1.example.org",
         "/browser/devtools/client/storage/test/")
     ]
   ],
   [["localStorage", "http://test1.example.org"],
-   ["ls1", "ls2"]],
+   ["key", "ls1", "ls2"]],
   [["localStorage", "http://sectest1.example.org"],
    ["iframe-u-ls1"]],
   [["localStorage", "https://sectest1.example.org"],
    ["iframe-s-ls1"]],
   [["sessionStorage", "http://test1.example.org"],
-   ["ss1"]],
+   ["key", "ss1"]],
   [["sessionStorage", "http://sectest1.example.org"],
    ["iframe-u-ss1", "iframe-u-ss2"]],
   [["sessionStorage", "https://sectest1.example.org"],
    ["iframe-s-ss1"]],
   [["indexedDB", "http://test1.example.org"],
    ["idb1 (default)", "idb2 (default)"]],
   [["indexedDB", "http://test1.example.org", "idb1 (default)"],
    ["obj1", "obj2"]],
--- a/devtools/client/storage/test/browser_storage_delete_all.js
+++ b/devtools/client/storage/test/browser_storage_delete_all.js
@@ -13,23 +13,23 @@ add_task(async function() {
 
   let contextMenu = gPanelWindow.document.getElementById("storage-table-popup");
   let menuDeleteAllItem = contextMenu.querySelector(
     "#storage-table-popup-delete-all");
 
   info("test state before delete");
   const beforeState = [
     [["localStorage", "http://test1.example.org"],
-      ["ls1", "ls2"]],
+      ["key", "ls1", "ls2"]],
     [["localStorage", "http://sectest1.example.org"],
       ["iframe-u-ls1"]],
     [["localStorage", "https://sectest1.example.org"],
       ["iframe-s-ls1"]],
     [["sessionStorage", "http://test1.example.org"],
-      ["ss1"]],
+      ["key", "ss1"]],
     [["sessionStorage", "http://sectest1.example.org"],
       ["iframe-u-ss1", "iframe-u-ss2"]],
     [["sessionStorage", "https://sectest1.example.org"],
       ["iframe-s-ss1"]],
     [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
       [1, 2, 3]],
     [["Cache", "http://test1.example.org", "plop"],
       [MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
@@ -62,23 +62,23 @@ add_task(async function() {
     await eventWait;
   }
 
   info("test state after delete");
   const afterState = [
     // iframes from the same host, one secure, one unsecure, are independent
     // from each other. Delete all in one doesn't touch the other one.
     [["localStorage", "http://test1.example.org"],
-      ["ls1", "ls2"]],
+      ["key", "ls1", "ls2"]],
     [["localStorage", "http://sectest1.example.org"],
       ["iframe-u-ls1"]],
     [["localStorage", "https://sectest1.example.org"],
       []],
     [["sessionStorage", "http://test1.example.org"],
-      ["ss1"]],
+      ["key", "ss1"]],
     [["sessionStorage", "http://sectest1.example.org"],
       ["iframe-u-ss1", "iframe-u-ss2"]],
     [["sessionStorage", "https://sectest1.example.org"],
       []],
     [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
       []],
     [["Cache", "http://test1.example.org", "plop"],
       []],
--- a/devtools/client/storage/test/browser_storage_delete_tree.js
+++ b/devtools/client/storage/test/browser_storage_delete_tree.js
@@ -23,18 +23,18 @@ add_task(async function() {
         getCookieId("c1", "test1.example.org", "/browser"),
         getCookieId("cs2", ".example.org", "/"),
         getCookieId("c3", "test1.example.org", "/"),
         getCookieId("c4", ".example.org", "/"),
         getCookieId("uc1", ".example.org", "/"),
         getCookieId("uc2", ".example.org", "/")
       ]
     ],
-    [["localStorage", "http://test1.example.org"], ["ls1", "ls2"]],
-    [["sessionStorage", "http://test1.example.org"], ["ss1"]],
+    [["localStorage", "http://test1.example.org"], ["key", "ls1", "ls2"]],
+    [["sessionStorage", "http://test1.example.org"], ["key", "ss1"]],
     [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"], [1, 2, 3]],
     [["Cache", "http://test1.example.org", "plop"],
       [MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
   ]);
 
   info("do the delete");
   const deleteHosts = [
     ["cookies", "http://test1.example.org"],
--- a/devtools/client/storage/test/browser_storage_delete_usercontextid.js
+++ b/devtools/client/storage/test/browser_storage_delete_usercontextid.js
@@ -46,23 +46,23 @@ const storageItemsForDefault = [
       getCookieId("c4", ".example.org", "/"),
       getCookieId("sc1", "sectest1.example.org",
         "/browser/devtools/client/storage/test/"),
       getCookieId("sc2", "sectest1.example.org",
         "/browser/devtools/client/storage/test/")
     ]
   ],
   [["localStorage", "http://test1.example.org"],
-   ["ls1", "ls2"]],
+   ["key", "ls1", "ls2"]],
   [["localStorage", "http://sectest1.example.org"],
    ["iframe-u-ls1"]],
   [["localStorage", "https://sectest1.example.org"],
    ["iframe-s-ls1"]],
   [["sessionStorage", "http://test1.example.org"],
-   ["ss1"]],
+   ["key", "ss1"]],
   [["sessionStorage", "http://sectest1.example.org"],
    ["iframe-u-ss1", "iframe-u-ss2"]],
   [["sessionStorage", "https://sectest1.example.org"],
    ["iframe-s-ss1"]],
   [["indexedDB", "http://test1.example.org"],
    ["idb1 (default)", "idb2 (default)"]],
   [["indexedDB", "http://test1.example.org", "idb1 (default)"],
    ["obj1", "obj2"]],
--- a/devtools/client/storage/test/browser_storage_dom_cache_disabled.js
+++ b/devtools/client/storage/test/browser_storage_dom_cache_disabled.js
@@ -11,23 +11,23 @@
 add_task(async function() {
   // Disable the DOM cache
   Services.prefs.setBoolPref(DOM_CACHE, false);
 
   await openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
 
   const state = [
     [["localStorage", "http://test1.example.org"],
-      ["ls1", "ls2"]],
+      ["key", "ls1", "ls2"]],
     [["localStorage", "http://sectest1.example.org"],
       ["iframe-u-ls1"]],
     [["localStorage", "https://sectest1.example.org"],
       ["iframe-s-ls1"]],
     [["sessionStorage", "http://test1.example.org"],
-      ["ss1"]],
+      ["key", "ss1"]],
     [["sessionStorage", "http://sectest1.example.org"],
       ["iframe-u-ss1", "iframe-u-ss2"]],
     [["sessionStorage", "https://sectest1.example.org"],
       ["iframe-s-ss1"]],
     [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
       [1, 2, 3]],
   ];
 
--- a/devtools/client/storage/test/storage-listings.html
+++ b/devtools/client/storage/test/storage-listings.html
@@ -22,18 +22,30 @@ document.cookie = "cs2=sessionCookie; pa
 document.cookie = "c3=foobar-2; expires=" +
   new Date(cookieExpiresTime1).toGMTString() + "; path=/";
 document.cookie = "c4=foobar-3; expires=" +
   new Date(cookieExpiresTime2).toGMTString() + "; path=/; domain=" +
   partialHostname;
 // ... and some local storage items ..
 localStorage.setItem("ls1", "foobar");
 localStorage.setItem("ls2", "foobar-2");
+
+// Because localStorage contains key() on the prototype and it can't be iterated
+// using object.keys() we check the the value "key" exists.
+// See bug 1451991 for details.
+localStorage.setItem("key", "value1");
+
 // ... and finally some session storage items too
 sessionStorage.setItem("ss1", "foobar-3");
+
+// Because sessionStorage contains key() on the prototype and it can't be
+// iterated using object.keys() we check the the value "key" exists.
+// See bug 1451991 for details.
+sessionStorage.setItem("key", "value2");
+
 dump("added cookies and storage from main page\n");
 
 let idbGenerator = async function () {
   let request = indexedDB.open("idb1", 1);
   request.onerror = function() {
     throw new Error("error opening db connection");
   };
   let db = await new Promise(done => {
--- a/devtools/server/actors/storage.js
+++ b/devtools/server/actors/storage.js
@@ -1163,20 +1163,30 @@ function getObjectForLocalOrSessionStora
       }
       if (name) {
         let value = storage ? storage.getItem(name) : null;
         return [{ name, value }];
       }
       if (!storage) {
         return [];
       }
-      return Object.keys(storage).map(key => ({
-        name: key,
-        value: storage.getItem(key)
-      }));
+
+      // local and session storage cannot be iterated over using Object.keys()
+      // because it skips keys that are duplicated on the prototype
+      // e.g. "key", "getKeys" so we need to gather the real keys using the
+      // storage.key() function.
+      const storageArray = [];
+      for (let i = 0; i < storage.length; i++) {
+        const key = storage.key(i);
+        storageArray.push({
+          name: key,
+          value: storage.getItem(key)
+        });
+      }
+      return storageArray;
     },
 
     populateStoresForHost(host, window) {
       try {
         this.hostVsStores.set(host, window[type]);
       } catch (ex) {
         console.warn(`Failed to enumerate ${type} for host ${host}: ${ex}`);
       }