Bug 1348253 - about:url-classifier: Providers information and update button. r?francois
The about:url-classifier supports following functions:
1. Provider section
- Show update status for each provider, update status include
last update time, next update time and last update status
- Update button to manually trigger an update for the provider.
2. Debug section
- Set MOZ_LOG Modules
- Set MOZ_LOG_FILE
MozReview-Commit-ID: AHiveKEHSNC
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -131,16 +131,20 @@ static const RedirEntry kRedirMap[] = {
"support", "chrome://global/content/aboutSupport.xhtml",
nsIAboutModule::ALLOW_SCRIPT
},
{
"telemetry", "chrome://global/content/aboutTelemetry.xhtml",
nsIAboutModule::ALLOW_SCRIPT
},
{
+ "url-classifier", "chrome://global/content/aboutUrlClassifier.xhtml",
+ nsIAboutModule::ALLOW_SCRIPT
+ },
+ {
"webrtc", "chrome://global/content/aboutwebrtc/aboutWebrtc.html",
nsIAboutModule::ALLOW_SCRIPT
},
{
"printpreview", "about:blank",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::HIDE_FROM_ABOUTABOUT |
nsIAboutModule::URI_CAN_LOAD_IN_CHILD
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -193,16 +193,17 @@ const mozilla::Module::ContractIDEntry k
#ifndef ANDROID
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "profiles", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
#endif
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "srcdoc", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "support", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "telemetry", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "webrtc", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "printpreview", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
+ { NS_ABOUT_MODULE_CONTRACTID_PREFIX "url-classifier", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
{ NS_URI_LOADER_CONTRACTID, &kNS_URI_LOADER_CID },
{ NS_DOCUMENTLOADER_SERVICE_CONTRACTID, &kNS_DOCUMENTLOADER_SERVICE_CID },
{ NS_HANDLERSERVICE_CONTRACTID, &kNS_CONTENTHANDLERSERVICE_CID, mozilla::Module::CONTENT_PROCESS_ONLY },
{ NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &kNS_EXTERNALHELPERAPPSERVICE_CID },
{ NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &kNS_EXTERNALHELPERAPPSERVICE_CID },
{ NS_MIMESERVICE_CONTRACTID, &kNS_EXTERNALHELPERAPPSERVICE_CID },
{ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default", &kNS_EXTERNALPROTOCOLHANDLER_CID },
{ NS_PREFETCHSERVICE_CONTRACTID, &kNS_PREFETCHSERVICE_CID },
--- a/toolkit/components/url-classifier/content/listmanager.js
+++ b/toolkit/components/url-classifier/content/listmanager.js
@@ -127,16 +127,23 @@ PROT_ListManager.prototype.registerTable
PROT_ListManager.prototype.getGethashUrl = function(tableName) {
if (this.tablesData[tableName] && this.tablesData[tableName].gethashUrl) {
return this.tablesData[tableName].gethashUrl;
}
return "";
}
+PROT_ListManager.prototype.getUpdateUrl = function(tableName) {
+ if (this.tablesData[tableName] && this.tablesData[tableName].updateUrl) {
+ return this.tablesData[tableName].updateUrl;
+ }
+ return "";
+}
+
/**
* Enable updates for some tables
* @param tables - an array of table names that need updating
*/
PROT_ListManager.prototype.enableUpdate = function(tableName) {
var table = this.tablesData[tableName];
if (table) {
log("Enabling table updates for " + tableName);
@@ -478,16 +485,22 @@ PROT_ListManager.prototype.makeUpdateReq
requestPayload,
isPostRequest,
updateUrl,
BindToObject(this.updateSuccess_, this, tableList, updateUrl),
BindToObject(this.updateError_, this, tableList, updateUrl),
BindToObject(this.downloadError_, this, tableList, updateUrl))) {
// Our alarm gets reset in one of the 3 callbacks.
log("pending update, queued request until later");
+ } else {
+ let table = Object.keys(this.tablesData).find(key => {
+ return this.tablesData[key].updateUrl === updateUrl;
+ });
+ let provider = this.tablesData[table].provider;
+ Services.obs.notifyObservers(null, "safebrowsing-update-begin", provider);
}
}
/**
* Callback function if the update request succeeded.
* @param waitForUpdate String The number of seconds that the client should
* wait before requesting again.
*/
@@ -545,29 +558,34 @@ PROT_ListManager.prototype.updateSuccess
log("Setting last update of " + provider + " to " + now);
this.prefs_.setPref(lastUpdatePref, now.toString());
let nextUpdatePref = "browser.safebrowsing.provider." + provider + ".nextupdatetime";
let targetTime = now + delay;
log("Setting next update of " + provider + " to " + targetTime
+ " (" + delay + "ms from now)");
this.prefs_.setPref(nextUpdatePref, targetTime.toString());
+
+ Services.obs.notifyObservers(null, "safebrowsing-update-finished", "success");
}
/**
* Callback function if the update request succeeded.
* @param result String The error code of the failure
*/
PROT_ListManager.prototype.updateError_ = function(table, updateUrl, result) {
log("update error for " + table + " from " + updateUrl + ": " + result + "\n");
// There was some trouble applying the updates. Don't try again for at least
// updateInterval milliseconds.
this.updateCheckers_[updateUrl] =
new G_Alarm(BindToObject(this.checkForUpdates, this, updateUrl),
this.updateInterval, false);
+
+ Services.obs.notifyObservers(null, "safebrowsing-update-finished",
+ "update error(" + result + ")");
}
/**
* Callback function when the download failed
* @param status String http status or an empty string if connection refused.
*/
PROT_ListManager.prototype.downloadError_ = function(table, updateUrl, status) {
log("download error for " + table + ": " + status + "\n");
@@ -584,16 +602,18 @@ PROT_ListManager.prototype.downloadError
delay = this.requestBackoffs_[updateUrl].nextRequestDelay();
} else {
log("Got non error status for error callback?!");
}
this.updateCheckers_[updateUrl] =
new G_Alarm(BindToObject(this.checkForUpdates, this, updateUrl),
delay, false);
+ Services.obs.notifyObservers(null, "safebrowsing-update-finished",
+ "download error(" + status + ")");
}
PROT_ListManager.prototype.QueryInterface = function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIUrlListManager) ||
iid.equals(Ci.nsITimerCallback))
return this;
--- a/toolkit/components/url-classifier/nsIUrlListManager.idl
+++ b/toolkit/components/url-classifier/nsIUrlListManager.idl
@@ -22,16 +22,21 @@ interface nsIUrlListManagerCallback : ns
interface nsIUrlListManager : nsISupports
{
/**
* Get the gethash url for this table
*/
ACString getGethashUrl(in ACString tableName);
/**
+ * Get the update url for this table
+ */
+ ACString getUpdateUrl(in ACString tableName);
+
+ /**
* Add a table to the list of tables we are managing. The name is a
* string of the format provider_name-semantic_type-table_type. For
* @param tableName A string of the format
* provider_name-semantic_type-table_type. For example,
* goog-white-enchash or goog-black-url.
* @param providerName The name of the entity providing the list.
* @param updateUrl The URL from which to fetch updates.
* @param gethashUrl The URL from which to fetch hash completions.
@@ -59,9 +64,15 @@ interface nsIUrlListManager : nsISupport
/**
* Lookup a key. Should not raise exceptions. Calls the callback
* function with a comma-separated list of tables to which the key
* belongs.
*/
void safeLookup(in nsIPrincipal key,
in nsIUrlListManagerCallback cb);
+
+ /**
+ * This is currently used by about:url-classifier to force an update
+ * for the update url. Update may still fail because of backoff algorithm.
+ */
+ boolean checkForUpdates(in ACString updateUrl);
};
new file mode 100644
--- /dev/null
+++ b/toolkit/content/aboutUrlClassifier.css
@@ -0,0 +1,72 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+html {
+ --aboutUrlClassifier-table-background: #ebebeb;
+ background-color: var(--in-content-page-background);
+}
+
+body {
+ margin: 40px 48px;
+}
+
+.major-section {
+ margin-top: 2em;
+ margin-bottom: 1em;
+ font-size: large;
+ text-align: start;
+ font-weight: bold;
+}
+
+table {
+ background-color: var(--aboutUrlClassifier-table-background);
+ color: var(--in-content-text-color);
+ font: message-box;
+ text-align: start;
+ width: 100%;
+ border: 1px solid var(--in-content-border-color);
+ border-spacing: 0px;
+}
+
+th, td {
+ border: 1px solid var(--in-content-border-color);
+ padding: 4px;
+}
+
+thead th {
+ text-align: center;
+}
+
+th {
+ text-align: start;
+ background-color: var(--in-content-table-header-background);
+ color: var(--in-content-selected-text);
+}
+
+th.column {
+ white-space: nowrap;
+ width: 0px;
+}
+
+td {
+ text-align: start;
+ border-color: var(--in-content-table-border-dark-color);
+}
+
+#provider-table > tbody > tr > td:last-child {
+ text-align: center;
+}
+
+#debug-table {
+ margin-top: 20px;
+}
+
+.options > .toggle-container-with-text {
+ display: inline-flex;
+}
+
+button {
+ margin-inline-start: 0;
+ margin-inline-end: 8px;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/content/aboutUrlClassifier.js
@@ -0,0 +1,335 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+const bundle = Services.strings.createBundle(
+ "chrome://global/locale/aboutUrlClassifier.properties");
+
+const UPDATE_BEGIN = "safebrowsing-update-begin";
+const UPDATE_FINISH = "safebrowsing-update-finished";
+const JSLOG_PREF = "browser.safebrowsing.debug";
+
+const STR_NA = bundle.GetStringFromName("NotAvailable");
+
+function unLoad() {
+ window.removeEventListener("unload", unLoad);
+
+ Provider.uninit();
+ Debug.uninit();
+}
+
+function onLoad() {
+ window.removeEventListener("load", onLoad);
+ window.addEventListener("unload", unLoad);
+
+ Provider.init();
+ Debug.init();
+}
+
+/*
+ * Provider
+ */
+var Provider = {
+ providers: null,
+
+ updatingProvider: "",
+
+ init() {
+ this.providers = new Set();
+ let branch = Services.prefs.getBranch("browser.safebrowsing.provider.");
+ let children = branch.getChildList("", {});
+ for (let child of children) {
+ this.providers.add(child.split(".")[0]);
+ }
+
+ this.register();
+ this.render();
+ this.refresh();
+ },
+
+ uninit() {
+ Services.obs.removeObserver(this.onBeginUpdate, UPDATE_BEGIN);
+ Services.obs.removeObserver(this.onFinishUpdate, UPDATE_FINISH);
+ },
+
+ onBeginUpdate(aSubject, aTopic, aData) {
+ this.updatingProvider = aData;
+ let p = this.updatingProvider;
+
+ // Disable update button for the provider while we are doing update.
+ document.getElementById("update-" + p).disabled = true;
+
+ let elem = document.getElementById(p + "-col-lastupdateresult");
+ elem.childNodes[0].nodeValue = bundle.GetStringFromName("Updating");
+ },
+
+ onFinishUpdate(aSubject, aTopic, aData) {
+ let p = this.updatingProvider;
+ this.updatingProvider = "";
+
+ // It is possible that we get update-finished event only because
+ // about::url-classifier is opened after update-begin event is fired.
+ if (p === "") {
+ this.refresh();
+ return;
+ }
+
+ this.refresh([p]);
+
+ document.getElementById("update-" + p).disabled = false;
+
+ let elem = document.getElementById(p + "-col-lastupdateresult");
+ elem.childNodes[0].nodeValue = aData;
+ },
+
+ register() {
+ // Handle begin update
+ this.onBeginUpdate = this.onBeginUpdate.bind(this);
+ Services.obs.addObserver(this.onBeginUpdate, UPDATE_BEGIN);
+
+ // Handle finish update
+ this.onFinishUpdate = this.onFinishUpdate.bind(this);
+ Services.obs.addObserver(this.onFinishUpdate, UPDATE_FINISH);
+ },
+
+ // This should only be called once because we assume number of providers
+ // won't change.
+ render() {
+ let tbody = document.getElementById("provider-table-body");
+
+ for (let provider of this.providers) {
+ let tr = document.createElement("tr");
+ let cols = document.getElementById("provider-head-row").childNodes;
+ for (let column of cols) {
+ if (!column.id) {
+ continue;
+ }
+ let td = document.createElement("td");
+ td.id = provider + "-" + column.id;
+
+ if (column.id === "col-update") {
+ let btn = document.createElement("button");
+ btn.id = "update-" + provider;
+ btn.addEventListener("click", () => { this.update(provider); });
+
+ let str = bundle.GetStringFromName("TriggerUpdate")
+ btn.appendChild(document.createTextNode(str));
+ td.appendChild(btn);
+ } else {
+ let str = column.id === "col-lastupdateresult" ? STR_NA : "";
+ td.appendChild(document.createTextNode(str));
+ }
+ tr.appendChild(td);
+ }
+ tbody.appendChild(tr);
+ }
+ },
+
+ refresh(listProviders = this.providers) {
+ for (let provider of listProviders) {
+ let values = {};
+ values["col-provider"] = provider;
+
+ let pref = "browser.safebrowsing.provider." + provider + ".lastupdatetime";
+ let lut = Services.prefs.getCharPref(pref, "");
+ values["col-lastupdatetime"] = lut ? new Date(lut * 1) : STR_NA;
+
+ pref = "browser.safebrowsing.provider." + provider + ".nextupdatetime";
+ let nut = Services.prefs.getCharPref(pref, "");
+ values["col-nextupdatetime"] = nut ? new Date(nut * 1) : STR_NA;
+
+ for (let key of Object.keys(values)) {
+ let elem = document.getElementById(provider + "-" + key);
+ elem.childNodes[0].nodeValue = values[key];
+ }
+ }
+ },
+
+ // Call update for the provider.
+ update(provider) {
+ let listmanager = Cc["@mozilla.org/url-classifier/listmanager;1"]
+ .getService(Ci.nsIUrlListManager);
+
+ let pref = "browser.safebrowsing.provider." + provider + ".lists";
+ let table = Services.prefs.getCharPref(pref, "").split(",")[0];
+
+ let updateUrl = listmanager.getUpdateUrl(table);
+ if (!listmanager.checkForUpdates(updateUrl)) {
+ // This may because of back-off algorithm.
+ let elem = document.getElementById(provider + "-col-lastupdateresult");
+ elem.childNodes[0].nodeValue = bundle.GetStringFromName("CannotUpdate");
+ }
+ },
+
+};
+
+/*
+ * Debug
+ */
+var Debug = {
+ // url-classifier NSPR Log modules.
+ modules: ["UrlClassifierDbService",
+ "nsChannelClassifier",
+ "UrlClassifierProtocolParser",
+ "UrlClassifierStreamUpdater",
+ "UrlClassifierPrefixSet",
+ "ApplicationReputation"],
+
+ init() {
+ this.register();
+ this.render();
+ this.refresh();
+ },
+
+ uninit() {
+ Services.prefs.removeObserver(JSLOG_PREF, this.refreshJSDebug);
+ },
+
+ register() {
+ this.refreshJSDebug = this.refreshJSDebug.bind(this);
+ Services.prefs.addObserver(JSLOG_PREF, this.refreshJSDebug);
+ },
+
+ render() {
+ // This function update the log module text field if we click
+ // safebrowsing log module check box.
+ function logModuleUpdate(module) {
+ let txt = document.getElementById("log-modules");
+ let chk = document.getElementById("chk-" + module);
+
+ let dst = chk.checked ? "," + module + ":5" : "";
+ let re = new RegExp(",?" + module + ":[0-9]");
+
+ let str = txt.value.replace(re, dst);
+ if (chk.checked) {
+ str = txt.value === str ? str + dst : str;
+ }
+ txt.value = str.replace(/^,/, "");
+ }
+
+ let setLog = document.getElementById("set-log-modules");
+ setLog.addEventListener("click", this.nsprlog);
+
+ let setLogFile = document.getElementById("set-log-file");
+ setLogFile.addEventListener("click", this.logfile);
+
+ let setJSLog = document.getElementById("js-log");
+ setJSLog.addEventListener("click", this.jslog);
+
+ let modules = document.getElementById("log-modules");
+ let sbModules = document.getElementById("sb-log-modules");
+ for (let module of this.modules) {
+ let container = document.createElement("div");
+ container.className = "toggle-container-with-text";
+ sbModules.appendChild(container);
+
+ let chk = document.createElement("input");
+ chk.id = "chk-" + module;
+ chk.type = "checkbox";
+ chk.checked = true;
+ chk.addEventListener("click", () => { logModuleUpdate(module) });
+ container.appendChild(chk, modules);
+
+ let label = document.createElement("label");
+ label.for = chk.id;
+ label.appendChild(document.createTextNode(module));
+ container.appendChild(label, modules);
+ }
+
+ this.modules.map(logModuleUpdate);
+
+ let file = Services.dirsvc.get("TmpD", Ci.nsIFile);
+ file.append("safebrowsing.log");
+
+ let logFile = document.getElementById("log-file");
+ logFile.value = file.path;
+
+ let curLog = document.getElementById("cur-log-modules");
+ curLog.childNodes[0].nodeValue = "";
+
+ let curLogFile = document.getElementById("cur-log-file");
+ curLogFile.childNodes[0].nodeValue = "";
+ },
+
+ refresh() {
+ this.refreshJSDebug();
+
+ // Disable configure log modules if log modules are already set
+ // by environment variable.
+ let env = Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment);
+
+ let logModules = env.get("MOZ_LOG") ||
+ env.get("MOZ_LOG_MODULES") ||
+ env.get("NSPR_LOG_MODULES");
+
+ if (logModules.length > 0) {
+ document.getElementById("set-log-modules").disabled = true;
+ for (let module of this.modules) {
+ document.getElementById("chk-" + module).disabled = true;
+ }
+
+ let curLogModules = document.getElementById("cur-log-modules");
+ curLogModules.childNodes[0].nodeValue = logModules;
+ }
+
+ // Disable set log file if log file is already set
+ // by environment variable.
+ let logFile = env.get("MOZ_LOG_FILE") || env.get("NSPR_LOG_FILE");
+ if (logFile.length > 0) {
+ document.getElementById("set-log-file").disabled = true;
+ document.getElementById("log-file").value = logFile;
+ }
+ },
+
+ refreshJSDebug() {
+ let enabled = Services.prefs.getBoolPref(JSLOG_PREF, false);
+
+ let jsChk = document.getElementById("js-log");
+ jsChk.checked = enabled;
+
+ let curJSLog = document.getElementById("cur-js-log");
+ curJSLog.childNodes[0].nodeValue = enabled ?
+ bundle.GetStringFromName("Enabled") :
+ bundle.GetStringFromName("Disabled");
+ },
+
+ jslog() {
+ let enabled = Services.prefs.getBoolPref(JSLOG_PREF, false);
+ Services.prefs.setBoolPref(JSLOG_PREF, !enabled);
+ },
+
+ nsprlog() {
+ // Turn off debugging for all the modules.
+ let children = Services.prefs.getBranch("logging.").getChildList("", {});
+ for (let pref of children) {
+ if (!pref.startsWith("config.")) {
+ Services.prefs.clearUserPref(`logging.${pref}`);
+ }
+ }
+
+ let value = document.getElementById("log-modules").value;
+ let logModules = value.split(",");
+ for (let module of logModules) {
+ let [key, value] = module.split(":");
+ Services.prefs.setIntPref(`logging.${key}`, parseInt(value, 10));
+ }
+
+ let curLogModules = document.getElementById("cur-log-modules");
+ curLogModules.childNodes[0].nodeValue = value;
+ },
+
+ logfile() {
+ let logFile = document.getElementById("log-file").value.trim();
+ Services.prefs.setCharPref("logging.config.LOG_FILE", logFile);
+
+ let curLogFile = document.getElementById("cur-log-file");
+ curLogFile.childNodes[0].nodeValue = logFile;
+ }
+};
new file mode 100644
--- /dev/null
+++ b/toolkit/content/aboutUrlClassifier.xhtml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - 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/. -->
+
+<!DOCTYPE html [
+<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
+<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD;
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD;
+<!ENTITY % urlClassifierDTD SYSTEM "chrome://global/locale/aboutUrlClassifier.dtd"> %urlClassifierDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <link rel="stylesheet" href="chrome://global/skin/in-content/common.css" type="text/css"/>
+ <link rel="stylesheet" href="chrome://global/content/aboutUrlClassifier.css" type="text/css"/>
+ <script type="text/javascript" src="chrome://global/content/aboutUrlClassifier.js"></script>
+</head>
+
+<body onload="onLoad()" class="aboutPageWideContainer">
+ <h1>&aboutUrlClassifier.pageTitle;</h1>
+ <div id="provider">
+ <h2 class="major-section">&aboutUrlClassifier.providerTitle;</h2>
+ <table id="provider-table">
+ <thead>
+ <tr id="provider-head-row">
+ <th id="col-provider">&aboutUrlClassifier.provider;</th>
+ <th id="col-lastupdatetime">&aboutUrlClassifier.providerLastUpdateTime;</th>
+ <th id="col-nextupdatetime">&aboutUrlClassifier.providerNextUpdateTime;</th>
+ <th id="col-lastupdateresult">&aboutUrlClassifier.providerLastUpdateStatus;</th>
+ <th id="col-update">&aboutUrlClassifier.providerUpdateBtn;</th>
+ </tr>
+ </thead>
+ <tbody id="provider-table-body">
+ <!-- data is generated in javascript -->
+ </tbody>
+ </table>
+ </div>
+ <div id="debug">
+ <h2 class="major-section">&aboutUrlClassifier.debugTitle;</h2>
+ <div id="debug-modules" class="options">
+ <input id="log-modules" type="text" value=""/>
+ <button id="set-log-modules">&aboutUrlClassifier.debugModuleBtn;</button>
+ <br></br>
+ <input id="log-file" type="text" value=""/>
+ <button id="set-log-file">&aboutUrlClassifier.debugFileBtn;</button>
+ <br></br>
+ <div class="toggle-container-with-text">
+ <input id="js-log" type="checkbox"/>
+ <label for="js-log">&aboutUrlClassifier.debugJSLogChk;</label>
+ </div>
+ </div>
+ <table id="debug-table">
+ <tbody>
+ <tr>
+ <th class="column">&aboutUrlClassifier.debugSBModules;</th>
+ <td id="sb-log-modules">
+ </td>
+ </tr>
+ <tr>
+ <th class="column">&aboutUrlClassifier.debugModules;</th>
+ <td id="cur-log-modules">
+ </td>
+ </tr>
+ <tr>
+ <th class="column">&aboutUrlClassifier.debugSBJSModules;</th>
+ <td id="cur-js-log">
+ </td>
+ </tr>
+ <tr>
+ <th class="column">&aboutUrlClassifier.debugFile;</th>
+ <td id="cur-log-file">
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</body>
+</html>
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -28,16 +28,19 @@ toolkit.jar:
content/global/aboutwebrtc/aboutWebrtc.css (aboutwebrtc/aboutWebrtc.css)
content/global/aboutwebrtc/aboutWebrtc.js (aboutwebrtc/aboutWebrtc.js)
content/global/aboutwebrtc/aboutWebrtc.html (aboutwebrtc/aboutWebrtc.html)
content/global/aboutSupport.js
* content/global/aboutSupport.xhtml
content/global/aboutTelemetry.js
content/global/aboutTelemetry.xhtml
content/global/aboutTelemetry.css
+ content/global/aboutUrlClassifier.js
+ content/global/aboutUrlClassifier.xhtml
+ content/global/aboutUrlClassifier.css
content/global/directionDetector.html
content/global/plugins.html
content/global/plugins.css
content/global/browser-child.js
content/global/browser-content.js
* content/global/buildconfig.html
content/global/contentAreaUtils.js
#ifndef MOZ_FENNEC
new file mode 100644
--- /dev/null
+++ b/toolkit/locales/en-US/chrome/global/aboutUrlClassifier.dtd
@@ -0,0 +1,29 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - 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/. -->
+
+<!-- LOCALIZATION NOTE the term "url-classifier" should not be translated. -->
+<!ENTITY aboutUrlClassifier.pageTitle "Information about the url-classifier">
+<!ENTITY aboutUrlClassifier.providerTitle "Provider">
+<!ENTITY aboutUrlClassifier.provider "Provider">
+<!ENTITY aboutUrlClassifier.providerLastUpdateTime "Last update time">
+<!ENTITY aboutUrlClassifier.providerNextUpdateTime "Next update time">
+<!ENTITY aboutUrlClassifier.providerLastUpdateStatus "Last update status">
+<!ENTITY aboutUrlClassifier.providerUpdateBtn "Update">
+<!ENTITY aboutUrlClassifier.lookupTitle "Lookup">
+<!ENTITY aboutUrlClassifier.lookupUrl "Url">
+<!ENTITY aboutUrlClassifier.lookupMatch "Match">
+<!ENTITY aboutUrlClassifier.lookupMatchBtn "Check Match Result">
+<!ENTITY aboutUrlClassifier.lookupLookup "Lookup">
+<!ENTITY aboutUrlClassifier.lookupBtn "Check Lookup Result">
+<!ENTITY aboutUrlClassifier.cacheTitle "Cache">
+<!ENTITY aboutUrlClassifier.memoryTitle "Memory">
+<!ENTITY aboutUrlClassifier.databaseTitle "Database">
+<!ENTITY aboutUrlClassifier.debugTitle "Debug">
+<!ENTITY aboutUrlClassifier.debugModuleBtn "Set Log Modules">
+<!ENTITY aboutUrlClassifier.debugFileBtn "Set Log File">
+<!ENTITY aboutUrlClassifier.debugJSLogChk "Set JS Log">
+<!ENTITY aboutUrlClassifier.debugSBModules "Safe Browsing log modules">
+<!ENTITY aboutUrlClassifier.debugModules "Current log modules">
+<!ENTITY aboutUrlClassifier.debugSBJSModules "Safe Browsing JS log">
+<!ENTITY aboutUrlClassifier.debugFile "Current log file">
new file mode 100644
--- /dev/null
+++ b/toolkit/locales/en-US/chrome/global/aboutUrlClassifier.properties
@@ -0,0 +1,19 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# 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/.
+
+TriggerUpdate = Trigger Update
+
+NotAvailable = N/A
+
+DisableSBJSLog = Disable Safe Browsing JS Log
+
+EnableSBJSLog = Enable Safe Browsing JS Log
+
+Enabled = Enabled
+
+Disabled = Disabled
+
+Updating = updating
+
+CannotUpdate = cannot update
--- a/toolkit/locales/jar.mn
+++ b/toolkit/locales/jar.mn
@@ -16,16 +16,18 @@
locale/@AB_CD@/global/aboutProfiles.properties (%chrome/global/aboutProfiles.properties)
#endif
locale/@AB_CD@/global/aboutServiceWorkers.dtd (%chrome/global/aboutServiceWorkers.dtd)
locale/@AB_CD@/global/aboutServiceWorkers.properties (%chrome/global/aboutServiceWorkers.properties)
locale/@AB_CD@/global/aboutSupport.dtd (%chrome/global/aboutSupport.dtd)
locale/@AB_CD@/global/aboutSupport.properties (%chrome/global/aboutSupport.properties)
locale/@AB_CD@/global/aboutTelemetry.dtd (%chrome/global/aboutTelemetry.dtd)
locale/@AB_CD@/global/aboutTelemetry.properties (%chrome/global/aboutTelemetry.properties)
+ locale/@AB_CD@/global/aboutUrlClassifier.dtd (%chrome/global/aboutUrlClassifier.dtd)
+ locale/@AB_CD@/global/aboutUrlClassifier.properties (%chrome/global/aboutUrlClassifier.properties)
locale/@AB_CD@/global/aboutWebrtc.properties (%chrome/global/aboutWebrtc.properties)
locale/@AB_CD@/global/autocomplete.properties (%chrome/global/autocomplete.properties)
locale/@AB_CD@/global/appPicker.dtd (%chrome/global/appPicker.dtd)
locale/@AB_CD@/global/brand.dtd (generic/chrome/global/brand.dtd)
locale/@AB_CD@/global/browser.properties (%chrome/global/browser.properties)
locale/@AB_CD@/global/charsetMenu.dtd (%chrome/global/charsetMenu.dtd)
locale/@AB_CD@/global/charsetMenu.properties (%chrome/global/charsetMenu.properties)
locale/@AB_CD@/global/commonDialog.dtd (%chrome/global/commonDialog.dtd)