browser/components/sessionstore/src/SessionStorage.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/components/sessionstore/src/SessionStorage.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,165 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 +* License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.6 +* You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +"use strict";
     1.9 +
    1.10 +this.EXPORTED_SYMBOLS = ["SessionStorage"];
    1.11 +
    1.12 +const Cu = Components.utils;
    1.13 +const Ci = Components.interfaces;
    1.14 +
    1.15 +Cu.import("resource://gre/modules/Services.jsm");
    1.16 +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    1.17 +
    1.18 +XPCOMUtils.defineLazyModuleGetter(this, "console",
    1.19 +  "resource://gre/modules/devtools/Console.jsm");
    1.20 +
    1.21 +// Returns the principal for a given |frame| contained in a given |docShell|.
    1.22 +function getPrincipalForFrame(docShell, frame) {
    1.23 +  let ssm = Services.scriptSecurityManager;
    1.24 +  let uri = frame.document.documentURIObject;
    1.25 +  return ssm.getDocShellCodebasePrincipal(uri, docShell);
    1.26 +}
    1.27 +
    1.28 +this.SessionStorage = Object.freeze({
    1.29 +  /**
    1.30 +   * Updates all sessionStorage "super cookies"
    1.31 +   * @param docShell
    1.32 +   *        That tab's docshell (containing the sessionStorage)
    1.33 +   * @param frameTree
    1.34 +   *        The docShell's FrameTree instance.
    1.35 +   * @return Returns a nested object that will have hosts as keys and per-host
    1.36 +   *         session storage data as values. For example:
    1.37 +   *         {"example.com": {"key": "value", "my_number": 123}}
    1.38 +   */
    1.39 +  collect: function (docShell, frameTree) {
    1.40 +    return SessionStorageInternal.collect(docShell, frameTree);
    1.41 +  },
    1.42 +
    1.43 +  /**
    1.44 +   * Restores all sessionStorage "super cookies".
    1.45 +   * @param aDocShell
    1.46 +   *        A tab's docshell (containing the sessionStorage)
    1.47 +   * @param aStorageData
    1.48 +   *        A nested object with storage data to be restored that has hosts as
    1.49 +   *        keys and per-host session storage data as values. For example:
    1.50 +   *        {"example.com": {"key": "value", "my_number": 123}}
    1.51 +   */
    1.52 +  restore: function (aDocShell, aStorageData) {
    1.53 +    SessionStorageInternal.restore(aDocShell, aStorageData);
    1.54 +  }
    1.55 +});
    1.56 +
    1.57 +let SessionStorageInternal = {
    1.58 +  /**
    1.59 +   * Reads all session storage data from the given docShell.
    1.60 +   * @param docShell
    1.61 +   *        A tab's docshell (containing the sessionStorage)
    1.62 +   * @param frameTree
    1.63 +   *        The docShell's FrameTree instance.
    1.64 +   * @return Returns a nested object that will have hosts as keys and per-host
    1.65 +   *         session storage data as values. For example:
    1.66 +   *         {"example.com": {"key": "value", "my_number": 123}}
    1.67 +   */
    1.68 +  collect: function (docShell, frameTree) {
    1.69 +    let data = {};
    1.70 +    let visitedOrigins = new Set();
    1.71 +
    1.72 +    frameTree.forEach(frame => {
    1.73 +      let principal = getPrincipalForFrame(docShell, frame);
    1.74 +      if (!principal) {
    1.75 +        return;
    1.76 +      }
    1.77 +
    1.78 +      // Get the root domain of the current history entry
    1.79 +      // and use that as a key for the per-host storage data.
    1.80 +      let origin = principal.jarPrefix + principal.origin;
    1.81 +      if (visitedOrigins.has(origin)) {
    1.82 +        // Don't read a host twice.
    1.83 +        return;
    1.84 +      }
    1.85 +
    1.86 +      // Mark the current origin as visited.
    1.87 +      visitedOrigins.add(origin);
    1.88 +
    1.89 +      let originData = this._readEntry(principal, docShell);
    1.90 +      if (Object.keys(originData).length) {
    1.91 +        data[origin] = originData;
    1.92 +      }
    1.93 +    });
    1.94 +
    1.95 +    return Object.keys(data).length ? data : null;
    1.96 +  },
    1.97 +
    1.98 +  /**
    1.99 +   * Writes session storage data to the given tab.
   1.100 +   * @param aDocShell
   1.101 +   *        A tab's docshell (containing the sessionStorage)
   1.102 +   * @param aStorageData
   1.103 +   *        A nested object with storage data to be restored that has hosts as
   1.104 +   *        keys and per-host session storage data as values. For example:
   1.105 +   *        {"example.com": {"key": "value", "my_number": 123}}
   1.106 +   */
   1.107 +  restore: function (aDocShell, aStorageData) {
   1.108 +    for (let host of Object.keys(aStorageData)) {
   1.109 +      let data = aStorageData[host];
   1.110 +      let uri = Services.io.newURI(host, null, null);
   1.111 +      let principal = Services.scriptSecurityManager.getDocShellCodebasePrincipal(uri, aDocShell);
   1.112 +      let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
   1.113 +
   1.114 +      // There is no need to pass documentURI, it's only used to fill documentURI property of
   1.115 +      // domstorage event, which in this case has no consumer. Prevention of events in case
   1.116 +      // of missing documentURI will be solved in a followup bug to bug 600307.
   1.117 +      // TODO: We should call createStorageForFirstParty() here.  See comment
   1.118 +      //       inside _readEntry() for details.
   1.119 +      let storage = storageManager.createStorage(principal, "", aDocShell.usePrivateBrowsing);
   1.120 +
   1.121 +      for (let key of Object.keys(data)) {
   1.122 +        try {
   1.123 +          storage.setItem(key, data[key]);
   1.124 +        } catch (e) {
   1.125 +          // throws e.g. for URIs that can't have sessionStorage
   1.126 +          console.error(e);
   1.127 +        }
   1.128 +      }
   1.129 +    }
   1.130 +  },
   1.131 +
   1.132 +  /**
   1.133 +   * Reads an entry in the session storage data contained in a tab's history.
   1.134 +   * @param aURI
   1.135 +   *        That history entry uri
   1.136 +   * @param aDocShell
   1.137 +   *        A tab's docshell (containing the sessionStorage)
   1.138 +   */
   1.139 +  _readEntry: function (aPrincipal, aDocShell) {
   1.140 +    let hostData = {};
   1.141 +    let storage;
   1.142 +
   1.143 +    try {
   1.144 +      let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
   1.145 +      // TODO: We should call getStorageForFirstParty() here, but we need an
   1.146 +      //       nsIDocument to call thirdPartyUtil.getFirstPartyURI(), and
   1.147 +      //       unfortunately nsIDocument is not exposed to JavaScript.
   1.148 +      //       However, this code is not called in TBB because the
   1.149 +      //       browser.sessionstore.privacy_level pref. is set to 2.
   1.150 +      storage = storageManager.getStorage(aPrincipal);
   1.151 +    } catch (e) {
   1.152 +      // sessionStorage might throw if it's turned off, see bug 458954
   1.153 +    }
   1.154 +
   1.155 +    if (storage && storage.length) {
   1.156 +       for (let i = 0; i < storage.length; i++) {
   1.157 +        try {
   1.158 +          let key = storage.key(i);
   1.159 +          hostData[key] = storage.getItem(key);
   1.160 +        } catch (e) {
   1.161 +          // This currently throws for secured items (cf. bug 442048).
   1.162 +        }
   1.163 +      }
   1.164 +    }
   1.165 +
   1.166 +    return hostData;
   1.167 +  }
   1.168 +};

mercurial