Bug 738647 - DOMStorageImpl::GetKey shouldn't throw; r=honzab
authorMs2ger <ms2ger@gmail.com>
Thu, 29 Mar 2012 23:09:09 +0200
changeset 90678 80aee211b0cefcc4e9079e569474cea6e052d7ad
parent 90677 dec46a6908cf2bea568475e0a47527af78cb5eb0
child 90679 8f188d9889412d9da432cae5356840616cdb9b79
push id7790
push usermak77@bonardo.net
push dateFri, 30 Mar 2012 10:28:34 +0000
treeherdermozilla-inbound@7bfb26afd19b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonzab
bugs738647
milestone14.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
Bug 738647 - DOMStorageImpl::GetKey shouldn't throw; r=honzab
dom/interfaces/storage/nsIDOMStorage.idl
dom/src/storage/nsDOMStorage.cpp
dom/tests/mochitest/localstorage/test_localStorageBase.html
dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing.html
dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
--- a/dom/interfaces/storage/nsIDOMStorage.idl
+++ b/dom/interfaces/storage/nsIDOMStorage.idl
@@ -59,18 +59,17 @@ interface nsIDOMStorage : nsISupports
    * The number of keys stored.
    */
   readonly attribute unsigned long length;
 
   /**
    * Retrieve the name of the key at a particular index.
    *
    * @param index index of the item to retrieve
-   * @returns the key at index
-   * @throws INDEX_SIZE_ERR if there is no key at that index
+   * @returns the key at index, null if there is no key at that index
    */
   DOMString key(in unsigned long index);
 
   /**
    * Retrieve an item with a given key
    *
    * @param key key to retrieve
    * @returns found data or empty string if the key was not found
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -1126,35 +1126,32 @@ IndexFinder(nsSessionStorageEntry* aEntr
   ++data->mIndex;
 
   return PL_DHASH_NEXT;
 }
 
 nsresult
 DOMStorageImpl::GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey)
 {
-  // XXXjst: This is as retarded as the DOM spec is, takes an unsigned
-  // int, but the spec talks about what to do if a negative value is
-  // passed in.
-
   // XXX: This does a linear search for the key at index, which would
   // suck if there's a large numer of indexes. Do we care? If so,
   // maybe we need to have a lazily populated key array here or
   // something?
 
   if (UseDB()) {
     CacheKeysFromDB();
   }
 
   IndexFinderData data(aCallerSecure, aIndex);
   mItems.EnumerateEntries(IndexFinder, &data);
 
   if (!data.mItem) {
-    // aIndex was larger than the number of accessible keys. Throw.
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+    // aIndex was larger than the number of accessible keys. Return null.
+    aKey.SetIsVoid(true);
+    return NS_OK;
   }
 
   aKey = data.mItem->GetKey();
   return NS_OK;
 }
 
 // The behaviour of this function must be kept in sync with StorageChild::GetValue.
 // See the explanatory comment there for more details.
--- a/dom/tests/mochitest/localstorage/test_localStorageBase.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBase.html
@@ -2,38 +2,23 @@
 <head>
 <title>localStorage basic test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-var INDEX_SIZE_ERR = 1;
-
-function checkException(func, exc)
-{
-  var exceptionThrew = false;
-  try {
-    func();
-  }
-  catch (ex) {
-    exceptionThrew = true;
-    is(ex.code, exc, "Expected "+exc+" exception");
-  }
-  ok(exceptionThrew, "Exception "+exc+" threw");
-}
-
 function startTest()
 {
   // Initially check the localStorage is empty
   is(localStorage.length, 0, "The storage is empty [1]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(localStorage["nonexisting"], null, "Nonexisting item is null (array access)");
   is(localStorage.nonexisting, null, "Nonexisting item is null (property access)");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
 
   is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof localStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof localStorage.nonexisting, "object", "nonexisting is object");
@@ -57,33 +42,33 @@ function startTest()
   is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
   is(typeof localStorage["empty"], "object", "['empty'] is object");
   is(typeof localStorage.empty, "object", "empty is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
 
   // check all access method give the correct result
   // and are of the correct type
   is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
   is(localStorage["key1"], "value1", "['key1'] == value1");
   is(localStorage.key1, "value1", "key1 == value1");
 
   is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
   is(typeof localStorage["key1"], "string", "['key1'] is string");
   is(typeof localStorage.key1, "string", "key1 is string");
 
   // remove the previously added key and check the storage is empty
   localStorage.removeItem("key1");
   is(localStorage.length, 0, "The storage is empty [2]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), null, "\'key1\' removed");
 
   is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
   is(typeof localStorage["key1"], "object", "['key1'] is object");
   is(typeof localStorage.key1, "object", "key1 is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
@@ -102,37 +87,37 @@ function startTest()
      (firstKey == 'key2' && secondKey == 'key1'),
      'key() API works.');
 
   // change the second key
   localStorage.setItem("key2", "value2-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1");
   is(localStorage.getItem("key2"), "value2-2");
 
   // change the first key
   localStorage.setItem("key1", "value1-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
   is(localStorage.getItem("key2"), "value2-2");
 
   // remove the second key
   localStorage.removeItem("key2");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
   
   // JS property test
   localStorage.testA = "valueA";
   is(localStorage.testA, "valueA");
   is(localStorage["testA"], "valueA");
   is(localStorage.getItem("testA"), "valueA");
   
@@ -161,19 +146,19 @@ function startTest()
   is(localStorage["testC"], "valueC2");
   is(localStorage.getItem("testC"), "valueC2");
   
   // Clear the storage
   localStorage.clear();
   is("testB" in localStorage, false, "Keys are not in the JS scope of the storage");
   is("testC" in localStorage, false, "Keys are not in the JS scope of the storage");
   is(localStorage.length, 0, "The storage is empty [3]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(localStorage.getItem("key1"), null, "key1 removed");
   is(localStorage.getItem("key2"), null, "key2 removed");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
   localStorage.removeItem("key1"); // Just check there is no exception
   localStorage.removeItem("key2"); // Just check there is no exception
 
   localStorage.clear();
--- a/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBasePrivateBrowsing.html
@@ -3,31 +3,16 @@
 <title>localStorage basic test, while in sesison only mode</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <script type="text/javascript" src="pbSwitch.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-var INDEX_SIZE_ERR = 1;
-
-function checkException(func, exc)
-{
-  var exceptionThrew = false;
-  try {
-    func();
-  }
-  catch (ex) {
-    exceptionThrew = true;
-    is(ex.code, exc, "Expected "+exc+" exception");
-  }
-  ok(exceptionThrew, "Exception "+exc+" threw");
-}
-
 function startTest()
 {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
   if (get_PBSvc())
     doTest();
   else
     ok(true, "No private browsing service, test could not be performed");
@@ -40,19 +25,19 @@ function doTest()
   localStorage.setItem("persistent", "persistent1");
 
   enterPrivateBrowsing();
 
   is(localStorage.getItem("persistent"), null, "previous values are inaccessible");
 
   // Initially check the localStorage is empty
   is(localStorage.length, 0, "The storage is empty [1]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(localStorage["nonexisting"], null, "Nonexisting item is null (array access)");
   is(localStorage.nonexisting, null, "Nonexisting item is null (property access)");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
 
   is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof localStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof localStorage.nonexisting, "object", "nonexisting is object");
@@ -76,33 +61,33 @@ function doTest()
   is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
   is(typeof localStorage["empty"], "object", "['empty'] is object");
   is(typeof localStorage.empty, "object", "empty is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
 
   // check all access method give the correct result
   // and are of the correct type
   is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
   is(localStorage["key1"], "value1", "['key1'] == value1");
   is(localStorage.key1, "value1", "key1 == value1");
 
   is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
   is(typeof localStorage["key1"], "string", "['key1'] is string");
   is(typeof localStorage.key1, "string", "key1 is string");
 
   // remove the previously added key and check the storage is empty
   localStorage.removeItem("key1");
   is(localStorage.length, 0, "The storage is empty [2]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), null, "\'key1\' removed");
 
   is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
   is(typeof localStorage["key1"], "object", "['key1'] is object");
   is(typeof localStorage.key1, "object", "key1 is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
@@ -121,37 +106,37 @@ function doTest()
      (firstKey == 'key2' && secondKey == 'key1'),
      'key() API works.');
 
   // change the second key
   localStorage.setItem("key2", "value2-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1");
   is(localStorage.getItem("key2"), "value2-2");
 
   // change the first key
   localStorage.setItem("key1", "value1-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
   is(localStorage.getItem("key2"), "value2-2");
 
   // remove the second key
   localStorage.removeItem("key2");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
 
   // JS property test
   localStorage.testA = "valueA";
   is(localStorage.testA, "valueA");
   is(localStorage["testA"], "valueA");
   is(localStorage.getItem("testA"), "valueA");
 
@@ -178,19 +163,19 @@ function doTest()
   localStorage.setItem("testC", "valueC2");
   is(localStorage.testC, "valueC2");
   is(localStorage["testC"], "valueC2");
   is(localStorage.getItem("testC"), "valueC2");
 
   // Clear the storage
   localStorage.clear();
   is(localStorage.length, 0, "The storage is empty [3]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(localStorage.getItem("key1"), null, "key1 removed");
   is(localStorage.getItem("key2"), null, "key2 removed");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
   localStorage.removeItem("key1"); // Just check there is no exception
   localStorage.removeItem("key2"); // Just check there is no exception
 
   localStorage.setItem("must disappear", "private browsing value");
--- a/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageBaseSessionOnly.html
@@ -2,48 +2,33 @@
 <head>
 <title>localStorage basic test, while in sesison only mode</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-var INDEX_SIZE_ERR = 1;
-
-function checkException(func, exc)
-{
-  var exceptionThrew = false;
-  try {
-    func();
-  }
-  catch (ex) {
-    exceptionThrew = true;
-    is(ex.code, exc, "Expected "+exc+" exception");
-  }
-  ok(exceptionThrew, "Exception "+exc+" threw");
-}
-
 function startTest()
 {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
   var io = Components.classes["@mozilla.org/network/io-service;1"]
     .getService(Components.interfaces.nsIIOService);
   var uri = io.newURI(window.location, "", null);
   var cp = Components.classes["@mozilla.org/cookie/permission;1"]
     .getService(Components.interfaces.nsICookiePermission);
   cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
 
 
   // Initially check the localStorage is empty
   is(localStorage.length, 0, "The storage is empty [1]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(localStorage["nonexisting"], null, "Nonexisting item is null (array access)");
   is(localStorage.nonexisting, null, "Nonexisting item is null (property access)");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
 
   is(typeof localStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof localStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof localStorage.nonexisting, "object", "nonexisting is object");
@@ -67,33 +52,33 @@ function startTest()
   is(typeof localStorage.getItem("empty"), "object", "getItem('empty') is object");
   is(typeof localStorage["empty"], "object", "['empty'] is object");
   is(typeof localStorage.empty, "object", "empty is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
 
   // check all access method give the correct result
   // and are of the correct type
   is(localStorage.getItem("key1"), "value1", "getItem('key1') == value1");
   is(localStorage["key1"], "value1", "['key1'] == value1");
   is(localStorage.key1, "value1", "key1 == value1");
 
   is(typeof localStorage.getItem("key1"), "string", "getItem('key1') is string");
   is(typeof localStorage["key1"], "string", "['key1'] is string");
   is(typeof localStorage.key1, "string", "key1 is string");
 
   // remove the previously added key and check the storage is empty
   localStorage.removeItem("key1");
   is(localStorage.length, 0, "The storage is empty [2]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), null, "\'key1\' removed");
 
   is(typeof localStorage.getItem("key1"), "object", "getItem('key1') is object");
   is(typeof localStorage["key1"], "object", "['key1'] is object");
   is(typeof localStorage.key1, "object", "key1 is object");
 
   // add one key, check it is there
   localStorage.setItem("key1", "value1");
@@ -112,37 +97,37 @@ function startTest()
      (firstKey == 'key2' && secondKey == 'key1'),
      'key() API works.');
 
   // change the second key
   localStorage.setItem("key2", "value2-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1");
   is(localStorage.getItem("key2"), "value2-2");
 
   // change the first key
   localStorage.setItem("key1", "value1-2");
   is(localStorage.length, 2, "The storage has two key-value pairs");
   is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(localStorage.key(1), secondKey);
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
   is(localStorage.getItem("key2"), "value2-2");
 
   // remove the second key
   localStorage.removeItem("key2");
   is(localStorage.length, 1, "The storage has one key-value pair");
   is(localStorage.key(0), "key1");
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("key1"), "value1-2");
 
   // JS property test
   localStorage.testA = "valueA";
   is(localStorage.testA, "valueA");
   is(localStorage["testA"], "valueA");
   is(localStorage.getItem("testA"), "valueA");
 
@@ -169,19 +154,19 @@ function startTest()
   localStorage.setItem("testC", "valueC2");
   is(localStorage.testC, "valueC2");
   is(localStorage["testC"], "valueC2");
   is(localStorage.getItem("testC"), "valueC2");
 
   // Clear the storage
   localStorage.clear();
   is(localStorage.length, 0, "The storage is empty [3]");
-  checkException(function() {localStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
-  checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {localStorage.key(1);}, INDEX_SIZE_ERR);
+  is(localStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(localStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(localStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(localStorage.getItem("key1"), null, "key1 removed");
   is(localStorage.getItem("key2"), null, "key2 removed");
   localStorage.removeItem("nonexisting"); // Just check there is no exception
   localStorage.removeItem("key1"); // Just check there is no exception
   localStorage.removeItem("key2"); // Just check there is no exception
 
 
--- a/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
+++ b/dom/tests/mochitest/sessionstorage/test_sessionStorageBase.html
@@ -2,40 +2,25 @@
 <head>
 <title>sessionStorage basic test</title>
 
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 <script type="text/javascript">
 
-var INDEX_SIZE_ERR = 1;
-
-function checkException(func, exc)
-{
-  var exceptionThrew = false;
-  try {
-    func();
-  }
-  catch (ex) {
-    exceptionThrew = true;
-    is(ex.code, exc, "Expected "+exc+" exception");
-  }
-  ok(exceptionThrew, "Exception "+exc+" threw");
-}
-
 function startTest()
 {
   sessionStorage.clear();
   
   // Initially check the sessionStorage is empty
   is(sessionStorage.length, 0, "The storage is empty [1]");
-  checkException(function() {sessionStorage.key(0);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null (getItem())");
   is(sessionStorage["nonexisting"], null, "Nonexisting item is null (array access)");
   is(sessionStorage.nonexisting, null, "Nonexisting item is null (property access)");
   sessionStorage.removeItem("nonexisting"); // Just check there is no exception
 
   is(typeof sessionStorage.getItem("nonexisting"), "object", "getItem('nonexisting') is object");
   is(typeof sessionStorage["nonexisting"], "object", "['nonexisting'] is object");
   is(typeof sessionStorage.nonexisting, "object", "nonexisting is object");
@@ -59,33 +44,33 @@ function startTest()
   is(typeof sessionStorage.getItem("empty"), "object", "getItem('empty') is object");
   is(typeof sessionStorage["empty"], "object", "['empty'] is object");
   is(typeof sessionStorage.empty, "object", "empty is object");
 
   // add one key, check it is there
   sessionStorage.setItem("key1", "value1");
   is(sessionStorage.length, 1, "The storage has one key-value pair");
   is(sessionStorage.key(0), "key1");
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
 
   // check all access method give the correct result
   // and are of the correct type
   is(sessionStorage.getItem("key1"), "value1", "getItem('key1') == value1");
   is(sessionStorage["key1"], "value1", "['key1'] == value1");
   is(sessionStorage.key1, "value1", "key1 == value1");
 
   is(typeof sessionStorage.getItem("key1"), "string", "getItem('key1') is string");
   is(typeof sessionStorage["key1"], "string", "['key1'] is string");
   is(typeof sessionStorage.key1, "string", "key1 is string");
 
   // remove the previously added key and check the storage is empty
   sessionStorage.removeItem("key1");
   is(sessionStorage.length, 0, "The storage is empty [2]");
-  checkException(function() {sessionStorage.key(0);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(0), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("key1"), null, "\'key1\' removed");
 
   is(typeof sessionStorage.getItem("key1"), "object", "getItem('key1') is object");
   is(typeof sessionStorage["key1"], "object", "['key1'] is object");
   is(typeof sessionStorage.key1, "object", "key1 is object");
 
   // add one key, check it is there
   sessionStorage.setItem("key1", "value1");
@@ -104,45 +89,45 @@ function startTest()
      (firstKey == 'key2' && secondKey == 'key1'),
      'key() API works.');
 
   // change the second key
   sessionStorage.setItem("key2", "value2-2");
   is(sessionStorage.length, 2, "The storage has two key-value pairs");
   is(sessionStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(sessionStorage.key(1), secondKey);
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("key1"), "value1");
   is(sessionStorage.getItem("key2"), "value2-2");
 
   // change the first key
   sessionStorage.setItem("key1", "value1-2");
   is(sessionStorage.length, 2, "The storage has two key-value pairs");
   is(sessionStorage.key(0), firstKey); // After key value changes the order must be preserved
   is(sessionStorage.key(1), secondKey);
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(2), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("key1"), "value1-2");
   is(sessionStorage.getItem("key2"), "value2-2");
 
   // remove the second key
   sessionStorage.removeItem("key2");
   is(sessionStorage.length, 1, "The storage has one key-value pair");
   is(sessionStorage.key(0), "key1");
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("key1"), "value1-2");
 
   // Clear the storage
   sessionStorage.clear();
   is(sessionStorage.length, 0, "The storage is empty [3]");
-  checkException(function() {sessionStorage.key(0);}, INDEX_SIZE_ERR); // this is unspecified!
-  checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
-  checkException(function() {sessionStorage.key(1);}, INDEX_SIZE_ERR);
+  is(sessionStorage.key(0), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(-1), null, "key() should return null for out-of-bounds access");
+  is(sessionStorage.key(1), null, "key() should return null for out-of-bounds access");
   is(sessionStorage.getItem("nonexisting"), null, "Nonexisting item is null");
   is(sessionStorage.getItem("key1"), null, "key1 removed");
   is(sessionStorage.getItem("key2"), null, "key2 removed");
   sessionStorage.removeItem("nonexisting"); // Just check there is no exception
   sessionStorage.removeItem("key1"); // Just check there is no exception
   sessionStorage.removeItem("key2"); // Just check there is no exception
 
   SimpleTest.finish();