Bug 1313003 - Add Site Data section into Network of Advanced of about:preferences, r=jaws
MozReview-Commit-ID: KVUs8FTftxY
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/SiteDataManager.jsm
@@ -0,0 +1,154 @@
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+this.EXPORTED_SYMBOLS = [
+ "SiteDataManager"
+];
+
+this.SiteDataManager = {
+
+ _qms: Services.qms,
+
+ _diskCache: Services.cache2.diskCacheStorage(Services.loadContextInfo.default, false),
+
+ _appCache: Cc["@mozilla.org/network/application-cache-service;1"].getService(Ci.nsIApplicationCacheService),
+
+ // A Map of sites using the persistent-storage API (have requested persistent-storage permission)
+ // Key is site's origin.
+ // Value is one object holding:
+ // - perm: persistent-storage permision; instance of nsIPermission
+ // - status: the permission granted/rejected status
+ // - quotaUsage: the usage of indexedDB and localStorage.
+ // - appCacheList: an array of app cache; instances of nsIApplicationCache
+ // - diskCacheList: an array. Each element is object holding metadata of http cache:
+ // - dataSize: that http cache size
+ // - idEnhance: the id extension of that http cache
+ _sites: new Map(),
+
+ _updateQuotaPromise: null,
+
+ _updateDiskCachePromise: null,
+
+ _quotaUsageRequests: null,
+
+ updateSites() {
+ // Clear old data and requests first
+ this._sites.clear();
+ this._cancelQuotaUpdate();
+
+ // Collect sites granted/rejected with the persistent-storage permission
+ let perm = null;
+ let status = null;
+ let e = Services.perms.enumerator;
+ while (e.hasMoreElements()) {
+ perm = e.getNext();
+ status = Services.perms.testExactPermissionFromPrincipal(perm.principal, "persistent-storage");
+ if (status === Ci.nsIPermissionManager.ALLOW_ACTION ||
+ status === Ci.nsIPermissionManager.DENY_ACTION) {
+ this._sites.set(perm.principal.origin, {
+ perm: perm,
+ status: status,
+ quotaUsage: 0,
+ appCacheList: [],
+ diskCacheList: []
+ });
+ }
+ }
+
+ this._updateQuota();
+ this._updateAppCache();
+ this._updateDiskCache();
+ },
+
+ _updateQuota() {
+ this._quotaUsageRequests = [];
+ let promises = [];
+ for (let [key, site] of this._sites) { // eslint-disable-line no-unused-vars
+ promises.push(new Promise(resolve => {
+ let callback = {
+ onUsageResult: function(request) {
+ site.quotaUsage = request.usage;
+ resolve();
+ }
+ };
+ // XXX: The work of integrating localStorage into Quota Manager is in progress.
+ // After the bug 742822 and 1286798 landed, localStorage usage will be included.
+ // So currently only get indexedDB usage.
+ this._quotaUsageRequests.push(
+ this._qms.getUsageForPrincipal(site.perm.principal, callback));
+ }));
+ }
+ this._updateQuotaPromise = Promise.all(promises);
+ },
+
+ _cancelQuotaUpdate() {
+ if (this._quotaUsageRequests) {
+ for (let request of this._quotaUsageRequests) {
+ request.cancel();
+ }
+ this._quotaUsageRequests = null;
+ }
+ },
+
+ _updateAppCache() {
+ let groups = this._appCache.getGroups();
+ for (let [key, site] of this._sites) { // eslint-disable-line no-unused-vars
+ for (let group of groups) {
+ let uri = Services.io.newURI(group, null, null);
+ if (site.perm.matchesURI(uri, true)) {
+ let cache = this._appCache.getActiveCache(group);
+ site.appCacheList.push(cache);
+ }
+ }
+ }
+ },
+
+ _updateDiskCache() {
+ this._updateDiskCachePromise = new Promise(resolve => {
+ if (this._sites.size) {
+ let sites = this._sites;
+ let visitor = {
+ onCacheEntryInfo: function(uri, idEnhance, dataSize) {
+ for (let [key, site] of sites) { // eslint-disable-line no-unused-vars
+ if (site.perm.matchesURI(uri, true)) {
+ site.diskCacheList.push({
+ dataSize,
+ idEnhance
+ });
+ break;
+ }
+ }
+ },
+ onCacheEntryVisitCompleted: function() {
+ resolve();
+ }
+ };
+ this._diskCache.asyncVisitStorage(visitor, true);
+ } else {
+ resolve();
+ }
+ });
+ },
+
+ getTotalUsage() {
+ return Promise.all([this._updateQuotaPromise, this._updateDiskCachePromise])
+ .then(() => {
+ let usage = 0;
+ for (let [key, site] of this._sites) { // eslint-disable-line no-unused-vars
+ let cache = null;
+ for (cache of site.appCacheList) {
+ usage += cache.usage;
+ }
+ for (cache of site.diskCacheList) {
+ usage += cache.dataSize;
+ }
+ usage += site.quotaUsage;
+ }
+ return usage;
+ });
+ },
+};
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -2,16 +2,19 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// Load DownloadUtils module for convertByteUnits
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "SiteDataManager",
+ "resource:///modules/SiteDataManager.jsm");
+
const PREF_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
var gAdvancedPane = {
_inited: false,
/**
* Brings the appropriate tab to the front and initializes various bits of UI.
*/
@@ -47,16 +50,21 @@ var gAdvancedPane = {
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
this.initSubmitHealthReport();
}
this.updateOnScreenKeyboardVisibility();
this.updateCacheSizeInputField();
this.updateActualCacheSize();
this.updateActualAppCacheSize();
+ if (Services.prefs.getBoolPref("browser.storageManager.enabled")) {
+ SiteDataManager.updateSites();
+ this.updateTotalSiteDataSize();
+ }
+
setEventListener("layers.acceleration.disabled", "change",
gAdvancedPane.updateHardwareAcceleration);
setEventListener("advancedPrefs", "select",
gAdvancedPane.tabSelectionChanged);
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
setEventListener("submitHealthReportBox", "command",
gAdvancedPane.updateSubmitHealthReport);
}
@@ -324,16 +332,28 @@ var gAdvancedPane = {
/**
* Displays a dialog in which proxy settings may be changed.
*/
showConnections: function()
{
gSubDialog.open("chrome://browser/content/preferences/connection.xul");
},
+ updateTotalSiteDataSize: function() {
+ SiteDataManager.getTotalUsage()
+ .then(usage => {
+ let size = DownloadUtils.convertByteUnits(usage);
+ let prefStrBundle = document.getElementById("bundlePreferences");
+ let totalSiteDataSizeLabel = document.getElementById("totalSiteDataSize");
+ totalSiteDataSizeLabel.textContent = prefStrBundle.getFormattedString("totalSiteDataSize", size);
+ let siteDataGroup = document.getElementById("siteDataGroup");
+ siteDataGroup.hidden = false;
+ });
+ },
+
// Retrieves the amount of space currently used by disk cache
updateActualCacheSize: function()
{
var actualSizeLabel = document.getElementById("actualDiskCacheSize");
var prefStrBundle = document.getElementById("bundlePreferences");
// Needs to root the observer since cache service keeps only a weak reference.
this.observer = {
--- a/browser/components/preferences/in-content/advanced.xul
+++ b/browser/components/preferences/in-content/advanced.xul
@@ -323,16 +323,25 @@
<vbox pack="end">
<button id="offlineAppsListRemove"
disabled="true"
label="&offlineAppsListRemove.label;"
accesskey="&offlineAppsListRemove.accesskey;"/>
</vbox>
</hbox>
</groupbox>
+
+ <!-- Site Data -->
+ <groupbox id="siteDataGroup" hidden="true">
+ <caption><label>&siteData.label;</label></caption>
+
+ <hbox align="center">
+ <label id="totalSiteDataSize" flex="1"></label>
+ </hbox>
+ </groupbox>
</tabpanel>
<!-- Update -->
<tabpanel id="updatePanel" orient="vertical">
#ifdef MOZ_UPDATER
<groupbox id="updateApp" align="start">
<caption><label>&updateApp.label;</label></caption>
<radiogroup id="updateRadioGroup" align="start">
--- a/browser/components/preferences/moz.build
+++ b/browser/components/preferences/moz.build
@@ -13,10 +13,14 @@ BROWSER_CHROME_MANIFESTS += [
for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
DEFINES[var] = CONFIG[var]
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
DEFINES['HAVE_SHELL_SERVICE'] = 1
JAR_MANIFESTS += ['jar.mn']
+EXTRA_JS_MODULES += [
+ 'SiteDataManager.jsm',
+]
+
with Files('**'):
BUG_COMPONENT = ('Firefox', 'Preferences')
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
@@ -52,16 +52,19 @@
<!ENTITY connectionDesc.label "Configure how &brandShortName; connects to the Internet">
<!ENTITY connectionSettings.label "Settings…">
<!ENTITY connectionSettings.accesskey "e">
<!ENTITY httpCache.label "Cached Web Content">
<!ENTITY offlineStorage2.label "Offline Web Content and User Data">
+<!-- Site Data section manages sites using Storage API and is under Network -->
+<!ENTITY siteData.label "Site Data">
+
<!-- LOCALIZATION NOTE:
The entities limitCacheSizeBefore.label and limitCacheSizeAfter.label appear on a single
line in preferences as follows:
&limitCacheSizeBefore.label [textbox for cache size in MB] &limitCacheSizeAfter.label;
-->
<!ENTITY limitCacheSizeBefore.label "Limit cache to">
<!ENTITY limitCacheSizeBefore.accesskey "L">
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -159,16 +159,23 @@ actualDiskCacheSizeCalculated=Calculating web content cache size…
####Preferences::Advanced::Network
#LOCALIZATION NOTE: The next string is for the disk usage of the application cache.
# e.g., "Your application cache is currently using 200 MB"
# %1$S = size
# %2$S = unit (MB, KB, etc.)
actualAppCacheSize=Your application cache is currently using %1$S %2$S of disk space
+####Preferences::Advanced::Network
+#LOCALIZATION NOTE: The next string is for the total usage of site data.
+# e.g., "The total usage is currently using 200 MB"
+# %1$S = size
+# %2$S = unit (MB, KB, etc.)
+totalSiteDataSize=Your stored site data is currently using %1$S %2$S of disk space
+
syncUnlink.title=Do you want to unlink your device?
syncUnlink.label=This device will no longer be associated with your Sync account. All of your personal data, both on this device and in your Sync account, will remain intact.
syncUnlinkConfirm.label=Unlink
# LOCALIZATION NOTE (featureEnableRequiresRestart, featureDisableRequiresRestart, restartTitle): %S = brandShortName
featureEnableRequiresRestart=%S must restart to enable this feature.
featureDisableRequiresRestart=%S must restart to disable this feature.
shouldRestartTitle=Restart %S
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5527,8 +5527,13 @@ pref ("security.mixed_content.hsts_primi
pref ("security.mixed_content.hsts_priming_request_timeout", 3000);
// Disable Storage api in release builds.
#ifdef NIGHTLY_BUILD
pref("dom.storageManager.enabled", true);
#else
pref("dom.storageManager.enabled", false);
#endif
+
+// Enable the Storage management in about:preferences and persistent-storage permission request
+// To enable the DOM implementation, turn on "dom.storageManager.enabled"
+pref("browser.storageManager.enabled", false);
+