diff --git a/Makefile.in b/Makefile.in
index f1cd311f80b2..af730e544771 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -3,7 +3,6 @@
# 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/.
-ifndef .PYMAKE
ifeq (,$(MAKE_VERSION))
$(error GNU Make is required)
endif
@@ -11,7 +10,6 @@ make_min_ver := 3.81
ifneq ($(make_min_ver),$(firstword $(sort $(make_min_ver) $(MAKE_VERSION))))
$(error GNU Make $(make_min_ver) or higher is required)
endif
-endif
export TOPLEVEL_BUILD := 1
diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js
index 19e999bfa261..d25651c10a02 100644
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -388,9 +388,6 @@ pref("content.ime.strict_policy", true);
// $ adb shell start
pref("browser.dom.window.dump.enabled", false);
-// Turn on the CSP 1.0 parser for Content Security Policy headers
-pref("security.csp.speccompliant", true);
-
// Default Content Security Policy to apply to privileged and certified apps
pref("security.apps.privileged.CSP.default", "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'");
// If you change this CSP, make sure to update the fast path in nsCSPService.cpp
diff --git a/b2g/gaia/Makefile.in b/b2g/gaia/Makefile.in
index 368e83e66d71..68ec5709d4f9 100644
--- a/b2g/gaia/Makefile.in
+++ b/b2g/gaia/Makefile.in
@@ -4,13 +4,6 @@
GAIA_PATH := gaia/profile
-ifdef .PYMAKE
-# For use of GNU make in pymake builds.
-GAIA_MAKE=$(GMAKE)
-else
-GAIA_MAKE=$(MAKE)
-endif
-
# This is needed to avoid making run-b2g depend on mozglue
WRAP_LDFLAGS :=
@@ -19,6 +12,6 @@ GENERATED_DIRS += $(DIST)/bin/$(GAIA_PATH)
include $(topsrcdir)/config/rules.mk
libs::
- +$(GAIA_MAKE) -j1 -C $(GAIADIR) clean
- +$(GAIA_MAKE) -j1 -C $(GAIADIR) profile
+ +$(MAKE) -j1 -C $(GAIADIR) clean
+ +$(MAKE) -j1 -C $(GAIADIR) profile
(cd $(GAIADIR)/profile && tar $(TAR_CREATE_FLAGS) - .) | (cd $(abspath $(DIST))/bin/$(GAIA_PATH) && tar -xf -)
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index 0a7d726e8c26..43dd3ef46cbd 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1524,9 +1524,6 @@ pref("social.sidebar.unload_timeout_ms", 10000);
pref("dom.identity.enabled", false);
-// Turn on the CSP 1.0 parser for Content Security Policy headers
-pref("security.csp.speccompliant", true);
-
// Block insecure active content on https pages
pref("security.mixed_content.block_active_content", true);
diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js
index 78e3688e3710..4388a4ef66be 100644
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -90,6 +90,7 @@ SocialUI = {
if (!this._initialized) {
return;
}
+ SocialSidebar.saveWindowState();
Services.obs.removeObserver(this, "social:ambient-notification-changed");
Services.obs.removeObserver(this, "social:profile-changed");
@@ -710,6 +711,11 @@ SocialSidebar = {
},
restoreWindowState: function() {
+ // Window state is used to allow different sidebar providers in each window.
+ // We also store the provider used in a pref as the default sidebar to
+ // maintain that state for users who do not restore window state. The
+ // existence of social.sidebar.provider means the sidebar is open with that
+ // provider.
this._initialized = true;
if (!this.canShow)
return;
@@ -737,13 +743,22 @@ SocialSidebar = {
let data = SessionStore.getWindowValue(window, "socialSidebar");
// if this window doesn't have it's own state, use the state from the opener
if (!data && window.opener && !window.opener.closed) {
- data = SessionStore.getWindowValue(window.opener, "socialSidebar");
+ try {
+ data = SessionStore.getWindowValue(window.opener, "socialSidebar");
+ } catch(e) {
+ // Window is not tracked, which happens on osx if the window is opened
+ // from the hidden window. That happens when you close the last window
+ // without quiting firefox, then open a new window.
+ }
}
if (data) {
data = JSON.parse(data);
document.getElementById("social-sidebar-browser").setAttribute("origin", data.origin);
if (!data.hidden)
this.show(data.origin);
+ } else if (Services.prefs.prefHasUserValue("social.sidebar.provider")) {
+ // no window state, use the global state if it is available
+ this.show(Services.prefs.getCharPref("social.sidebar.provider"));
}
},
@@ -754,7 +769,18 @@ SocialSidebar = {
"hidden": broadcaster.hidden,
"origin": sidebarOrigin
};
- SessionStore.setWindowValue(window, "socialSidebar", JSON.stringify(data));
+
+ // Save a global state for users who do not restore state.
+ if (broadcaster.hidden)
+ Services.prefs.clearUserPref("social.sidebar.provider");
+ else
+ Services.prefs.setCharPref("social.sidebar.provider", sidebarOrigin);
+
+ try {
+ SessionStore.setWindowValue(window, "socialSidebar", JSON.stringify(data));
+ } catch(e) {
+ // window not tracked during uninit
+ }
},
setSidebarVisibilityState: function(aEnabled) {
diff --git a/browser/base/content/content.js b/browser/base/content/content.js
index 052f3fec9ed7..cd1856249ed4 100644
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -34,22 +34,22 @@ addMessageListener("Browser:HideSessionRestoreButton", function (message) {
}
});
+addEventListener("DOMFormHasPassword", function(event) {
+ InsecurePasswordUtils.checkForInsecurePasswords(event.target);
+ LoginManagerContent.onFormPassword(event);
+});
+addEventListener("DOMAutoComplete", function(event) {
+ LoginManagerContent.onUsernameInput(event);
+});
+addEventListener("blur", function(event) {
+ LoginManagerContent.onUsernameInput(event);
+});
+
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
addEventListener("contextmenu", function (event) {
sendAsyncMessage("contextmenu", {}, { event: event });
}, false);
} else {
- addEventListener("DOMFormHasPassword", function(event) {
- InsecurePasswordUtils.checkForInsecurePasswords(event.target);
- LoginManagerContent.onFormPassword(event);
- });
- addEventListener("DOMAutoComplete", function(event) {
- LoginManagerContent.onUsernameInput(event);
- });
- addEventListener("blur", function(event) {
- LoginManagerContent.onUsernameInput(event);
- });
-
addEventListener("mozUITour", function(event) {
if (!Services.prefs.getBoolPref("browser.uitour.enabled"))
return;
diff --git a/browser/base/content/test/general/browser_urlbar_search_healthreport.js b/browser/base/content/test/general/browser_urlbar_search_healthreport.js
index 785ecbe24bd2..cc5d2451a8fc 100644
--- a/browser/base/content/test/general/browser_urlbar_search_healthreport.js
+++ b/browser/base/content/test/general/browser_urlbar_search_healthreport.js
@@ -3,15 +3,13 @@
"use strict";
-function test() {
- waitForExplicitFinish();
+add_task(function* test_healthreport_search_recording() {
try {
let cm = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
cm.getCategoryEntry("healthreport-js-provider-default", "SearchesProvider");
} catch (ex) {
// Health Report disabled, or no SearchesProvider.
ok(true, "Firefox Health Report is not enabled.");
- finish();
return;
}
@@ -20,72 +18,63 @@ function test() {
.wrappedJSObject
.healthReporter;
ok(reporter, "Health Reporter available.");
- reporter.onInit().then(function onInit() {
- let provider = reporter.getProvider("org.mozilla.searches");
- ok(provider, "Searches provider is available.");
- let m = provider.getMeasurement("counts", 3);
+ yield reporter.onInit();
+ let provider = reporter.getProvider("org.mozilla.searches");
+ ok(provider, "Searches provider is available.");
+ let m = provider.getMeasurement("counts", 3);
- m.getValues().then(function onData(data) {
- let now = new Date();
- let oldCount = 0;
+ let data = yield m.getValues();
+ let now = new Date();
+ let oldCount = 0;
- // This will to be need changed if default search engine is not Google.
- let field = "google.urlbar";
+ // This will to be need changed if default search engine is not Google.
+ let field = "google.urlbar";
- if (data.days.hasDay(now)) {
- let day = data.days.getDay(now);
- if (day.has(field)) {
- oldCount = day.get(field);
- }
- }
+ if (data.days.hasDay(now)) {
+ let day = data.days.getDay(now);
+ if (day.has(field)) {
+ oldCount = day.get(field);
+ }
+ }
- let tab = gBrowser.addTab();
- gBrowser.selectedTab = tab;
+ let tab = gBrowser.addTab();
+ gBrowser.selectedTab = tab;
- let searchStr = "firefox health report";
- let expectedURL = Services.search.currentEngine.
- getSubmission(searchStr, "", "keyword").uri.spec;
+ let searchStr = "firefox health report";
+ let expectedURL = Services.search.currentEngine.
+ getSubmission(searchStr, "", "keyword").uri.spec;
- // Expect the search URL to load but stop it as soon as it starts.
- let loadPromise = waitForDocLoadAndStopIt(expectedURL);
+ // Expect the search URL to load but stop it as soon as it starts.
+ let docLoadPromise = waitForDocLoadAndStopIt(expectedURL);
- // Meanwhile, poll for the new measurement.
- let count = 0;
- let measurementDeferred = Promise.defer();
- function getNewMeasurement() {
- if (count++ >= 10) {
- ok(false, "Timed out waiting for new measurement");
- measurementDeferred.resolve();
- return;
- }
- m.getValues().then(function onData(data) {
- if (data.days.hasDay(now)) {
- let day = data.days.getDay(now);
- if (day.has(field)) {
- let newCount = day.get(field);
- if (newCount > oldCount) {
- is(newCount, oldCount + 1,
- "Exactly one search has been recorded.");
- measurementDeferred.resolve();
- return;
- }
- }
- }
- executeSoon(getNewMeasurement);
- });
- }
- executeSoon(getNewMeasurement);
+ // Trigger the search.
+ gURLBar.value = searchStr;
+ gURLBar.handleCommand();
- // Trigger the search.
- gURLBar.value = searchStr;
- gURLBar.handleCommand();
+ yield docLoadPromise;
- // Wait for the page load and new measurement.
- Promise.all([loadPromise, measurementDeferred.promise]).then(() => {
- gBrowser.removeTab(tab);
- finish();
- });
- });
- });
-}
+ data = yield m.getValues();
+ ok(data.days.hasDay(now), "We have a search measurement for today.");
+ let day = data.days.getDay(now);
+ ok(day.has(field), "Have a search count for the urlbar.");
+ let newCount = day.get(field);
+ is(newCount, oldCount + 1, "We recorded one new search.");
+ // We should record the default search engine if Telemetry is enabled.
+ let oldTelemetry = Services.prefs.getBoolPref("toolkit.telemetry.enabled");
+ Services.prefs.setBoolPref("toolkit.telemetry.enabled", true);
+
+ m = provider.getMeasurement("engines", 1);
+ yield provider.collectDailyData();
+ data = yield m.getValues();
+
+ ok(data.days.hasDay(now), "Have engines data when Telemetry is enabled.");
+ day = data.days.getDay(now);
+ ok(day.has("default"), "We have default engine data.");
+ is(day.get("default"), "google", "The default engine is reported properly.");
+
+ // Restore.
+ Services.prefs.setBoolPref("toolkit.telemetry.enabled", oldTelemetry);
+
+ gBrowser.removeTab(tab);
+});
diff --git a/browser/base/content/test/social/browser_social_window.js b/browser/base/content/test/social/browser_social_window.js
index e93069ebc5c6..1978a6a906d0 100644
--- a/browser/base/content/test/social/browser_social_window.js
+++ b/browser/base/content/test/social/browser_social_window.js
@@ -30,17 +30,20 @@ function openWindowAndWaitForInit(parentWin, callback) {
}, topic, false);
}
+function closeWindow(w, cb) {
+ waitForNotification("domwindowclosed", cb);
+ w.close();
+}
+
function closeOneWindow(cb) {
let w = createdWindows.pop();
- if (!w) {
+ if (!w || w.closed) {
cb();
return;
}
- waitForCondition(function() w.closed,
- function() {
- info("window closed, " + createdWindows.length + " windows left");
- closeOneWindow(cb);
- }, "window did not close");
+ closeWindow(w, function() {
+ closeOneWindow(cb);
+ });
w.close();
}
@@ -126,6 +129,51 @@ let tests = {
}, cbnext);
},
+ testGlobalState: function(cbnext) {
+ setManifestPref("social.manifest.test", manifest);
+ ok(!SocialSidebar.opened, "sidebar is closed initially");
+ ok(!Services.prefs.prefHasUserValue("social.sidebar.provider"), "global state unset");
+ // mimick no session state in opener so we exercise the global state via pref
+ SessionStore.deleteWindowValue(window, "socialSidebar");
+ ok(!SessionStore.getWindowValue(window, "socialSidebar"), "window state unset");
+ SocialService.addProvider(manifest, function() {
+ openWindowAndWaitForInit(window, function(w1) {
+ w1.SocialSidebar.show();
+ waitForCondition(function() w1.SocialSidebar.opened,
+ function() {
+ ok(Services.prefs.prefHasUserValue("social.sidebar.provider"), "global state set");
+ ok(!SocialSidebar.opened, "1. main sidebar is still closed");
+ ok(w1.SocialSidebar.opened, "1. window sidebar is open");
+ closeWindow(w1, function() {
+ // this time, the global state should cause the sidebar to be opened
+ // in the new window
+ openWindowAndWaitForInit(window, function(w1) {
+ ok(!SocialSidebar.opened, "2. main sidebar is still closed");
+ ok(w1.SocialSidebar.opened, "2. window sidebar is open");
+ w1.SocialSidebar.hide();
+ ok(!w1.SocialSidebar.opened, "2. window sidebar is closed");
+ ok(!Services.prefs.prefHasUserValue("social.sidebar.provider"), "2. global state unset");
+ // global state should now be no sidebar gets opened on new window
+ closeWindow(w1, function() {
+ ok(!Services.prefs.prefHasUserValue("social.sidebar.provider"), "3. global state unset");
+ ok(!SocialSidebar.opened, "3. main sidebar is still closed");
+ openWindowAndWaitForInit(window, function(w1) {
+ ok(!Services.prefs.prefHasUserValue("social.sidebar.provider"), "4. global state unset");
+ ok(!SocialSidebar.opened, "4. main sidebar is still closed");
+ ok(!w1.SocialSidebar.opened, "4. window sidebar is closed");
+ SocialService.removeProvider(manifest.origin, function() {
+ Services.prefs.clearUserPref("social.manifest.test");
+ cbnext();
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ },
+
// Check per window sidebar functionality, including migration from using
// prefs to using session state, and state inheritance of windows (new windows
// inherit state from the opener).
diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js
index da9fcad6ab8f..1ee1125b443b 100644
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -93,6 +93,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
"resource://gre/modules/AsyncShutdown.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
+ "resource://gre/modules/LoginManagerParent.jsm");
+
#ifdef NIGHTLY_BUILD
XPCOMUtils.defineLazyModuleGetter(this, "SignInToWebsiteUX",
"resource:///modules/SignInToWebsite.jsm");
@@ -507,6 +510,8 @@ BrowserGlue.prototype = {
RemotePrompt.init();
}
+ LoginManagerParent.init();
+
Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
},
diff --git a/browser/devtools/webconsole/test/browser.ini b/browser/devtools/webconsole/test/browser.ini
index 6e5aadb5b8aa..b5a4a1c5084a 100644
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -53,8 +53,6 @@ support-files =
test-bug-782653-css-errors-1.css
test-bug-782653-css-errors-2.css
test-bug-782653-css-errors.html
- test-bug-821877-csperrors.html
- test-bug-821877-csperrors.html^headers^
test-bug-837351-security-errors.html
test-bug-846918-hsts-invalid-headers.html
test-bug-846918-hsts-invalid-headers.html^headers^
@@ -100,8 +98,6 @@ support-files =
test-repeated-messages.html
test-result-format-as-string.html
test-webconsole-error-observer.html
- test_bug_770099_bad_policy_uri.html
- test_bug_770099_bad_policy_uri.html^headers^
test_bug_770099_violation.html
test_bug_770099_violation.html^headers^
test-autocomplete-in-stackframe.html
@@ -230,13 +226,11 @@ run-if = os == "win"
[browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js]
[browser_webconsole_bug_764572_output_open_url.js]
[browser_webconsole_bug_766001_JS_Console_in_Debugger.js]
-[browser_webconsole_bug_770099_bad_policyuri.js]
[browser_webconsole_bug_770099_violation.js]
[browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js]
[browser_webconsole_bug_804845_ctrl_key_nav.js]
run-if = os == "mac"
[browser_webconsole_bug_817834_add_edited_input_to_history.js]
-[browser_webconsole_bug_821877_csp_errors.js]
[browser_webconsole_bug_837351_securityerrors.js]
[browser_webconsole_bug_846918_hsts_invalid-headers.js]
[browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js]
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js b/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js
index 9b23e67ced9f..ddb09510a3de 100644
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js
@@ -15,8 +15,8 @@ The expected console messages in the constants CSP_VIOLATION_MSG and CSP_REPORT_
*/
const TEST_VIOLATION = "http://example.com/browser/browser/devtools/webconsole/test/test_bug_1010953_cspro.html";
-const CSP_VIOLATION_MSG = 'Content Security Policy: The page\'s settings blocked the loading of a resource at http://some.example.com/test.png ("img-src http://example.com:80").';
-const CSP_REPORT_MSG = 'Content Security Policy: The page\'s settings observed the loading of a resource at http://some.example.com/test_bug_1010953_cspro.js ("script-src http://example.com:80"). A CSP report is being sent.';
+const CSP_VIOLATION_MSG = 'Content Security Policy: The page\'s settings blocked the loading of a resource at http://some.example.com/test.png ("img-src http://example.com").';
+const CSP_REPORT_MSG = 'Content Security Policy: The page\'s settings observed the loading of a resource at http://some.example.com/test_bug_1010953_cspro.js ("script-src http://example.com"). A CSP report is being sent.';
let hud = undefined;
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_bad_policyuri.js b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_bad_policyuri.js
deleted file mode 100644
index de80168df0ab..000000000000
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_bad_policyuri.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- *
- * ***** END LICENSE BLOCK ***** */
-
-// Tests that the Web Console CSP messages are displayed
-
-const TEST_BAD_POLICY_URI = "https://example.com/browser/browser/devtools/webconsole/test/test_bug_770099_bad_policy_uri.html";
-
-let hud = undefined;
-
-function test() {
- addTab("data:text/html;charset=utf8,Web Console CSP bad policy URI test");
- browser.addEventListener("load", function _onLoad() {
- browser.removeEventListener("load", _onLoad, true);
- openConsole(null, loadDocument);
- }, true);
-}
-
-function loadDocument(theHud) {
- hud = theHud;
- hud.jsterm.clearOutput();
- browser.addEventListener("load", onLoad, true);
- content.location = TEST_BAD_POLICY_URI;
-}
-
-function onLoad(aEvent) {
- browser.removeEventListener("load", onLoad, true);
-
- waitForMessages({
- webconsole: hud,
- messages: [{
- text: "can't fetch policy",
- category: CATEGORY_SECURITY,
- severity: SEVERITY_ERROR,
- }],
- }).then(finishTest);
-}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js
index a463d1d95897..79dde9c4e402 100644
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js
@@ -8,7 +8,7 @@
// Tests that the Web Console CSP messages are displayed
const TEST_VIOLATION = "https://example.com/browser/browser/devtools/webconsole/test/test_bug_770099_violation.html";
-const CSP_VIOLATION_MSG = 'Content Security Policy: The page\'s settings blocked the loading of a resource at http://some.example.com/test.png ("default-src https://example.com:443").'
+const CSP_VIOLATION_MSG = 'Content Security Policy: The page\'s settings blocked the loading of a resource at http://some.example.com/test.png ("default-src https://example.com").'
let hud = undefined;
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_821877_csp_errors.js b/browser/devtools/webconsole/test/browser_webconsole_bug_821877_csp_errors.js
deleted file mode 100644
index dae8f4d8b42c..000000000000
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_821877_csp_errors.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Tests that CSP errors from nsDocument::InitCSP are logged to the Web Console
-
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-821877-csperrors.html";
-const CSP_DEPRECATED_HEADER_MSG = "The X-Content-Security-Policy and X-Content-Security-Report-Only headers will be deprecated in the future. Please use the Content-Security-Policy and Content-Security-Report-Only headers with CSP spec compliant syntax instead.";
-
-function test()
-{
- addTab(TEST_URI);
- browser.addEventListener("load", function onLoad(aEvent) {
- browser.removeEventListener(aEvent.type, onLoad, true);
- openConsole(null, function testCSPErrorLogged (hud) {
- waitForMessages({
- webconsole: hud,
- messages: [
- {
- name: "Deprecated CSP header error displayed successfully",
- text: CSP_DEPRECATED_HEADER_MSG,
- category: CATEGORY_SECURITY,
- severity: SEVERITY_WARNING
- },
- ],
- }).then(finishTest);
- });
- }, true);
-}
diff --git a/browser/devtools/webconsole/test/test-bug-821877-csperrors.html b/browser/devtools/webconsole/test/test-bug-821877-csperrors.html
deleted file mode 100644
index 25d9da1c0905..000000000000
--- a/browser/devtools/webconsole/test/test-bug-821877-csperrors.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- Bug 821877 - Log CSP Errors to Web Console
-
-
-
-
This page is served with a deprecated CSP header.
-
-
diff --git a/browser/devtools/webconsole/test/test-bug-821877-csperrors.html^headers^ b/browser/devtools/webconsole/test/test-bug-821877-csperrors.html^headers^
deleted file mode 100644
index 426d8738c602..000000000000
--- a/browser/devtools/webconsole/test/test-bug-821877-csperrors.html^headers^
+++ /dev/null
@@ -1 +0,0 @@
-X-Content-Security-Policy: default-src *; options inline-script
diff --git a/browser/devtools/webconsole/test/test_bug_770099_bad_policy_uri.html b/browser/devtools/webconsole/test/test_bug_770099_bad_policy_uri.html
deleted file mode 100644
index eb0c52c3acb2..000000000000
--- a/browser/devtools/webconsole/test/test_bug_770099_bad_policy_uri.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- Test for Bug 770099 - bad policy-uri
-
-
-
-Mozilla Bug 770099
-
-
diff --git a/browser/devtools/webconsole/test/test_bug_770099_bad_policy_uri.html^headers^ b/browser/devtools/webconsole/test/test_bug_770099_bad_policy_uri.html^headers^
deleted file mode 100644
index b64692028c62..000000000000
--- a/browser/devtools/webconsole/test/test_bug_770099_bad_policy_uri.html^headers^
+++ /dev/null
@@ -1,2 +0,0 @@
-X-Content-Security-Policy: policy-uri http://example.com/some_policy
-Content-type: text/html; charset=utf-8
diff --git a/browser/devtools/webconsole/test/test_bug_770099_violation.html^headers^ b/browser/devtools/webconsole/test/test_bug_770099_violation.html^headers^
index 5374efd3e17b..4c6fa3c26a77 100644
--- a/browser/devtools/webconsole/test/test_bug_770099_violation.html^headers^
+++ b/browser/devtools/webconsole/test/test_bug_770099_violation.html^headers^
@@ -1 +1 @@
-X-Content-Security-Policy: default-src 'self'
+Content-Security-Policy: default-src 'self'
diff --git a/browser/experiments/Experiments.jsm b/browser/experiments/Experiments.jsm
index 8a8afac6f410..288814df1ea1 100644
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -597,6 +597,7 @@ Experiments.Experiments.prototype = {
active: experiment.enabled,
endDate: experiment.endDate.getTime(),
detailURL: experiment._homepageURL,
+ branch: experiment.branch,
});
}
@@ -628,6 +629,54 @@ Experiments.Experiments.prototype = {
return info;
},
+ /**
+ * Experiment "branch" support. If an experiment has multiple branches, it
+ * can record the branch with the experiment system and it will
+ * automatically be included in data reporting (FHR/telemetry payloads).
+ */
+
+ /**
+ * Set the experiment branch for the specified experiment ID.
+ * @returns Promise<>
+ */
+ setExperimentBranch: Task.async(function*(id, branchstr) {
+ yield this._loadTask;
+ let e = this._experiments.get(id);
+ if (!e) {
+ throw new Error("Experiment not found");
+ }
+ e.branch = String(branchstr);
+ this._dirty = true;
+ Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC, null);
+ yield this._run();
+ }),
+ /**
+ * Get the branch of the specified experiment. If the experiment is unknown,
+ * throws an error.
+ *
+ * @param id The ID of the experiment. Pass null for the currently running
+ * experiment.
+ * @returns Promise
+ * @throws Error if the specified experiment ID is unknown, or if there is no
+ * current experiment.
+ */
+ getExperimentBranch: Task.async(function*(id=null) {
+ yield this._loadTask;
+ let e;
+ if (id) {
+ e = this._experiments.get(id);
+ if (!e) {
+ throw new Error("Experiment not found");
+ }
+ } else {
+ e = this._getActiveExperiment();
+ if (e === null) {
+ throw new Error("No active experiment");
+ }
+ }
+ return e.branch;
+ }),
+
/**
* Determine whether another date has the same UTC day as now().
*/
@@ -1013,6 +1062,17 @@ Experiments.Experiments.prototype = {
return e.id;
},
+ getActiveExperimentBranch: function() {
+ if (!this._experiments) {
+ return null;
+ }
+ let e = this._getActiveExperiment();
+ if (!e) {
+ return null;
+ }
+ return e.branch;
+ },
+
_getActiveExperiment: function () {
let enabled = [experiment for ([,experiment] of this._experiments) if (experiment._enabled)];
@@ -1258,6 +1318,8 @@ Experiments.ExperimentEntry = function (policy) {
this._lastChangedDate = null;
// Has this experiment failed to activate before?
this._failedStart = false;
+ // The experiment branch
+ this._branch = null;
// We grab these from the addon after download.
this._name = null;
@@ -1306,6 +1368,7 @@ Experiments.ExperimentEntry.prototype = {
"_addonId",
"_startDate",
"_endDate",
+ "_branch",
]),
DATE_KEYS: new Set([
@@ -1313,6 +1376,10 @@ Experiments.ExperimentEntry.prototype = {
"_endDate",
]),
+ UPGRADE_KEYS: new Map([
+ ["_branch", null],
+ ]),
+
ADDON_CHANGE_NONE: 0,
ADDON_CHANGE_INSTALL: 1,
ADDON_CHANGE_UNINSTALL: 2,
@@ -1344,6 +1411,14 @@ Experiments.ExperimentEntry.prototype = {
return this._manifestData.id;
},
+ get branch() {
+ return this._branch;
+ },
+
+ set branch(v) {
+ this._branch = v;
+ },
+
get startDate() {
return this._startDate;
},
@@ -1376,6 +1451,12 @@ Experiments.ExperimentEntry.prototype = {
* @return boolean Whether initialization succeeded.
*/
initFromCacheData: function (data) {
+ for (let [key, dval] of this.UPGRADE_KEYS) {
+ if (!(key in data)) {
+ data.set(key, dval);
+ }
+ }
+
for (let key of this.SERIALIZE_KEYS) {
if (!(key in data) && !this.DATE_KEYS.has(key)) {
this._log.error("initFromCacheData() - missing required key " + key);
@@ -1970,6 +2051,9 @@ let stripDateToMidnight = function (d) {
function ExperimentsLastActiveMeasurement1() {
Metrics.Measurement.call(this);
}
+function ExperimentsLastActiveMeasurement2() {
+ Metrics.Measurement.call(this);
+}
const FIELD_DAILY_LAST_TEXT = {type: Metrics.Storage.FIELD_DAILY_LAST_TEXT};
@@ -1983,6 +2067,17 @@ ExperimentsLastActiveMeasurement1.prototype = Object.freeze({
lastActive: FIELD_DAILY_LAST_TEXT,
}
});
+ExperimentsLastActiveMeasurement2.prototype = Object.freeze({
+ __proto__: Metrics.Measurement.prototype,
+
+ name: "info",
+ version: 2,
+
+ fields: {
+ lastActive: FIELD_DAILY_LAST_TEXT,
+ lastActiveBranch: FIELD_DAILY_LAST_TEXT,
+ }
+});
this.ExperimentsProvider = function () {
Metrics.Provider.call(this);
@@ -1997,6 +2092,7 @@ ExperimentsProvider.prototype = Object.freeze({
measurementTypes: [
ExperimentsLastActiveMeasurement1,
+ ExperimentsLastActiveMeasurement2,
],
_OBSERVERS: [
@@ -2040,8 +2136,8 @@ ExperimentsProvider.prototype = Object.freeze({
this._experiments = Experiments.instance();
}
- let m = this.getMeasurement(ExperimentsLastActiveMeasurement1.prototype.name,
- ExperimentsLastActiveMeasurement1.prototype.version);
+ let m = this.getMeasurement(ExperimentsLastActiveMeasurement2.prototype.name,
+ ExperimentsLastActiveMeasurement2.prototype.version);
return this.enqueueStorageOperation(() => {
return Task.spawn(function* recordTask() {
@@ -2055,6 +2151,11 @@ ExperimentsProvider.prototype = Object.freeze({
this._log.info("Recording last active experiment: " + todayActive.id);
yield m.setDailyLastText("lastActive", todayActive.id,
this._experiments._policy.now());
+ let branch = todayActive.branch;
+ if (branch) {
+ yield m.setDailyLastText("lastActiveBranch", branch,
+ this._experiments._policy.now());
+ }
}.bind(this));
});
},
diff --git a/browser/experiments/test/xpcshell/head.js b/browser/experiments/test/xpcshell/head.js
index a45020303ee3..86df15e4fdfc 100644
--- a/browser/experiments/test/xpcshell/head.js
+++ b/browser/experiments/test/xpcshell/head.js
@@ -76,6 +76,7 @@ const FAKE_EXPERIMENTS_1 = [
description: "experiment 1",
active: true,
detailUrl: "https://dummy/experiment1",
+ branch: "foo",
},
];
@@ -87,6 +88,7 @@ const FAKE_EXPERIMENTS_2 = [
active: false,
endDate: new Date(2014, 2, 11, 2, 4, 35, 42).getTime(),
detailUrl: "https://dummy/experiment2",
+ branch: null,
},
{
id: "id1",
@@ -95,6 +97,7 @@ const FAKE_EXPERIMENTS_2 = [
active: false,
endDate: new Date(2014, 2, 10, 0, 0, 0, 0).getTime(),
detailURL: "https://dummy/experiment1",
+ branch: null,
},
];
diff --git a/browser/experiments/test/xpcshell/test_api.js b/browser/experiments/test/xpcshell/test_api.js
index 3a5304ce7837..ab0be9d3a400 100644
--- a/browser/experiments/test/xpcshell/test_api.js
+++ b/browser/experiments/test/xpcshell/test_api.js
@@ -171,6 +171,14 @@ add_task(function* test_getExperiments() {
let addons = yield getExperimentAddons();
Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed.");
+ try {
+ let b = yield experiments.getExperimentBranch();
+ Assert.ok(false, "getExperimentBranch should fail with no experiment");
+ }
+ catch (e) {
+ Assert.ok(true, "getExperimentBranch correctly threw");
+ }
+
// Trigger update, clock set for experiment 1 to start.
now = futureDate(startDate1, 5 * MS_IN_ONE_DAY);
@@ -196,6 +204,19 @@ add_task(function* test_getExperiments() {
"Property " + k + " should match reference data.");
}
+ let b = yield experiments.getExperimentBranch();
+ Assert.strictEqual(b, null, "getExperimentBranch should return null by default");
+
+ b = yield experiments.getExperimentBranch(EXPERIMENT1_ID);
+ Assert.strictEqual(b, null, "getExperimentsBranch should return null (with id)");
+
+ yield experiments.setExperimentBranch(EXPERIMENT1_ID, "foo");
+ b = yield experiments.getExperimentBranch();
+ Assert.strictEqual(b, "foo", "getExperimentsBranch should return the set value");
+
+ Assert.equal(observerFireCount, ++expectedObserverFireCount,
+ "Experiments observer should have been called.");
+
Assert.equal(gTimerScheduleOffset, 10 * MS_IN_ONE_DAY,
"Experiment re-evaluation should have been scheduled correctly.");
diff --git a/browser/experiments/test/xpcshell/test_cache.js b/browser/experiments/test/xpcshell/test_cache.js
index cba484bf1953..2de87ba993b3 100644
--- a/browser/experiments/test/xpcshell/test_cache.js
+++ b/browser/experiments/test/xpcshell/test_cache.js
@@ -190,6 +190,13 @@ add_task(function* test_cache() {
checkExperimentListsEqual(experimentListData.slice(1), list);
checkExperimentSerializations(experiments._experiments.values());
+ let branch = yield experiments.getExperimentBranch(EXPERIMENT1_ID);
+ Assert.strictEqual(branch, null);
+
+ yield experiments.setExperimentBranch(EXPERIMENT1_ID, "testbranch");
+ branch = yield experiments.getExperimentBranch(EXPERIMENT1_ID);
+ Assert.strictEqual(branch, "testbranch");
+
// Re-init, clock set for experiment 1 to stop.
now = futureDate(now, 20 * MS_IN_ONE_DAY);
@@ -207,6 +214,9 @@ add_task(function* test_cache() {
checkExperimentListsEqual(experimentListData.slice(1), list);
checkExperimentSerializations(experiments._experiments.values());
+ branch = yield experiments.getExperimentBranch(EXPERIMENT1_ID);
+ Assert.strictEqual(branch, "testbranch");
+
// Re-init, clock set for experiment 2 to start.
now = futureDate(startDates[1], 20 * MS_IN_ONE_DAY);
diff --git a/browser/experiments/test/xpcshell/test_healthreport.js b/browser/experiments/test/xpcshell/test_healthreport.js
index 965348af9b54..f4e9bcbd2f85 100644
--- a/browser/experiments/test/xpcshell/test_healthreport.js
+++ b/browser/experiments/test/xpcshell/test_healthreport.js
@@ -9,6 +9,8 @@ Cu.import("resource:///modules/experiments/Experiments.jsm");
Cu.import("resource://testing-common/services/healthreport/utils.jsm");
Cu.import("resource://testing-common/services-common/logging.js");
+const kMeasurementVersion = 2;
+
function getStorageAndProvider(name) {
return Task.spawn(function* get() {
let storage = yield Metrics.Storage(name);
@@ -53,7 +55,7 @@ add_task(function* test_collect() {
// Initial state should not report anything.
yield provider.collectDailyData();
- let m = provider.getMeasurement("info", 1);
+ let m = provider.getMeasurement("info", kMeasurementVersion);
let values = yield m.getValues();
Assert.equal(values.days.size, 0, "Have no data if no experiments known.");
@@ -69,6 +71,8 @@ add_task(function* test_collect() {
let day = values.days.getDay(now);
Assert.ok(day.has("lastActive"), "Has lastActive field.");
Assert.equal(day.get("lastActive"), "id2", "Last active ID is sane.");
+ Assert.strictEqual(day.get("lastActiveBranch"), undefined,
+ "no branch should be set yet");
// Making an experiment active replaces the lastActive value.
replaceExperiments(provider._experiments, FAKE_EXPERIMENTS_1);
@@ -76,6 +80,8 @@ add_task(function* test_collect() {
values = yield m.getValues();
day = values.days.getDay(now);
Assert.equal(day.get("lastActive"), "id1", "Last active ID is the active experiment.");
+ Assert.equal(day.get("lastActiveBranch"), "foo",
+ "Experiment branch should be visible");
// And make sure the observer works.
replaceExperiments(provider._experiments, FAKE_EXPERIMENTS_2);
diff --git a/browser/locales/en-US/searchplugins/eBay.xml b/browser/locales/en-US/searchplugins/eBay.xml
index c6eb7734e2bc..d26245928538 100644
--- a/browser/locales/en-US/searchplugins/eBay.xml
+++ b/browser/locales/en-US/searchplugins/eBay.xml
@@ -7,6 +7,8 @@
eBay - Online auctionsISO-8859-1data:image/x-icon;base64,AAABAAIAEBAAAAAAAAB6AQAAJgAAACAgAAAAAAAAQgMAAKABAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAFBSURBVDjLtZPdK0MBGIf3J5Babhx3rinFBWuipaUskX9DYvkopqgV90q5UJpyp0OKrUWM2VrRsS9D0zZKHGaOnW1nj4vtypVtPPe/533r9746QAAOAJXfo5Yzgg44pHrcugon/6Sgo0b+XuAOZ2iZiVQmyPoDpIwmUkYTzqM7GsdDdC7F6Lbf8pzOkfWOouzqeZem2b+2AqAV8zjD8yVBqqcf2b7C66yNiMGMfixIQSvi8Mp0LEbR5ADq1QSKWM+Gx0RC9nOZ2GLzwlIWdPWiuNzk4w/EpThNkyEAXKEP2ud8KGId2sspilhPMrmNwzfCuqePr/xbSfC5I/I0MMSj2YJ3z49gDdO2cEOrLUowJpE9G0QRG1ClKbR0EIdvmOPYcnUtnN+vsnZiQC1k/qnGagQ1n3LNzySUJZVskitnmr8BlQG7T2hvgxsAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAMJSURBVFjD7ZddSFNhGMeHXXQTZFFCWfR1pRhUECQlBdWVToo+6KYu1KigtDASG5qUfZgFZvahEDosECPDktKZS1FL+1DRnEvdUptjug91X2dnZzv/3vO6OZbWnR4v9sADL+fs7P97/s/znu2VAJD4UkpSSdKG+QubTyPBr+sXz8XCR64fIAHihVTis0SsUAoAVhEBrBKIHCGAEMB/ARi3F5LkbpS2WMRzYEEBXC2tsD6T03R9agsCGLNyqPw6CXmrBT06JvhbPHZwmkdwtR0B138PPKOHgzXD5jLAy3tmibo4K9weZwDAazJj/FQKRnfugfHMeRiTz0K3Ixam1HQKcPC+Fisu9NK1P08Uj4DleHgMdXC+WQ7nu3UEOhFMfTQcVUvQ1H4IN2sj8H2k7K+2TqCc3GseyA8AmDOzMBq7D9bS8sAr6nEJdNt3UbHVF1XQGtmZew8bTPT6tWoD3KpsUvlR8NxUoEICMvl6KQo+xqCwcRs4T8Ax5c8bFExjbAgAjO7aS8VsLypgq3g5nWStjztAhWRVhqAqeB6IuKTClkw1eNYEbrCQQBwD8yGGOsAooogLYejQPKBi7UPF9DkH+ezd+o141ZkUPAOC+L9SAMivNc7q46YMNSLTe4n1kaQF4XD3ZIDTPgU3XEYciKcAHrsGJS1xKFBGgyVzouiT4VbdGhjt/cEA5isyKsaz7jl3we7bg7Rqf6j0LoSldON4wWcqJDgQNGTN++l13vELA+MK6kKd6iryFOvxtidt9i5gO7owdjKJQliflNAU1pas6xQgnAzg1ux+lJEdILixNr0Pq9JUUA8NwVG9DM73G0jlcnh+V4BpjIWzJmIGQIjnXw5TiDuKSEwxurm3ITc8DNO51BnrLbIcsrW0dNA6RxgUKU1UdGVqLy5X6qGzTLvlnewiBZyGs3Yz6X8UeaYI3olvZDhzwLumZ+eHvooCCC0Q5VUsb4unwycM4YIDqA01tPqmgbzQr2EIYPECiPm33LYoDiZSsY9moh9O/Znoa4d9HkXtPg2pX/cPKCoRQ+ocZa4AAAAASUVORK5CYII=
+data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAYAAADovjFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjQ0MDYxRTZDQjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjQ0MDYxRTZEQjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NDQwNjFFNkFCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NDQwNjFFNkJCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7+A48PAAAMr0lEQVR42txYaZBVxRU+3ffet86+z4jMhC2gMzhixShKXKJJaQRFNHEBkhjUiBisWDEpjaWJEo0CP1DcEjUGiyRCLKIghahUjKCowRHZBkUdhhEYmO29edtduvN13/uGYRHxhymTW3Xu2re7zznf+c7pZtuogogYGZQlkxzcGsRCBhHnJCGUSlIJl7S7sI5On/Ic9ZWOIur5EN9NCo4fQ+4J7j+AnE1HODgjMnBiuJKU5AhcbDykq+jps6+i6aNeoVS/6X/nlm5D0oUIX5iaT4gwI4rieRlzaQUJqho0BpN0zIdk/jUSJ93n5x77zBiN6dtJS/8xjcjLEsUq/Yn5RzWkLpDGQ/9ViqMxfYH5/dePYzKCBa98Eiuh87q20m0v3kxUBH25kf+cGmyvwf+ZRt7z9JU++DG3BBz3kkVzti+msZueJSpDWAjvM7AGw8EASsRX3ACfbQQVj65L0nGgD8SxiXCfQEyqY+GrtxNluonCRUd0s/K+aXwZ02VfihHMwQMohcFWxEQUcR8dyq1QDeXMCBlWDl93G32JnTvQ8sz+j+jytx+lJefcSbTnvcGhwZVNDO4ToScItEPDISUQsBy143X7F1B2GKRScSEEnhD78e0DRYEqBnOB/fPsdKx2V7/lESrwsymDASVliJnherOm9gZWXPQ9Fo02MsvSWUK1VKgwUukWt69vWfbTj+ff9tbC5NLmaSRjZYyyvfmJZ4NBmnKu/KXnycm4jyloKHA5npQwzuuIkj+j9R/lEXXnJ5Owr0cn38HAX9O9Ma57ZcJRjdpwWjaS8bnrQvEpJhlnWOhdSJGwneS1n2sAqVTidRGraD4eWDzOS0wOOwrKkVlS8aPwiPpHKRYPM8Mgmc2RTKdddJ9g3ChlsRjjhQXNRkV5c1dl2fXN7/37iivXPv7a4ovmGJTp8WOAqAuXG4GAh8g7KNhEgBIGD0wQjCag3TT8czE+9RrM8w0gxQ0w18NywLc6XwIBsh/XUpXY8K0elp59qkfTe0zetypU0lAr/NQuhPOa7WQX8aMwnUJAxCyYFzGLf6AMGw67hChPUKwoflmkccxTFAqHGTzutnWsyG58/1x706bK3MZ3a5zNW6rsTZsnuZ92rpeeS6ywuJZG1f9zVtsyi/Z+uIVC8fwY4yEPKcchQv4Qtdh4pMgKg7GqsMnOhE5P5JEOj3wLwfgWsYiVdmNK37OQSx72kylT3n8T0DwXPVXhTQ3joSrUJhdKxjZ4ftItPT+XaBjqpqkbTwI1Rcgs+L3yhTwKCkyDD7HM2BUewl5Ij3p7uiZyycyoObz+r6SUQwe5XfueSn20+SIv1b0GL3oZcQfX/W5i3wvZ1pbTRFfvWoas0F05lL4Z771v7M61iNjy/DhhDTeS00yTrgP031DoUAJwrYVuMzDD6YP8MpJk0YJ9brlip9kHUonsAipOx80a3PdBwM7gA0krIafAWHvSsDTHYGc4yZ4cY1ohg0dqLTM87bMykpobDHU/YyjKMEvXy7Sm+3PLuVFeMYPH44Zq4XX1tNnt268JQcFo4ylknXAChcaeRNbor1NEPceKyWndfKnM2SIHmuMFxoxx3t5pJMzBmeFJcMEzjiMP53LFQsJbhOk8M/Au3P3Tv3RcWuUm6VfhkDgZPm3C2+P8UBDKx6BBzF6oqPCCPtl8Fgw23MusLvOyrzrM1O1DZuF9/BAWZEL/qlDQYJnxK2WQ2rNm/2w7qjiiqOACGcSf159eGamDAUaPILwnHokQjwKq6lpcqA3CK6o7ZSLZpuYF0xfVWLlzgSJn0Kh3aSKEO0CE/qSZyrjSr1VVwEq6d6B5rJ02fXLJpdPX373diFKLaYY3wUs5hAKMwc5Hi8twvRpXIIipEv0adHCK+tXGOKWS+iq85C0pHe9AgxGps8zIT0RAKxIpQ4DfPYhlFc5VCwQGFLkiu9XO2qsMONNk0cgwclAT2DaZ1ZWXIyNMEumM7zV2wJcqOxAwbo0Y5gEJNaT15hSXdi28m2e2Dlza/d842Z6kfMkoYDVmDPS3BY97dcktuXJVWV20U3UxSQg5FfF+DtYNFTojaH5gQZyLg4Clci5WE6OHunbLJiO9ppzHzkGWUGi413GzT6jmMgJjobwJCaPB8mJTpEITjGDbiRsNqKCmZLJIpEQrqOZrmuU6cA4xwEAFBF2l+oYAd9XkvAyV2r2KmQ3fBir+2UH/SCkPMP3BXe7XRsjUUl3tq9n7mh6cJTP0oPScQWMzlXJ3QhLoHJ5hbvDheMiI4D4+VEM+eY3Hoh8rQxlGuBJouN7OZR/T1lMZwSuYzwELlV8cmV5vM2eNqv2EMoLM5fqR/qo1J+zf/ziPFTzLiuIYMns4s4RC2orwvCwWOWorG0PLar49mdzULPU/+qvhh+R9pklL+pwnDir6avU5V05X1C2/2Syk49Pdea/L5+GRecgQG5lwQc7CR5I2jkbFTTgvCFaD7lCgrkS4nyRY6vkSo3CS9NFwj+tkH7PVtKU5KizikwVSMQPystR/kxs+UFyZUPZjXlI8XIMt2Z+yP/rwlXBTMxnFRSATjwaKFUyA9SXJ2dVGdrKXSkFUb9WeQS+POw3oyc4KOKgKETAaBtmmO0cVopCAFKnLaNv1fC9L+gZuyrRFeJqaC7ccr+oKyTT438XdxYfWeFJHFkgS9QAeT8t/yUGK8K0B8iYlZxXL+CRlbdMIV1hmdGZWZh6OyIJ5KhsgnSDyM2vdnPO2OQiYXPT1v6AfFScMOe46TLowt/FtZIFW8jo6yNu9h9yd7eRsa6X0+xvI7ek7waysWdBZOWTB5b1v3D152+KxFKs9UNtI+XsVTqp09pfR/kLaDLzoRwn7jYapC2ou6NhzatnmzaooDia1wYew8prQfpfMUtWsyhPo2lPMekneCPkl3HBAwhGi3Rb9T3NkCkWSphm9Niqt8SERuUhwT1dKTi4xy1ClsorqQEynq+sxK1n9AMVjIYR2PDy66WVnW8sEu3OXjUyst1uEWkRpNFvxSNNJK0IVJQ3Ky7TDW7ePYgtJuAeKcsYmccO4DUb43UFlC2Ix2PS4A5cLtMZuIQ0t3vCzkfFPG0EyJwYtL0QfEfBMlvIBrdYmTG2oIGV6zosqpxxUaeM0DMFdYkhKieTPQ0bshypOOLeaY7JsrQazImqWWpWNuC2KDAevfzngm8vsaL+EBctlo6zo1HDjuFaromYmLywbx+IFw3isdJxVXj0z3jR2q1kQbfBsh8p3fUDru4snrqs/u5uyXYPJToX+HFfQapTPV+FxnBI8TwXcV8MUvx2wjRtdMyy0cwkI6gVP5K1ItZjwBsxnMu7rITVA14moE6CY3AIUfdcnSsqnZdSKkmqlEvVBdue85L2cGXnUDWzpZEX/zYoIRYCgvJgeFZLo71tpbNw40Rox8nFeUFDLKssbQmVlC0U2ozOCwjaPxHQ+0cvrRGInbd0xY97Jv+4WNaMnUudmbUD034Yxv4/5LEU9ch7S3XkDgafTZR4tqlxgi4XgV5eYvYqh3kFtdSuUv99fN8gxSEPP+SSoZu3o0AgWWHPRxSrcrg6w0GyjlYJGI5q0Qvecl7rLYrGpnJvHK5I0EE45r3+FyLjbQkdYkZuKeTlFUCj1LqeW90ayqsrprKRkshGNNiGoanRxAwW83p7dMp1pEX29y8r2dTz9enRobsn4qUT9HcvRazrorxWWX2NwOZyb7EZXyCmwYSMGtZQ+GLsDyF4bsviTMNBLOZU1iOcN8wBi/1+w8kw8TYDX6wdNtw+rnHWkVp7Sfg70idKH5gZA2Jcvk+vgZhOdAVW2w9J/ivLSOzxNqh45dmK2oijOjrKfwLBkR7ZJuZ27HpGdex8xo3HUEOEyT3gREA2QlNwv3bQqP7TVO4qGIPmC2NL9K/G40mdwfycJA/VGTISEZHNSnkCa4cWwpWsZtBdGEAY/sCl1SHGNRZP1ps4gwq3GqjDMVQLgof3Ew56/8eqXbjj9Il8+FeBdEtfnTZ8sULVwy4hdrStIqJjlib9lo2KHwQ4ttw7bVNF1MKYU8VOiK1xh251C7SqBmVVYMAr55TUybUxtuDpZvYT1a7fDl6xBnZQIZGARI+XnbXlow+w9/L087E00ePUEptaGqVRDy5ARv93k4WFqZak2CrJ26hY6yurSPPLGjt4f9wtBaeqrhJDrfWX2BZVC8UCrpTDAO9BkiK4lWFGYFd6pUKBSZc5JLKKs1xFix7S99r9zaAMEBPd3gPYlSG1Q10WMwqdAhEj/rt5jsEXyVq3l/5MRmF40EW3HzRLMfjv5IWBpFBj1Foue5Ul7D/IZy1BqUS4s93A6Mhfkj/8IMADEmqUjWa9CogAAAABJRU5ErkJggg==
+data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAYAAABGkOCVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkE4OUIxMDhEQjUyNjExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkE4OUIxMDhFQjUyNjExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTg5QjEwOEJCNTI2MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QTg5QjEwOENCNTI2MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7A0O4yAAAeb0lEQVR42uxdCZRd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
diff --git a/browser/locales/en-US/searchplugins/google.xml b/browser/locales/en-US/searchplugins/google.xml
index 7af19a82fe70..95588cc4bf6c 100644
--- a/browser/locales/en-US/searchplugins/google.xml
+++ b/browser/locales/en-US/searchplugins/google.xml
@@ -7,6 +7,8 @@
Google SearchUTF-8data:image/x-icon;base64,AAABAAIAEBAAAAAAAAB9AQAAJgAAACAgAAAAAAAA8gIAAKMBAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAFESURBVDjLpZNJSwNBEIXnt4lE4kHxovgT9BDwJHqPy0HEEOJBiAuCRg+KUdC4QS4KrpC4gCBGE3NQ48JsnZ6eZ3UOM6gjaePhQU93v6+qq2q0pqgeJj2S8EdJT1hr0OxBtKCD5iEd8QxDYpvhvOBAuMDKURX9C9aPu4GA1GEVkzvMg10UBfYveWAWgYAP00V01fa+R9M2bA51wJvhIn3qR+ybt3D3JNQBE5sMjCIOLFpoHzOwdsLRO22qA6R6kiZiWwxUvy/PUQZIhYZ1vFM9cvcOOsYNdcBgysISdSJBnZjJMlR0Fw8vAp0xoz5gao/h+NZBy4i/10XGwrPA+hmvDyhVRG2Avu/LwcrkFADZa16L1h330w1RNgc3DiJzCpPYRm1bpveXX11clQR28xwblHpk1vq1iP/5mcoS0CoXDZiL0vsJ+dzfl+3T/VYAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAK5SURBVFjDxVfrSxRRFJ9/Jta/oyWjF5XQm6D6EkHRgygIIgjUTcueVgqVWSRRkppEUQYWWB8ye1iGWilWlo/Ude489s7M6Zw7D9dlt53dmd29cFiWvXvO77x+51xpaaUsoSxBaUWZQ4ECy5xji2xKZDyCMlMEw6lCNiOSgwZKJK1SkcKeSealfP64t0mBjl4Ow39MkDUL0p2RSROOtqhZdeUEYM1pBl39XCg/fEeFtWcY7G9W4csvUxjlBkCsQ4Nt9QyWVfvT6RsAKXw3aoDGATZeYIt+W1kjw7cJG0RctWDTRebbKd8A6h5pwsDb70ba3w/eUr3wt/cmwgfw6Yft4TNMQaY7o1P2ncm4FT4ANQH/jQBJ2xv7kqIXEADDql8eS3+n8bku7oxNm+EDIM/dU92upb3T/NJGeaNbDx/AsbsLRUY5Xn92caWXY5d8RV6gWllxSg4fAEnTC90DQW13BLlgXR2D3dcUeDVkwOthA1bXspxILWcm3HdThcfvufB26LcJpkOEAz9NKI/lzqpSEC7feol5EWnpSeSlIxCALUkApmULdjUqxQVAQnl3D/X/yQda4QBEq2TYc12By091MQ17Bg3R88nHKlQbVmHvj89awNBLYrwT9zXY2aBAxTkGFdiSxP/Jp6FLDw+AS7GfsdJTJ2EqSO5khD43nGfBARy/ZxOQgZHe7GPM1jzUvChUtmnBAXQPcKGMJp3fdFGq6NByEhiAO4b/YptFfQJwNyQ/bZkVQGcf90Ja25ndIyrKBOa/f8wIpwi3X1G8UcxNu7ozUS7tiH0jBswwS3RIaF1w6LYKU/ML2+8sGnjygQswtKrVIy/Qd9qQP6LnO64q4fPAKpxyZIymHo1jWk6p1ag2BsdNwQMHcC+M5kHFJX+YlPxpVlbCx2mZ5DzPI04k4kUwHHdskU3pH76iftG8yWlkAAAAAElFTkSuQmCC
+data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAYAAADovjFxAAAKQWlDQ1BJQ0MgUHJvZmlsZQAASA2dlndUU9kWh8+9N73QEiIgJfQaegkg0jtIFQRRiUmAUAKGhCZ2RAVGFBEpVmRUwAFHhyJjRRQLg4Ji1wnyEFDGwVFEReXdjGsJ7601896a/cdZ39nnt9fZZ+9917oAUPyCBMJ0WAGANKFYFO7rwVwSE8vE9wIYEAEOWAHA4WZmBEf4RALU/L09mZmoSMaz9u4ugGS72yy/UCZz1v9/kSI3QyQGAApF1TY8fiYX5QKUU7PFGTL/BMr0lSkyhjEyFqEJoqwi48SvbPan5iu7yZiXJuShGlnOGbw0noy7UN6aJeGjjAShXJgl4GejfAdlvVRJmgDl9yjT0/icTAAwFJlfzOcmoWyJMkUUGe6J8gIACJTEObxyDov5OWieAHimZ+SKBIlJYqYR15hp5ejIZvrxs1P5YjErlMNN4Yh4TM/0tAyOMBeAr2+WRQElWW2ZaJHtrRzt7VnW5mj5v9nfHn5T/T3IevtV8Sbsz55BjJ5Z32zsrC+9FgD2JFqbHbO+lVUAtG0GQOXhrE/vIADyBQC03pzzHoZsXpLE4gwnC4vs7GxzAZ9rLivoN/ufgm/Kv4Y595nL7vtWO6YXP4EjSRUzZUXlpqemS0TMzAwOl89k/fcQ/+PAOWnNycMsnJ/AF/GF6FVR6JQJhIlou4U8gViQLmQKhH/V4X8YNicHGX6daxRodV8AfYU5ULhJB8hvPQBDIwMkbj96An3rWxAxCsi+vGitka9zjzJ6/uf6Hwtcim7hTEEiU+b2DI9kciWiLBmj34RswQISkAd0oAo0gS4wAixgDRyAM3AD3iAAhIBIEAOWAy5IAmlABLJBPtgACkEx2AF2g2pwANSBetAEToI2cAZcBFfADXALDIBHQAqGwUswAd6BaQiC8BAVokGqkBakD5lC1hAbWgh5Q0FQOBQDxUOJkBCSQPnQJqgYKoOqoUNQPfQjdBq6CF2D+qAH0CA0Bv0BfYQRmALTYQ3YALaA2bA7HAhHwsvgRHgVnAcXwNvhSrgWPg63whfhG/AALIVfwpMIQMgIA9FGWAgb8URCkFgkAREha5EipAKpRZqQDqQbuY1IkXHkAwaHoWGYGBbGGeOHWYzhYlZh1mJKMNWYY5hWTBfmNmYQM4H5gqVi1bGmWCesP3YJNhGbjS3EVmCPYFuwl7ED2GHsOxwOx8AZ4hxwfrgYXDJuNa4Etw/XjLuA68MN4SbxeLwq3hTvgg/Bc/BifCG+Cn8cfx7fjx/GvyeQCVoEa4IPIZYgJGwkVBAaCOcI/YQRwjRRgahPdCKGEHnEXGIpsY7YQbxJHCZOkxRJhiQXUiQpmbSBVElqIl0mPSa9IZPJOmRHchhZQF5PriSfIF8lD5I/UJQoJhRPShxFQtlOOUq5QHlAeUOlUg2obtRYqpi6nVpPvUR9Sn0vR5Mzl/OX48mtk6uRa5Xrl3slT5TXl3eXXy6fJ18hf0r+pvy4AlHBQMFTgaOwVqFG4bTCPYVJRZqilWKIYppiiWKD4jXFUSW8koGStxJPqUDpsNIlpSEaQtOledK4tE20Otpl2jAdRzek+9OT6cX0H+i99AllJWVb5SjlHOUa5bPKUgbCMGD4M1IZpYyTjLuMj/M05rnP48/bNq9pXv+8KZX5Km4qfJUilWaVAZWPqkxVb9UU1Z2qbapP1DBqJmphatlq+9Uuq43Pp893ns+dXzT/5PyH6rC6iXq4+mr1w+o96pMamhq+GhkaVRqXNMY1GZpumsma5ZrnNMe0aFoLtQRa5VrntV4wlZnuzFRmJbOLOaGtru2nLdE+pN2rPa1jqLNYZ6NOs84TXZIuWzdBt1y3U3dCT0svWC9fr1HvoT5Rn62fpL9Hv1t/ysDQINpgi0GbwaihiqG/YZ5ho+FjI6qRq9Eqo1qjO8Y4Y7ZxivE+41smsImdSZJJjclNU9jU3lRgus+0zwxr5mgmNKs1u8eisNxZWaxG1qA5wzzIfKN5m/krCz2LWIudFt0WXyztLFMt6ywfWSlZBVhttOqw+sPaxJprXWN9x4Zq42Ozzqbd5rWtqS3fdr/tfTuaXbDdFrtOu8/2DvYi+yb7MQc9h3iHvQ732HR2KLuEfdUR6+jhuM7xjOMHJ3snsdNJp9+dWc4pzg3OowsMF/AX1C0YctFx4bgccpEuZC6MX3hwodRV25XjWuv6zE3Xjed2xG3E3dg92f24+ysPSw+RR4vHlKeT5xrPC16Il69XkVevt5L3Yu9q76c+Oj6JPo0+E752vqt9L/hh/QL9dvrd89fw5/rX+08EOASsCegKpARGBFYHPgsyCRIFdQTDwQHBu4IfL9JfJFzUFgJC/EN2hTwJNQxdFfpzGC4sNKwm7Hm4VXh+eHcELWJFREPEu0iPyNLIR4uNFksWd0bJR8VF1UdNRXtFl0VLl1gsWbPkRoxajCCmPRYfGxV7JHZyqffS3UuH4+ziCuPuLjNclrPs2nK15anLz66QX8FZcSoeGx8d3xD/iRPCqeVMrvRfuXflBNeTu4f7kufGK+eN8V34ZfyRBJeEsoTRRJfEXYljSa5JFUnjAk9BteB1sl/ygeSplJCUoykzqdGpzWmEtPi000IlYYqwK10zPSe9L8M0ozBDuspp1e5VE6JA0ZFMKHNZZruYjv5M9UiMJJslg1kLs2qy3mdHZZ/KUcwR5vTkmuRuyx3J88n7fjVmNXd1Z752/ob8wTXuaw6thdauXNu5Tnddwbrh9b7rj20gbUjZ8MtGy41lG99uit7UUaBRsL5gaLPv5sZCuUJR4b0tzlsObMVsFWzt3WazrWrblyJe0fViy+KK4k8l3JLr31l9V/ndzPaE7b2l9qX7d+B2CHfc3em681iZYlle2dCu4F2t5czyovK3u1fsvlZhW3FgD2mPZI+0MqiyvUqvakfVp+qk6oEaj5rmvep7t+2d2sfb17/fbX/TAY0DxQc+HhQcvH/I91BrrUFtxWHc4azDz+ui6rq/Z39ff0TtSPGRz0eFR6XHwo911TvU1zeoN5Q2wo2SxrHjccdv/eD1Q3sTq+lQM6O5+AQ4ITnx4sf4H++eDDzZeYp9qukn/Z/2ttBailqh1tzWibakNml7THvf6YDTnR3OHS0/m/989Iz2mZqzymdLz5HOFZybOZ93fvJCxoXxi4kXhzpXdD66tOTSna6wrt7LgZevXvG5cqnbvfv8VZerZ645XTt9nX297Yb9jdYeu56WX+x+aem172296XCz/ZbjrY6+BX3n+l37L972un3ljv+dGwOLBvruLr57/17cPel93v3RB6kPXj/Mejj9aP1j7OOiJwpPKp6qP6391fjXZqm99Oyg12DPs4hnj4a4Qy//lfmvT8MFz6nPK0a0RupHrUfPjPmM3Xqx9MXwy4yX0+OFvyn+tveV0auffnf7vWdiycTwa9HrmT9K3qi+OfrW9m3nZOjk03dp76anit6rvj/2gf2h+2P0x5Hp7E/4T5WfjT93fAn88ngmbWbm3/eE8/syOll+AAAACXBIWXMAAAsTAAALEwEAmpwYAAACN2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjcyPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6Q29tcHJlc3Npb24+MTwvdGlmZjpDb21wcmVzc2lvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHRpZmY6UGhvdG9tZXRyaWNJbnRlcnByZXRhdGlvbj4yPC90aWZmOlBob3RvbWV0cmljSW50ZXJwcmV0YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgqIYvkNAAAKUElEQVRYCe1YCVQURxqu6pnuYYYZZoZLYAEjhwY5DAHRgCcx4IEa8UniruhqjLriJtHEXGvivGSfCTGJkjXxTFxvM4gYcQVPPAc0CIIcKlFRIJwDzN0zfdR2jw5vJJDI5r113z7rAX/9f31//VVf1/93NQA8aU8Y4BmAPWnYedHgXXRT8MeaFjrRQKIgvRlJKBqJ3MTQFOAOzoV6Y0eG+csK5o+HZE/fx6Xn15eN+6ImfwEEkBFCDC0PS/kqyT/86qOuR+gMXLLDvOzLAupDTym6HB0o2BzgLqiJ9mXJA2WMnKTBqPJ6ekVhtfWVAHfq+qZC8wdLxksOOPs/tj5EVpKln7pQXzo61ifiOG0hav6jtby+x7TR57Uu9NZ+0+K+Jjhai0TJa7v2uC9po7JOGif2hXsc9leLtmWCbTNRSM7yf/Q3vv0krM0nV646YFny3hRijSrVdXNfk0wOhdZ9GvPXo0KEO16fID3eF+5x2BmGIQBC3A/70Ol+lLUI1Zcsg976nvxosA/WOjFSkqn6Da/Z8RLNb0AeyzAGEAAsy5HAyX424cVadkGzjnEZHybKGRkK9f30fwhuVKt9LPeqp5ENdX6syUjgwWHVLkH+ee5pi3UPAR8o6NbfYoFVOxq0n/QCkiAzkA4thE+vv9gbdl0BOeF6ExuVf40cYCIxChciymBhxNEBeMWFD+V7acByJPBE/NJbu2V9srX+Toy1vs5NNDTitixhzCFZQnJrXl7eHwQCQRRWdo9JEAkgoGlQ9kv3R7e0ZX2yqOtkzjFEUwGYVF4qCouA5ktnv+vI3n9Vd+zwJOeZUL1ajCpSvwPtRz8HVJMBDJhSDjDhGHB3ywX0Y7Ia6arcHfjWViSds8lw8NwN+lUWsVVJ4USnpwy8zzBIlTZCFLA0yaXSjuU3j1hAO5GAtFq3pveX5djqajMAy9wQD41sISvLM5vXf1qiKzw6MiYlpdNNqRSDiPe7bsuXaNHcTYa/OgL3V+pzdi2smz4GdR1WJzr7duVlJ11PegZdnxxn0Z0qiOPHuOMqQFcn5aHiqDqk3e3mjEdlabvREQ7y4+R8HsePLd9n2hb2rs7IF2UHdrfGOkO2SIumZelOOGzzzn6zDnw9FfnuWbrRYWtbvSKvafmCcofOy45D+0ZXjxqCbs2f1tBaVSXl4kAMcjEZjj2KBZ7O4Efto5M/DOjYs20dERR8RjEt7bSzn2LqrOOykWP2UK1NLm37t39kH7v7wXTQmp8CPCathR5zHk6/wIz3gMjdAFqOTgS1qyf+cAHJcn5k5vsqBJV8UXbMPSdelBszSFh88ho9YcMpyxjeDh+kA4MYOwydyB+lv3g6RTgoZIPDr33HxjjTxdOzCF//CnzgoE10dhYLIUTCAXJ490YTG9RpYsY6wL3Jo+Vm/xlZ+mdFGEbjQpbUGaFgxihJo0W7f5itqVEqioqt682PGBiqhiLxnyw/3Rijz9vsCXTZL9vz1jWsticeeoytR8XjTgHzmRdB54mpRnJOjYnyx8w22l2FEKaCsPuwB3lBjeYmGtncxSq65+GKIiuwHyCgO3XkOZaiABdb2LYt62XLlUvTzddKbbiHxxEywGVl4GtZ3aQKn/IUXLsAqfFVDXRsbgkZPCPW5Vb3pA86JSUI/0qjX+jrJhgrxsGAxi4Q5uslNC0eTsUbc8u8EXeeWF2HvKcfr2MQK8MkrmbKTEtoa5MfMNUE8oUc6MsDesMDTMrn+IuAbHoal1BdYgKZ7rQzQVFl9AjOXuTwwQVQ4OUG6eGDJZfsNp4e7hcT4nbVcL5QilxwYDxzfCnxdHiuS1xCpvf8jF5vkdjIQQI1tzHQqmddT1RSbziCOMuYGEDv/ItcVbfea/y8sZKVVgoBpStWNSHGvQJAAcNyT8DWqR2KqqoIZz++31xyppPbsxFxPCEo7gCYxAJoboBqi+yJtevm2212CZXNafHhHWlxLt+26ZHgn2cta89XICU/dqwceVfU0ynz4sVvT4+ELbyNq4l8wQGs1carQDp6XBdjNgIgEXf5rf78w74I4LHYwkTJxeQo/ADFILC3yLL4cJl1Oj/g3Pi8cejuUkiw3KuIphn7dwcRGVWEiV0Qead2sLbmSrQD55DSiGdxhiTlLsGhJR4z32kAkthC+0nQnpuAUMn9x+YA81LiL7GT5DvrX7y6PA1796U44ZfFt+igZWr94fi/63a+m60780IEkbnmJck6HsO3+x9B3DJpyq67jp+iAQQOzLXVCboTR6bYjX38wXj7x6nypc8F42U6E4tnbNfve2OXbnYfeCAAiOQvJJBl7L6KtFevuI1KzKbaW6Hlasmqnn6u3gOnUCaTyCv9ldX2sRDVt0Di0wJ098LB3aK5PfGA1L4IFENqQMg4+3dJAISWfUvd3kyOU4ZG+AtU1xupdAvFen2U6rrV2ZeAGAUYGsiFhP0oEMlTLinjEw/RBh1s3vDJ1qYt64c74/l+886drrzs/oo8V4u8VNmdGy7ftqVZOTIThxLHvGRwk78nVrn/jNU4MwEXKaWEV00Dmb5XY3kteqCwpHSNj31i1NDgUbdm5T5jafEL4siYrUTgoExcrtQLFB7jWrN3feGR9ufPfNMXdldp1KQeCyqW7QW0zg/4Tn8FgAF5QCSUA8PN5cB0YyyIOTgNKqJu8wt0bmoNcn8np+Nmq47xiPLHD3yWqlg0Ogp2qus14i+LcvOK75Y+H+IdXBOmDHh7Ueyk03FaWmbM/DjHUHU1QaBQAiIwaLckevg5a2OjkrWQIr+5S7dK4+Kau0lwBPvksCGxoMI2+2Yz/TxX7+TcUzcKITDIXTGSu6CQXm7YbQkOzr/wjItmxURZlcMPqdWChuvFs03VlemYWIKAANdiMlmTZEjEfr8lK0ocOIdEjd8FgJ8PLuA2ngRwj5+BQGgCuOIqkEzcBsMzuGS+31SFSCg2mlMu36GSjCSAHAGDm3VsXIuOlSYMJq5sTldMVbfvwrdfOz1HjLuwNpoi3EVSQ5i7/5ZdyStNSKMWN165Nc+gOTuTMZsDuYTR434BBV4TJm32mDmngY/yCxIexAYqFcKqfDtl5yutRNIQVzbIm7Sq0ry7F+fA9SZ5QkB1NYIqFV+ufrOhks04jF18P5md0AcuW8NXZRu2y8QYNSIEX+/jJijW2sTtQ31sod+eNm4tvmGLSx0hzT34hizVye3/p1t2BymeXdX+U8ibbS3c28Ceu867yy1Diqj32iuUi5rNsz7t/fXsjP+1vr24/RrgcY1l7GiL4u4uwb5yeDl5GDT1XMeMaNgVHyr8nktXzEtG378m9gQ9ov4/S0KUv4jEuDdzYycTfazc4N3bfu61Mc9NfkZ06JuMR0vT3ubgbX3WhL4c/lt27gkT6Rt1O3afN708PISoHRZIrFZKQImFtJkQxH1aDOyCNj0Tued1z1R/N6j9Pevq939hfk+w/vhyFzRbCUJzuUuc5tJP1gV5peYs/hbMvam6fJWo1VsuKMhI9VzBEXD/itifyZ9gnzDQKwP/BlaTi1SzVazVAAAAAElFTkSuQmCC
+data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAYAAABGkOCVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjMwQjQ3MEVGRjQxMTExRTM5RkNCRjhFNDM0QjY3OEQ1IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjMwQjQ3MEYwRjQxMTExRTM5RkNCRjhFNDM0QjY3OEQ1Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MzBCNDcwRURGNDExMTFFMzlGQ0JGOEU0MzRCNjc4RDUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzBCNDcwRUVGNDExMTFFMzlGQ0JGOEU0MzRCNjc4RDUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5U94CwAAArpElEQVR42ux9B5hU5dn2c9r02Z3ZXmCX3QV2KS69KE1AsQAGEBT1tyQawUSN0fgbjfrFWGIs0ZjYjaKiWBABERSRDtKR3naXXZbtO7PTy6n/87xnlqLEL1++/Pn/fNee6zrOMDtz5pz3uZ/7ue/nfc/IGYYBXVvXxncNQdfWBYSurQsIXVsXELq2LiB0bV1A6Np+cBNDcdM+SgJAR9QADqGx7pAKNW06DC0RoCSbh+V7VZB48FS36hftqlMvjSvGyOag3q+uSTePIhjgtHGQ6eIiPXOFg7oONX0L+S0Axma7xG2f2NcCJ/06aGhV6bnTCqDq5zodDgwnD2m7NoJweBckOzrAMewC0FUV/O+/DqrfB2mX/Ag4qw04yQK8ywVKaxPYe/cFW59K4Gx24EQRDN0AXsTdQlBPA2h+HyCyDyBvNkBoG0CiESDZAJA9DSBeB1D7NIAWA+h+O4Cu4PU4gQ2E3AaQPhwgYwwex4av6XjeEkRVJ/CcARpegz9iAI4JSCLAjuMaDCwSQcfrfH5lAnbVarDyPguM6clDUP6+Taf3eSwO4DgO7tkx/95DwcYcj8WZJEvPcwKEEyFLWFNyHh0064ECh7cxpibPMWZ4XFc66HhuaS88D9xXy8E6eiKI+YXsr87ho8EaDkB11TH4Ei9RpO/VVPa3IUOGsH3VqlXs9XOcIIDdwkFRJg/HWvSRaw4qP91ao/6k2Y8BdwCk2TmoyBe+vaSf1Izv5SIJw3a4SevVFtYLVu+Qh2PEh687zM3OdnOQ4eQOxmTjQwTI630KhCYHHlfT/+f3LugKNQ2g0MsxgNMrRupZ52YTJAgosaxrNvxl6Zd7Pz0f0vIxUpglmEmgyJgtCXj+wrteGZ1b7v9b3xOnPAwEQKw5Bm1NzRC228H6jzDCWSePZ8rjmWa5OAjEjYwXvko+//F2+fr2Jg0Kuglw83jrHy/uL763/rC6q7I7D9eOtGLMAfadVGHZbgXcdq7weJs2CZnlxs92Jce1BnRENdf35ZXxRzLT+F/PGGJ5ISdNeBUBdjx+jgzBJAMNmcnAAcK0/rcGAjIo2x/8WIWHrhChT4EJgaBisHGmf1kEEY6Fm+2V3u4fz7riyWf+fOirx/a1Hu4jWd2QTETg+gHTX/5F30t/VhNuBVlX8TPmMShGcQIWHqjsZDsYJ2tBsdpBRxBw/2CDUDwTwchQkJvGQ1tYnfjkssQH9a1almjl4NqLbR8O7SHchVndnO7gADMcWkMGnPDpDAgNHTrIqgGKCg3ndRPfumGU9a35FeL0Z7+Iv3iiWcvPRWbxhw376+9G7nPYOedz17rvONmhwVnnjM9VOw8iJoIYxosTLf/e4gvH0oOMuGCNBku2a3DDaAFuu1iASkwoutggJTxmfrbNXX9Tz/HP9XBkwsLabXP2yPE+uuQCzuGF+kjbnstXPQ0RNX4KBJ3CrppX4FeJTBgQy4FYYTaiygrw3+gS852lQMRnBV4e3vtGnn3ne7FVqAGy7A4e5o633n/vZbbZhsE1U53v1BQcd2ZlN49BNbM1pEO9X4MxFdKnv53uqOhXLHwVQu2hRHWYNNmxaOYw232+6HeyHf+pOQTgFRyYhiMgxsNgSLZ/+9JADF+Yz4GEyfTKMhWGPyTDzW/IsB8ZNt2ig4CDqOCbmmIdUBdth7gm20mbGKkyEpYT6Tr+/SwQUOKpURjqyofb7L1BllBXUTD+m1MFPCHXirxgETlYvke5/KbXowuSmN0U2F9eYn385xOtT9a148kizZOg/KEMkFGDEFvQKZGIGtVLCv16quOBeLsGU8+3fXrfFMeVqA9ixB5ngki1IgoDIUj/Yj5IMT/ojvR/+9LQuVFyOJDcCos4sCG23/xchfPuVeG1rX6I8MfgJF6viMGnYLNYGibl0yOJSAnLh8Sf3nlRQuZV4TY5E6iEREH7pzEYE4Yo9gpmvRhdZkNAxFGcYj3f9viV9gdRFMLIngLkpfMQjhtnMcGZm4zngxoBsHyAgHF12whcKNYTxuDLx9nX3HO5fUZrWIdI0jC/NAUC2eDBgo4j58Re4BqrQXN5/seA4CzSw0uyo/QpKOZAxISa85wTXl7HgcsVZcwAcBoAZz6eudO7ahIBmOkqgYu5XGSQKPDA/XOAsLNOIxDA/R/HFsbiOudBoUgBvGakdCOVgm9PaBDHetYfxaEvBkwLnAsMZD0H9xBgbIUAQQQMAYPKRFmusHTuBNsEH4Ig+j0QIOJRIebjAFlxV20uc8T+B2/EEDkeHAek9N+/kw+NzW5wO2RWS04BADqBoJ+1x1UZHMgKc0pGYy2XQE3ZwH8KEIjK0RlMXfqtcn5hFg/NPg1mDLOsKMkWDu+p1+AkCsG9+EgBnDJAZPRFiv97YODM4KJghE7DRDHFstNM35FQ4GwQ6DwDQaEthhmB/wbhn4Ttfw8wuBw6MjEPIX+22bPgzgAA1WViRQNO7ZT5dVEfXFk4CFm3L8TjflY6/mkNpTG9RWp+/E5XTQGITA2XV4p/Lc/jmY3s/C4j1VvIcPLwIYYtnDBYCdC0039P4jEUzQw4XQt9li6a9s7nxDa56QK0hTTI4OJ4DOMUOL7vJ3kQvJnAE6J4nn0J70oD3u5gKKPm0T8skjiioQI8qcTpb5cyzYaSGa5UFP5OcWiYp0iui8drous0/tZ1pV5PGklIxryCFvNqYFdSQTdSj2d/MqEpkC7a4WZiA10zezG8Oci8yw28O5012tgY2ewgpHvAkGWz8cbAp0MwFAHRMESB51RTIKJLE03jKC77Vum387g6MBOtTgDpvXe+oAwoEteRPYx9x+uTY/A4ObhupAWBYApDCdMZdQCWBp3RO9XBNLSBZCupHNB10TmTIEWWAQHfP39THC4qU0GgcZe5033uVFB5pwsETwaovtZ+kbUrp2rRyAV6MNBTj8fkxP5dR8Fi2WcpKt0sObt/LXi8KQT/Z0FLhUXKwFFBEZSoHw6N8yZDonEEqB09EBAx8H99EN+2H9wDN4AlaxN776nP/u3sdqIryPNwsK9eK/xou3xdc1Abd6BB75aQjaTLygWN1NnRaSYVsGHy88Gg7qooEY7luPifxCKusMPh+wFrx0EtssEtCILi9FzQmxsxR/BVbwZzXHLVkYuSJ45PV+prz8fg25PHj1Ur/ra9YlbOVhzwpbo303BYrTCwshQBKqZHQsHbrVarnkgkYh0dHS9gSbpVXLhDnk7Zne3mkb4NcFu5qm3VajtRuaob5+w64ntYoKMIBLKdPTDAD1xhh5GlEtRiablnQQR+NNAClw20QiBmMkccj7dqfxI+2pSAmkYZjj/rNvvanWBDKuQkCcTsXEgePTQxtGLxb5O1VaM5ohebPYYXFRK9mXmRdV8N0FV5llRYhIBxH7VXDn7K0XfgXwXMCE1OnjsDDc1sG1sLAdoWzYTmDx6FaFUF8Oi9BXcI7GUJ0BPlcPKTQQyVgU14blk7wTvmUcgYtwQEl8kU3PdZoBjL6dFWrdvjSxOPf31QvYE6p8WZ3MGBRYLjWLPe41izBjnIEiQQCTT5CJgjjRqUFIrw8BXO+5x2I6wKSPN6ikZPsYJ+SiTGNBkyJKfJBhQDzHg+zQNKfd2M4Cfzn5MbTxQRKwiZOS3W0l5piarDFUpzw2Qao9j+3XWuCy99IKe05/uTh48BRbL4jh48eKL2+PGYqqqTamtrH0ZWGC7KijFCxWDoqZKUZufqD6F49EVOC7vvbjRPQHU9wynBxH4ipKHqF1JpTY+fbknAp2vjMGu8HWYOt8LBBhUW4msHamUSA5CVJ4LDevbBOStaaKcbAgveejm48N25WiIOaVNmPm0bNOJP8f27Gox4DNyXThPcbS3TOz586+nEsUM9OLu9d/zYwTdUv29KwUNPXSl5MnQtHgFOILpTzQYF4z0PpaMFqu7+EGrfmQZkg7vfeh+4Kv8K/tU+DDpA3tVOCO28Go4/9zzEmnBUW4ZAYP9i0OKvwnlvzGVA0oJ4GNMVUcy8yI7fVKlj7pgXW3G8XnP+crrtpW4Zwp0IGK1fIYeW28h7b7P8/NcHlauzU4x7cT/py0evdPzYH9H9Hpsl6dfaINMRQrbPPIMVjbPY4ETUD7eUjobuWYXsT2JaOgRWr3gVQXAredLsB37/UyOZfCu0aplmHzgM3BdPHR1a8emL0d1bK7VIqDi685v3YO6vimyjJj6pYrmQFaWhpaVFGjJkyKcItGFer3e5iLRexGFUSagQIzgtoA4vwRoeNn7Qc7Yg4XXP4MHr4FjJoHen283WR/ccAerbNfh4fRw+2RZng0Zv8GYI7L2iYGCSS1SUkQVMkSFkZENsw6qvY1s3TpBKekL6ZdPGSj16biA+1WNRICDgxWr2vpULYfaPv/C9/fL2ZF1NhZiTD/4lC6ZpkfCmoqdfO59HQGEpQWBZzaJNmyXbDkde3gUdjRXg7R6FgpsHgL20GtQQBjdi6gUDvVjGhDfxTFZB9RO7IOnLBGsawLF5c0BPZsKAd2eh1EdiUBm7ZaN+2l2nlU37U2R9a4MGt02zf/bYTPvPX12ThHq/ybBYXpvnz3HOfnJ5Qnj+0/jMnFwe5q9PXnJhH2n6LeNsL0XjAA2KAnUR1EtiqgSd0gjmrqB4c0l2mJJ/nokTOQHtTz28IPjJe7Ol4lLFe/MdfZznj60Ofr6ITcBJrS1grxy6sejF9wfWzpl1JH5oXy/SWS1vvvB71/DR6+2DR24uKOu5WrRY+DS7XZYslmWoFTi+MaB7nLbTQESEGASIuGwC47t7EndqLnXL4GBwicgsoXGO8iGJHGRmCuCy8agreMhwm0GhUpKQeWhvCuCTNtDCQSZqQosXzIvt2joB6z94rr3lF94bbmMgUPHiWEAJEEj9qBXAUTk0kn/fY+PF7BxVC/jBhsAJrPh0ZOOzj7yi+tohcRhLfbQBLyaMgY4C1D62EkIIAupa9/rDDCi+uxq/GEe5DY8rmNpBpX/jORXceAIq354EaNOw1qC8RyaoWjATjj54NyjNIAePQjseMoQa6aFF8Y9a23XI6S5An0LhuYMIiHwPuiEEOiVKeb7AxuHhK+yzyksEfxB1lAMTZ+68yIsr9sj9a9sNaGyzgUUQTkuRU7sJig5dhkH2LBjajufS0gqhpR/fHFzy4Wya7sz65YP3pF1xVTWdv+BwgmPAMFZaE4f2gNxYb3imXXNLp3jUQkFo+OMjS9WGExLUH1dVRZHN7icrQQZ/5neT2GsNG2kHGnWoxQukqejv7lWtOs1IQv/uIptUUf6TxhbVxjNLDAmrQMgKL32GQdi5BpRjByH4ybsTAgvevJHcgLW8X7u1T/8X5JO1IOXkgZRbAFpHu2mrknGsjWko7rPBMXhks2fKrN+qbc3MbkndiqBj2cdzgqtXDDCwKhhtawEiWwFqHvwpNHw+mpUDb+UBcPRZCZH9AI7eiNYcBGNTCr0YWSvN/qEeyJ68C/JnzYN4wrR21O0+/udnoe2LbEU10D0BrNirnL/+iDo43cuTU9AK0vmjLSiwqYs4ulzCBOCgFzJAI3VkEVM3jrE+loyaYltFVnxtbeIXrUH8+qSAQlqA0+l0dmmI4MWcJ3nZ82TtUXvgo3l/QakPyJZJQ1Xnxb/dDvF9u4HDEuEYPAJdlpe5iGT1YUgeO9wNUHcprc14qQXotlwnW15+xiG/9CSkbVkDKrkMTDLSIWKGgwvWtOHFiYQOg2ivfGSZSI5Nl88R5DgyQhZezHndBNYl/K9aWcY8ahIayboVo82SLeB/59VndQWFHmfFgBZv1WMx0OpqWNOE0Gwt6Y2DUAW2nhWmSPK34esO8Eye+WzwyyUPyCfrHDy6DBnVdHT3tvvTRk+azdHoczjKzR/+nglA+l5739WQbMHRP26uLxCR+p29zfKQPswsEfFaBAgOfPHtj0DToptAxfRHaoYIPob3/MJTMu3B5z8PwuqjtsnWlEXkzeviSFyjK8Dk0LFMIhFh4tCag7aQTusU3ikpEp9uDeoCkRAK9GH5GQYE4g6QcQw4R0qk6WdiwQBNkaF3TzzHioGQWPbxTHQENgETRswrPKYFO8KUMDThJGbmoIV0I57jkKw5ekPHh/Pujx87VCHlF/pc5497X8rvtgDF4zeJmmPAB1AWYYmRz0xYtD1tykFqiAvM4jV2aDn42KdHlnCAAv3djcpDgYcEE4cX8H0g0JxFyvL/7U1VQESVDw4vJHZt6o8nN5B8sNLeCnxGVr21z3mgZmWbIhKFn7eiP4TWfgnRvbtRS2Syz9MXS9m5CWtZ+eJ41ZFrOU1Dce+G2OEDlyvt7Tap1JuA0JJLINqUyagrTj6vogEyxuNFlKW6NBgtzyiA5oUA/o04GuhkiE4oUlJWLaRVfgNt28+nhTcs2v4tP4JuHQ+e39ML66q4nlQWvVj2WkK6UOfTupdk8SdVjVlEZAOBLcSJolOl17LcnK80W9hR26qN4KiNLxvub+s0TCYVSsrIfXGniSBVFmhCKsfugl4hPOCJkxDfve0yAzWKJsjEIHH78FGg4pgZqKGSNccGJDat+Vl4zYpbDV0DqaBbc/qUK++ylvR6U3ClhQ0NP9fhY00oAxNMF6WzmRup7BCO9QQ6CxvSWmuHDhuPKpPQ8hxowudnBlpLzaP372Y2mgT+bF0AqfKSSBhzqM/RqXvou8/oEWGB1XIFgdsMGd2/wlo2Wm1vARJ9BgonpD2dAsqCnbKVvCsdnCPGQGTLeqYRINWb14gtispWoO28ljWY0HWowQ533UN39it54rGd9pyTFwIdhthBl83cpWVLZAc7pz0tWA4yJmKQ16Xew6VA4kDg9FkOLQgE6rYRmIKH+8DOq739en3RkeHpZknIEXSfqAeQ/jGOg/oVCt/QlLwk8CwZQjFgToEaTE4rj7aS34eDOIJwhuDw8XgdGW6znKjad8QiU9AiiFYHRD98G2R/EmLh9nI+OwchEAe1w5+mNNTb4nt3TI2sXfk4Zn8v3uEAx9ALPkDx+IytZ5+dkW3rkZ4UUP3tzJqfEs/nKuEjyqRv3tuY/Dl5XFbLMdpbqtUbfzHJ/hz9mzRAJxhU/BvVPpvEsfdapdMoseDF+aNGxf96MbS5za9709I5SOJBaZ6CuQnenDTx+zS4aJILnr3eMiL67RaIfrutJ9pAIBTThagtjbnhr5eD0tJ4qoVqYLZzrESUAYdINlLtTMHpAnv/gbtEdBwqik7qrMk+H2ReNSfXmotisX5NCdMG1K6lx8iBbGiaj0itO93zMwh8yDLuganGVKoeWlE/eEftAPEdHBM1JShlAXpe1WNVTU5HVaNW5Xac7ryuPKBc+6PBlpdoTMga76pVmeC+uB8t09Og0EPCmUsYrNNqQFkuv4Ha8TKfwGtC2jCc3+9/0YwkBi9WcwTCB4+DWpCbzrqq1HKIhIqaf/erOJVJKTvveOb1c++w9aucJzjdER1dEy3rI4EouLH88SlBTL0JWvmEu4GvGaQRElH2NxFR+kVhJme0h3WOlqClYwA3H5IHfLIjOWxkmbTdH2VoZ0AlBqBu4uHGBGsm0YoiPTWkNPO4pUrJPdyovD9hoKWa+hJYRrQMF9d3W40yh6ao40ilWR4++tTcjOL0tkZfyzuvoYMLOUgLsIkVVM9KS1MpIVdEy9MZcDpxAdWw0tbCLBJvMdcqcOgwjGSiFh8DeACPkerTi1n5WLAPYiGudpoFPNVPSNaXMG1AfYNTVJY0G02xYxiVVpMxWIrgAMZPHMOsNJARTN6m4Ig5MKV/GJqjnk9+9wncS0CnfsL6Q+qo5qA+ZFQvcWcdWmdihk92yMxiEzCSmERYPvoAjmdGgQD3XGr/Y798EapCHLQkTU3xXcdwqi3LWsbpxJYKCkTGFHLTSbu9csiqjOvn3se703ZxGFjalaZ6zH4rS5zOjiuH48pxZmeVtJSWSICQiIGOpcLIQ62GukIcUy75LqywLHzvq/gsPqUTghEdFu9IvnTbBPswqoPk/TNcPGsi7a5V4Dg6hz0nVFYfyRWwjqSdJyu5bkAPaZ0V39jQocF1o2zQK08on/GnjjmcwYGi6lDaw9KwfIfh2x8Mw/U33QRt6zY1x99CIZyVy05c9bf1tVWc5xG9GQESPqxvgRdloHWsu/9ngGKJtZ/ZiCHaBIcrBpLFjwj30KCJqJpb33mxyV12J9hLZ7TALsxou2FOHSR9QyBz0mmXwOYXUBhGEQSH70PAhcwOZGfZENIi6CJUSAbMgiraNdjzQL1QxMPtl9y6dftRy9eL1iQmFpeK0B7U4K75sQ/WPeDuVU8rt/DjnlSPBZkCGkJGxZJNiYmUPX+42nndkBKpocmHY4cW16Dv4s4IfmezFROBlxXIu2wGpKGFDK5Z1hjbtrFCyMhiotBa0X+jY8SYXfE9O/BcUZgG4tRrwdP2MDCQtRaQZYkFdNGCjiILda8T80oBAUsvt3g+iGg5tf6DgacO4vSh1t8KLnPOgJLHmy3Ayh3y0N8tid1Mdo86wVuqZHhxVZQ5BWqZ0nS0TTJrWz7SXn46z0pFDI9R06bB6N4WuH60jQaiOCmDiUgqNarBq3ilDslgPQJNU/eD1cpKA+d0EtKtKHjGxg/sgdiuLbhvZdogceQgSHndQEDAUBcSrRAqbXOnImwgKNRQADMnI1zyzMsHbUUY4I6O/WbJp8YGlYYjxdD8UV8IbsEatcbc2z9HNjhi2klLtgkEYgMx3bSSnatOCTfOskNwwbp2V94ooL88c419Vv8KsaWuXoVsZNLtNUrPKc9FNoSTRmlpDg+0rI96CSv2yCMufDiwncrnnCudP+nXTXgfyzyCAPWsFgCJO/eyPAHPO6AloLZ3GfCjxoOlW4+dWixiZjmW09DXn9+PSeJwXzwFHMNHUyMJpKJSrHw1iOkOcF94KfA5hRCuqoLoiRNgMHGimKVBsrD1jfrW9WAsmg88IXfyQMvBuRfZ34q2Yog4c/6AHNN/fBB+Y1+D1j/LzUN1swbUMKESQGxFWoFsEW+2paEW6yBNNjWgcLqs0gK3jLexGcpI3GBLv80MZv/l7JzK+bg0iEbxeD17fiVm5ypU40lJEtIjWzdeS5NvWjSKzi7MZhkj6JdpLsFaWg6WohImLi2FxSBm5wkoMt30WaXDD47zBi23l5Yl0ayjOLlgCQOAlvJ4FMy2z65h4o/6B8lmYPbQt8F0EK5+WONwd5TgY39kkm4iaHHRXEaFe+b4xeDow8RgCO0AuoSOj253Dbigv/glNdooEVbvk0fPnRetnr9J/qrBr7/89PL4qinPhrZU1SmuBfemjZxYLr21v15nZdantqIzUPDU+NPC4HRnD0RkyJASgyYlwqZ57cMvWMy50lhjDcsBJI4dsvo+mvcHEtcSUTyWAA0DHT1eBZG9u8A1CgkI3ZiKdpwB4MwFP/Q9aDsNmrVEcIndsIaR+HtkhvOnS3cmL6pvULtnI4q9bg6oa3bJ4/7NO5/IHDGsp3RoX4PKKO+US8ABKsTPtwQ0eOK9IIweaIOfT7TDJAQCCSKiRV4wmcAwuFNFUMKT8gte0MovgPTuOWHXgf2vtb767M8ZpWEZiB/YfRUG+WfOwSP9nVOp4T07mQBynz8OvJdcgWIpTDWT7FOPjlWf56hooXi3BzzjJv5ebqgDyZkPQrcRVdDyxWqoWzcB0lJiJrDzNug/6iHIGGdaRQ0B045AUPwAOVcAdLvWBAmVjI5N5XD8I56dtpNW9k59AaJHSWuAZKUmTx5Vs5aHp9sv3V6tjdtcpVy6uUorP1GvuZFpL8JgX7TrmMIG/e1702fPGGTdunhnEnpkStCIgx/U/GDhrKkFKdyp3kEnGEg32fH1emQOEnzp5w3d7CvvdziyfVOFtXsJ003t775yu3PwiA+tpb03dixfxDqLkgf1FY4xlQZATcHTVPMPOAYCBE8TSCHM3EwXr6263zsuM4OPtTWZK4yzswRoatHcYx717/h6vzy+L4ocWpPQaRVZomC2EZAUFEfHmhUYVyHBhsMyVLVokOFEkYIXYgLRSNVBYAtSgsgGTQIqc7RH2T++8yGpsEhNNjegmPFCouYo1/LSH17tXCUbWLmUpqSZVlDamiGBOkFPJsDarRhCm9ZcK6PDSJxohpzrbnndO/GyPdR74JzdMEM8AOXPzmVrtYkNaMF/e0Mm1PzuMVYCqK3c8L7pHNiKm+MoMA+ZfQQrapamBTeyrgsJ61733geZ49qYuBQ9YLdqpxpsvrABBV5uXWmOcD8K6xlP3OC8+MIK8fM4iUBMKCeW3b75wloqvRU4hn0LeQjEdJYs3FlTmmfoBGQ4fyKsERN8G26E+kADXpMHsm+47TYKKjElMQGVxJO/u2dVYNnCYYLLhTo4l5XZ7zV4MAjkspgO6/BxWjgEZ+5853o6cgG984Tjy3/tHVpWKNS3YfYnSA8gO1Q3qo5fzgut3nhEeYxcI14wW4dwVg8BSwXNK5A7QJcAm47I4EJ9gWWjjfQBQ71+elUGDcKRVoONspiT29H98RdnkNBB14B1rgT8H82bGfxyyfWxg6gVcBfTzTYr2ad41SHGBnJrU7fmd159INEYgowrrtjR/d7/uJXYQ8KsoEc2n5A+5BgMevoOdicI9RRInR/642+gfcUY8K3FwO9DZKabwadp6cB2vEJ0FcGtI6Bm6Q1ANxdVTFkMfZ58ip04lQ1Pb9hd74Qv96GORKCQK3Dj9VNSPDvbAfdPtUMwplcqGHgS3zKC5e73wn/5cp8M39apeN0KZFvTwCtmYMVJgh1dU44jnW54SYCmmEI16ofppSMik/L7w4lIK2xx43EkHtIunro2Z849f06crGWlk0S24mu3tn/w121YKuYKaekocTx4KVbEawabg6AxE1EoRvbtnqxHo5PTL7iQd/SthDN34de/+Q8GHmIOQnZumtCe4+VfjelG2aE6pX8U7U46ikFqRO04Ko9de1T+CYLGjUBoQiHp65UrsSbSJ6tjkFcgwl2XuuFYiwroeKEtrDuX7Y5PPdKoXU5OUMUssNi4tIoC6VEanONtOlR4dfCg0LIW9z5qLS47Htq0errqa0Mh4YToto3T9Xi81VHRfwf1D8g+2orLwDVoGMQPHxhWffsNO6L7ahzZ1129pvy1D8fxksUg78yaSzw1w6iwY4C9Y7aBVU1C04aLINUSgPZlN4GuHIL0QQdAsJm3vqVVIg1OAGheMgW+uWY1Y4K+MxfA8E+vMvsIQaIz1EY2+GS3lTEggb05qEJxtgjRhMbmEkgkNgUM9+Yj8ngH6icLfuZwnda3MaSPH1QifTG8VIqAjoljtcCJWCNa0QBUBZpg6fFtD/ij/ix2t1MiDOU5PXMdgrSlJtDAXVY8xI7aP+ayOsFb1HOFEgkVRnZvHUJ6gfooGpbG2P5vp8hNDbPlxpO5CAgrWnBb8mRtz+CW9VdGdm59U4/HxmdOnjEvbfjoZgsmiw0ZtXPniKI6J4eiiOBmFHtbq9GyYPCrmpWpn+xI/HpntXJBIo7CEDNep1YtBjU3T4Asl7BnUA9xH9rHqqWb43JmlsBfPdKeeaxZLTjSpFTGkkafxhpMmTSB3eyBNbP58oG2pbdOcM4NxgyjPcbBeTkaDC7FZPWFWPMjuHrFsPYFbzyTOHpoLDVLyDe7ho+plXLyFyANVuF7ipWAf7Lvs0VDpPxCSB930YN519/6uGvQcHQNQbZyhzUGLQgEpk8kc1aR+gf1r1wCJxY8BaEDlZByj5BTvhfsBQtxJBswbXpBsn0WnNxRBm5vAvLG/gLKH3kN0gZgOvoYpgzODhurrMxF2fDfReiw6v0qjC23ADImSygky8wNR5QKHMflJ3x6GjkvYsV2LJ+ZaSgw7/JMm9BHWu9Dm7625Rs47D+Z/+yuxSs7Ao39weY2RR01gWIdDLWZabkwrfeYOVar7bU+3iK4Xc2FJB6vY+v629s/eOsxubE+nS1Tw5KoUBKx+0JJVMrsvlEeHUbGxVMX51xz0wwU3oaE7KorytnrQb4LBHICX+2XmQIeiv44hH//cm9y7Em/dtXuOvXCcNzo1x42b2gl4WgoZk3zZAgQjRmYtSpwKCBzMPgJ2Tg+tsKyoXsmv1PRYUs8aey6bIBNvXaUA9BiYUnhWAs0XVJACQZR3PjYhfBIZ5HtmyeFt26crgb8Y9RgoB/1yonyk40NtB7voOO8wa+7Bg55W3B7OyjBvRdPZrqhs9SeBoLFvJk1fsIUhBZUjU3LZ0D7qitAbh4JSricaQRbEQ5ADfra0u3gGfo6ZIyYj3YlAXZ8PRdFpIrnZqBGMRzsFr9NR5OQ4xahX6EAG47KpTWt+rQtVcpMtM4jLQLHNQbMlUnUXQzheLndZsexpZ1uWDFg0T0Z06YNtSzZ7TsK7x1e03/h0W03Z9lc1RxT12abjqaIk2rCk+3w+rq7sl4/Hm3XJnQfCI8YPSAaRpBkZOI1J9OD61ZeE9mzY6oWifQxeD6D6jAGWjc0rdHarWhl1pSZr9nLyo+QpSS2tPcoo8/97XsfT6EjVf5p3UEAS0NZnrh+eJll/XlFKhxtUnugsOzhj+jd1x2SM074NUtldymMpSA+vEwKW7FkvL853n735a4TK/Ykk5MHWcGFsdhUpUB7SAXqVFIDio6r6Dy46botqS/FLNCCAYZkW2mvlZjhKy2ojm3FJbbo3l0WS7ciIVFb00Gi0dG3P1rKHRhDDWuhF354GpQzNUCi2Zzs8A5bBJp/EbiwFDh6OKBjuwhpAzno2BBkC1qdPVEjfAtsTYLNvKtY1u0Q0xyslW4VDSjOFOFQozZ20Y7EfZ/tki9XMfDde0hav0Jxoaob21+/2b1//uZEnawaBrLmPb95N3xzGIV2Hq0UR5s+60/+xV8/kFXZr6D3vkh8435R0n6Z68LAstXL+imLl8DvLHJngVO0gdviAAeVDZVjglBtbsSykBlMH3vRK2gfX5Gy85D8/GmotQxk0GT08D6ZGkqkG+SWJjaHwNts//lNsOdaaUsb3diSkDW2CAXHu7ZXnlB7os1sNJFAIqRT57EMRWS6HV/k4kxNK5pBs5lsFRP57L9vdTHHUMvULNofPSePuooJtEMJtmQaBwdVLyitLf/1FcwEArKMRPOy3+wuarT0SYFTO/UWaBaycx5Cj5rGAQNC40FNNDeWyM92x597Z0PiLqNNg7yeUuOTP/XcGpfh87isE0AAg49ikod2pP8HpjpvcUrcuscXR95ubtO43BwRWk4q8PN3Am8vuSNr8I/LJ6MmaoWdLTXgMLJS7WATCEkUj+x+BgQA9/371FhmI2uyeQXWllfkEHUSyT7qbFVXnD3StP0PJcvf/UMZnQ06KgfUH6A5Bz1197Q59Wr2DWg1s2F2f0/d9fsPbylQsDmH1COzRv+ULTXBxFaxdD52zpzQ96LNcGCeZA5lg0RzAR67eb1//ir28tufRe8y0B4OGGo5+tS1rrL+heLnVDKbgjorB/ScmI/GiRawThtqffeJ2e5BqJUCLagp7Fg+T7RrgzbWxPrbFNQAtl9DiTQINFsj/EML9GmehY2Pbu6ppPl7IyBC13aOQUVQOBVoMqZCdVMF2AyV1XW67W/1IXn8nz6LzhW8AuvAPjPbPeei/pYEzS+QhfRFOqeUTVtNCUILVqobETRF4p7fzHBd/JsPw9vNtZ9oK+eHBmNq7XfwLsTdT4HrrUEuyhQuUQDGv/CWny4gfG+9PkbX2QFtbb3gzZYhIMYSqAs0llkEhNdXx++mqXpagNs9U2iv82lr/7o2zsjreCvaRxeHpZR0BMem3+MyD+X5ItA9JfTanPGOHftOKJ+882X0SkuWQAzLVuxHtBC7V8S1bw6+TwJL7hZI4/IAtC4g/L+5l93jg7rAWBjxxz7QogUhy5FItcdP3dAy0JMpsCl1rBnGvnoVS6LOFp7QApMIPq8o4LEcqFDVJMMNYxzw3IoIYwti6nQHT02mzYirK2n946Oz3LuL8Hikw+ineUBBEHBzYHFYhX2RbZBDHc4uIPwrNwy2iDY2EYH7V18OLWEFsrPQwRj8qcWkosDRrCubaSNGaGhSsyffmDZ8fB/LNgp8C+qDl76KQLZbYrf0VbWorIO64tsE3HGJC/oWipDrEWD14WRvaFagT19n1Yyhtr0krOXO+1m5JHgEKxQEb4RHD9WDLxGEPIe3Cwj/2k2BQGQ4XDtRhDsn0eBknSXcqC/w8MLwN+8sixRlFUnQjpbxtx+H/zL4V97hpBeqMfDUPDJXhHPsOekEclThuPn7EvtOKp4lm+P/C7BM/PJS1x09skW20vn0Sm9a66jD+AIXHIhPgid2vw7lnqL/61fe9fN6p7QBZr/YD9SCq2BiL4AhxQJUYrAHnLEXY02fO9HxCM2rtPs1yMwVYPOu+LDL/uD/Eh1T9/7dJPbrcgQK0gMUXJqToUm5gcUSHGhQ86c94dvZui/p/NXt3qevG2X/gsqKTTSX+nXudtHsKY0p7APZNi/7/aQuIPyrtmQLqDlXgJheDLGw+RNB4YR+1k7W+PxelkOL7s+cxdYTYDlw5Yiw/XBy0uVP+2peXxt9ozWkX4Hqr1TWDEk375Cm31Ub8dRnkWdn/tHX2N4gl95zp/ehp2el/W+6fYBsNjHF2bv5GwNOyYrAsJhNpq7S8K9iBI2tSKIFzwKc+/5nsz9iwPQhtoWPzHaPWLo9/vTeenUsjyzQelIV/1oduhmyxZtpGp4C3Iql49Y3OqAVtQMkUUSWWNZfconrVzOG2bdTr4EWA3Pc6RXg3xWu1EwiEHD/AhvZBYQzu456kvWUfuhnIGn9RqNPIyu57e4p7nEH6pULNh6RL4sljUEY1LKmgJaOjsKOh7MO7yW1+CP60Usq7atGl1uX64ZxgCb1TuLnSTiKPAD8f/KTk1zX/7ija+vSCF1bFxC6trO3/yPAAKRem5XZIKfcAAAAAElFTkSuQmCC
diff --git a/browser/locales/en-US/searchplugins/yahoo.xml b/browser/locales/en-US/searchplugins/yahoo.xml
index 3d9f58821bd8..a21ccc2d20ba 100644
--- a/browser/locales/en-US/searchplugins/yahoo.xml
+++ b/browser/locales/en-US/searchplugins/yahoo.xml
@@ -7,6 +7,7 @@
Yahoo SearchUTF-8data:image/x-icon;base64,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
+data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAYAAADovjFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjcwNUUyRjFGQjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjcwNUUyRjIwQjUyNTExRTNCNzdEOTU4N0NCMjI3MEFDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NzA1RTJGMURCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NzA1RTJGMUVCNTI1MTFFM0I3N0Q5NTg3Q0IyMjcwQUMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4qMBarAAAI8ElEQVR42uxZeVRT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data:image/png;base64,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
diff --git a/browser/metro/base/content/browser-ui.js b/browser/metro/base/content/browser-ui.js
index 96a91526c329..b106824af167 100644
--- a/browser/metro/base/content/browser-ui.js
+++ b/browser/metro/base/content/browser-ui.js
@@ -7,6 +7,9 @@
Cu.import("resource://gre/modules/devtools/dbg-server.jsm")
Cu.import("resource://gre/modules/WindowsPrefSync.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
+ "resource://gre/modules/LoginManagerParent.jsm");
+
/**
* Constants
*/
@@ -167,6 +170,7 @@ var BrowserUI = {
DialogUI.init();
FormHelperUI.init();
FindHelperUI.init();
+ LoginManagerParent.init();
#ifdef NIGHTLY_BUILD
PdfJs.init();
#endif
diff --git a/build/autoconf/compiler-opts.m4 b/build/autoconf/compiler-opts.m4
index 216edeb9a0f7..05e5632d0d60 100644
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -185,9 +185,7 @@ dnl A high level macro for selecting compiler options.
AC_DEFUN([MOZ_COMPILER_OPTS],
[
if test "${MOZ_PSEUDO_DERECURSE-unset}" = unset; then
- dnl Don't enable on pymake, because of bug 918652. Bug 912979 is an annoyance
- dnl with pymake, too.
- MOZ_PSEUDO_DERECURSE=no-pymake
+ MOZ_PSEUDO_DERECURSE=1
fi
MOZ_DEBUGGING_OPTS
@@ -246,6 +244,13 @@ if test "$GNU_CC" -a -n "$MOZ_FORCE_GOLD"; then
fi
fi
fi
+if test "$GNU_CC"; then
+ if $CC $LDFLAGS -Wl,--version 2>&1 | grep -q "GNU ld"; then
+ LD_IS_BFD=1
+ fi
+fi
+
+AC_SUBST([LD_IS_BFD])
if test "$GNU_CC"; then
if test -z "$DEVELOPER_OPTIONS"; then
diff --git a/build/docs/slow.rst b/build/docs/slow.rst
index 018652d9b834..546fe26ce230 100644
--- a/build/docs/slow.rst
+++ b/build/docs/slow.rst
@@ -88,22 +88,9 @@ GB is likely entering the point of diminishing returns.
This cause impacts both clobber and incremental builds.
-You are building with pymake
-============================
-
-Pymake is slower than GNU make. One reason is Python is generally slower
-than C. The build system maintainers are consistently looking at
-optimizing pymake. However, it is death by a thousand cuts.
-
-This cause impacts both clobber and incremental builds.
-
You are building on Windows
===========================
-Builds on Windows are slow for a few reasons. First, Windows builds use
-pymake, not GNU make (because of compatibility issues with GNU make).
-But, there are other sources of slowness.
-
New processes on Windows are about a magnitude slower to spawn than on
UNIX-y systems such as Linux. This is because Windows has optimized new
threads while the \*NIX platforms typically optimize new processes.
diff --git a/build/win32/autobinscope.py b/build/win32/autobinscope.py
index 4899e731ab46..8bb455990bfd 100644
--- a/build/win32/autobinscope.py
+++ b/build/win32/autobinscope.py
@@ -46,8 +46,7 @@ except KeyError:
try:
proc = subprocess.Popen([binscope_path, "/target", binary_path,
"/output", log_file_path, "/sympath", symbol_path,
- "/c", "ATLVersionCheck", "/c", "ATLVulnCheck", "/c", "FunctionPointersCheck",
- "/c", "SharedSectionCheck", "/c", "APTCACheck", "/c", "NXCheck",
+ "/c", "ATLVersionCheck", "/c", "ATLVulnCheck", "/c", "SharedSectionCheck", "/c", "APTCACheck", "/c", "NXCheck",
"/c", "GSCheck", "/c", "GSFunctionSafeBuffersCheck", "/c", "GSFriendlyInitCheck",
"/c", "CompilerVersionCheck", "/c", "SafeSEHCheck", "/c", "SNCheck",
"/c", "DBCheck"], stdout=subprocess.PIPE)
diff --git a/client.mk b/client.mk
index 8785d07c47e3..7fd04c5d5db9 100644
--- a/client.mk
+++ b/client.mk
@@ -145,13 +145,6 @@ endif
ifndef MOZ_OBJDIR
MOZ_OBJDIR = obj-$(CONFIG_GUESS)
-else
-# On Windows Pymake builds check MOZ_OBJDIR doesn't start with "/"
- ifneq (,$(findstring mingw,$(CONFIG_GUESS)))
- ifeq (1_a,$(.PYMAKE)_$(firstword a$(subst /, ,$(MOZ_OBJDIR))))
- $(error For Windows Pymake builds, MOZ_OBJDIR must be a Windows [and not MSYS] style path.)
- endif
- endif
endif
ifdef MOZ_BUILD_PROJECTS
diff --git a/config/config.mk b/config/config.mk
index b6df7a93b5ad..c1c41964e86e 100644
--- a/config/config.mk
+++ b/config/config.mk
@@ -194,16 +194,6 @@ endif
CONFIG_TOOLS = $(MOZ_BUILD_ROOT)/config
AUTOCONF_TOOLS = $(topsrcdir)/build/autoconf
-# Disable MOZ_PSEUDO_DERECURSE when it contains no-pymake and we're running
-# pymake. This can be removed when no-pymake is removed from the default in
-# build/autoconf/compiler-opts.m4.
-ifdef .PYMAKE
-comma = ,
-ifneq (,$(filter no-pymake,$(subst $(comma), ,$(MOZ_PSEUDO_DERECURSE))))
-MOZ_PSEUDO_DERECURSE :=
-endif
-endif
-
# Disable MOZ_PSEUDO_DERECURSE on PGO builds until it's fixed.
ifneq (,$(MOZ_PROFILE_USE)$(MOZ_PROFILE_GENERATE))
MOZ_PSEUDO_DERECURSE :=
@@ -238,10 +228,6 @@ MKDIR ?= mkdir
SLEEP ?= sleep
TOUCH ?= touch
-ifdef .PYMAKE
-PYCOMMANDPATH += $(PYTHON_SITE_PACKAGES)
-endif
-
PYTHON_PATH = $(PYTHON) $(topsrcdir)/config/pythonpath.py
# determine debug-related options
@@ -720,9 +706,6 @@ endif # NSINSTALL_BIN
ifeq (,$(CROSS_COMPILE)$(filter-out WINNT, $(OS_ARCH)))
INSTALL = $(NSINSTALL) -t
-ifdef .PYMAKE
-install_cmd = $(NSINSTALL_NATIVECMD) -t $(1)
-endif # .PYMAKE
else
@@ -839,6 +822,7 @@ endif
define CHECK_BINARY
$(call CHECK_STDCXX,$(1))
$(call CHECK_TEXTREL,$(1))
+$(call LOCAL_CHECKS,$(1))
endef
# autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
diff --git a/config/makefiles/functions.mk b/config/makefiles/functions.mk
index d97b604f9944..ac3632b486f9 100644
--- a/config/makefiles/functions.mk
+++ b/config/makefiles/functions.mk
@@ -27,8 +27,4 @@ core_winabspath = $(error core_winabspath is unsupported)
#
# libs::
# $(call py_action,purge_manifests,_build_manifests/purge/foo.manifest)
-ifdef .PYMAKE
-py_action = %mozbuild.action.$(1) main $(2)
-else
py_action = $(PYTHON) -m mozbuild.action.$(1) $(2)
-endif
diff --git a/config/rules.mk b/config/rules.mk
index b958cccefe71..dff696a68589 100644
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -35,23 +35,8 @@ endif
USE_AUTOTARGETS_MK = 1
include $(topsrcdir)/config/makefiles/makeutils.mk
-# Only build with Pymake (not GNU make) on Windows.
-ifeq ($(HOST_OS_ARCH),WINNT)
-ifndef L10NBASEDIR
-ifndef .PYMAKE
-$(error Pymake is required to build on Windows. Run |./mach build| to \
-automatically use pymake or invoke pymake directly via \
-|python build/pymake/make.py|.)
-endif
-endif
-endif
-
ifdef REBUILD_CHECK
-ifdef .PYMAKE
-REPORT_BUILD = @%rebuild_check rebuild_check $@ $^
-else
REPORT_BUILD = $(info $(shell $(PYTHON) $(MOZILLA_DIR)/config/rebuild_check.py $@ $^))
-endif
else
REPORT_BUILD = $(info $(notdir $@))
endif
@@ -66,15 +51,11 @@ endif
# ELOG prints out failed command when building silently (gmake -s). Pymake
# prints out failed commands anyway, so ELOG just makes things worse by
# forcing shell invocations.
-ifndef .PYMAKE
ifneq (,$(findstring s, $(filter-out --%, $(MAKEFLAGS))))
ELOG := $(EXEC) sh $(BUILD_TOOLS)/print-failed-commands.sh
else
ELOG :=
endif # -s
-else
- ELOG :=
-endif # ifndef .PYMAKE
_VPATH_SRCS = $(abspath $<)
@@ -238,7 +219,7 @@ endif
COMPILE_CFLAGS += $(COMPILE_PDB_FLAG)
COMPILE_CXXFLAGS += $(COMPILE_PDB_FLAG)
-LINK_PDBFILE = $(basename $(@F)).pdb
+LINK_PDBFILE ?= $(basename $(@F)).pdb
ifdef MOZ_DEBUG
CODFILE=$(basename $(@F)).cod
endif
@@ -1142,9 +1123,7 @@ else
endif
# Cancel GNU make built-in implicit rules
-ifndef .PYMAKE
MAKEFLAGS += -r
-endif
ifneq (,$(filter WINNT,$(OS_ARCH)))
SEP := ;
diff --git a/config/tests/makefiles/autodeps/Makefile.in b/config/tests/makefiles/autodeps/Makefile.in
index b588c33be94a..ea21c5a8e404 100644
--- a/config/tests/makefiles/autodeps/Makefile.in
+++ b/config/tests/makefiles/autodeps/Makefile.in
@@ -22,7 +22,6 @@ tgts =\
$(NULL)
export MAKE
-export .PYMAKE
##------------------_##
##---] TARGETS [---##
diff --git a/content/base/src/CSPUtils.jsm b/content/base/src/CSPUtils.jsm
index b21e5db8ff7d..983a7f574ef2 100644
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -193,7 +193,7 @@ CSPPolicyURIListener.prototype = {
// send the policy we received back to the parent document's CSP
// for parsing
this._csp.appendPolicy(this._policy, this._docURI,
- this._reportOnly, this._csp._specCompliant);
+ this._reportOnly, true);
}
else {
// problem fetching policy so fail closed by appending a "block it all"
@@ -202,7 +202,7 @@ CSPPolicyURIListener.prototype = {
this._csp.log(WARN_FLAG, CSPLocalizer.getFormatStr("errorFetchingPolicy",
[status]));
this._csp.appendPolicy("default-src 'none'", this._docURI,
- this._reportOnly, this._csp._specCompliant);
+ this._reportOnly, true);
}
// resume the parent document request
this._docRequest.resume();
@@ -213,49 +213,23 @@ CSPPolicyURIListener.prototype = {
/**
* Class that represents a parsed policy structure.
- *
- * @param aSpecCompliant: true: this policy is a CSP 1.0 spec
- * compliant policy and should be parsed as such.
- * false or undefined: this is a policy using
- * our original implementation's CSP syntax.
*/
-this.CSPRep = function CSPRep(aSpecCompliant) {
+this.CSPRep = function CSPRep() {
// this gets set to true when the policy is done parsing, or when a
// URI-borne policy has finished loading.
this._isInitialized = false;
this._allowEval = false;
this._allowInlineScripts = false;
+ this._allowInlineStyles = false;
this._reportOnlyMode = false;
// don't auto-populate _directives, so it is easier to find bugs
this._directives = {};
-
- // Is this a 1.0 spec compliant CSPRep ?
- // Default to false if not specified.
- this._specCompliant = (aSpecCompliant !== undefined) ? aSpecCompliant : false;
-
- // Only CSP 1.0 spec compliant policies block inline styles by default.
- this._allowInlineStyles = !aSpecCompliant;
}
-// Source directives for our original CSP implementation.
-// These can be removed when the original implementation is deprecated.
-CSPRep.SRC_DIRECTIVES_OLD = {
- DEFAULT_SRC: "default-src",
- SCRIPT_SRC: "script-src",
- STYLE_SRC: "style-src",
- MEDIA_SRC: "media-src",
- IMG_SRC: "img-src",
- OBJECT_SRC: "object-src",
- FRAME_SRC: "frame-src",
- FRAME_ANCESTORS: "frame-ancestors",
- FONT_SRC: "font-src",
- XHR_SRC: "xhr-src"
-};
-
// Source directives for our CSP 1.0 spec compliant implementation.
-CSPRep.SRC_DIRECTIVES_NEW = {
+CSPRep.SRC_DIRECTIVES = {
DEFAULT_SRC: "default-src",
SCRIPT_SRC: "script-src",
STYLE_SRC: "style-src",
@@ -273,268 +247,6 @@ CSPRep.URI_DIRECTIVES = {
POLICY_URI: "policy-uri" /* single URI */
};
-// These directives no longer exist in CSP 1.0 and
-// later and will eventually be removed when we no longer
-// support our original implementation's syntax.
-CSPRep.OPTIONS_DIRECTIVE = "options";
-CSPRep.ALLOW_DIRECTIVE = "allow";
-
-/**
- * Factory to create a new CSPRep, parsed from a string.
- *
- * @param aStr
- * string rep of a CSP
- * @param self (optional)
- * URI representing the "self" source
- * @param reportOnly (optional)
- * whether or not this CSP is report-only (defaults to false)
- * @param docRequest (optional)
- * request for the parent document which may need to be suspended
- * while the policy-uri is asynchronously fetched
- * @param csp (optional)
- * the CSP object to update once the policy has been fetched
- * @param enforceSelfChecks (optional)
- * if present, and "true", will check to be sure "self" has the
- * appropriate values to inherit when they are omitted from the source.
- * @returns
- * an instance of CSPRep
- */
-CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp,
- enforceSelfChecks) {
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
- var UD = CSPRep.URI_DIRECTIVES;
- var aCSPR = new CSPRep();
- aCSPR._originalText = aStr;
- aCSPR._innerWindowID = innerWindowFromRequest(docRequest);
- if (typeof reportOnly === 'undefined') reportOnly = false;
- aCSPR._reportOnlyMode = reportOnly;
-
- var selfUri = null;
- if (self instanceof Ci.nsIURI) {
- selfUri = self.cloneIgnoringRef();
- // clean userpass out of the URI (not used for CSP origin checking, but
- // shows up in prePath).
- try {
- // GetUserPass throws for some protocols without userPass
- selfUri.userPass = '';
- } catch (ex) {}
- }
-
- var dirs = aStr.split(";");
-
- directive:
- for each(var dir in dirs) {
- dir = dir.trim();
- if (dir.length < 1) continue;
-
- var dirname = dir.split(/\s+/)[0].toLowerCase();
- var dirvalue = dir.substring(dirname.length).trim();
-
- if (aCSPR._directives.hasOwnProperty(dirname)) {
- // Check for (most) duplicate directives
- cspError(aCSPR, CSPLocalizer.getFormatStr("duplicateDirective",
- [dirname]));
- CSPdebug("Skipping duplicate directive: \"" + dir + "\"");
- continue directive;
- }
-
- // OPTIONS DIRECTIVE ////////////////////////////////////////////////
- if (dirname === CSPRep.OPTIONS_DIRECTIVE) {
- if (aCSPR._allowInlineScripts || aCSPR._allowEval) {
- // Check for duplicate options directives
- cspError(aCSPR, CSPLocalizer.getFormatStr("duplicateDirective",
- [dirname]));
- CSPdebug("Skipping duplicate directive: \"" + dir + "\"");
- continue directive;
- }
-
- // grab value tokens and interpret them
- var options = dirvalue.split(/\s+/);
- for each (var opt in options) {
- if (opt === "inline-script")
- aCSPR._allowInlineScripts = true;
- else if (opt === "eval-script")
- aCSPR._allowEval = true;
- else
- cspWarn(aCSPR, CSPLocalizer.getFormatStr("ignoringUnknownOption",
- [opt]));
- }
- continue directive;
- }
-
- // ALLOW DIRECTIVE //////////////////////////////////////////////////
- // parse "allow" as equivalent to "default-src", at least until the spec
- // stabilizes, at which time we can stop parsing "allow"
- if (dirname === CSPRep.ALLOW_DIRECTIVE) {
- cspWarn(aCSPR, CSPLocalizer.getStr("allowDirectiveIsDeprecated"));
- if (aCSPR._directives.hasOwnProperty(SD.DEFAULT_SRC)) {
- // Check for duplicate default-src and allow directives
- cspError(aCSPR, CSPLocalizer.getFormatStr("duplicateDirective",
- [dirname]));
- CSPdebug("Skipping duplicate directive: \"" + dir + "\"");
- continue directive;
- }
- var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri,
- enforceSelfChecks);
- if (dv) {
- aCSPR._directives[SD.DEFAULT_SRC] = dv;
- continue directive;
- }
- }
-
- // SOURCE DIRECTIVES ////////////////////////////////////////////////
- for each(var sdi in SD) {
- if (dirname === sdi) {
- // process dirs, and enforce that 'self' is defined.
- var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri,
- enforceSelfChecks);
- if (dv) {
- aCSPR._directives[sdi] = dv;
- continue directive;
- }
- }
- }
-
- // REPORT URI ///////////////////////////////////////////////////////
- if (dirname === UD.REPORT_URI) {
- // might be space-separated list of URIs
- var uriStrings = dirvalue.split(/\s+/);
- var okUriStrings = [];
-
- for (let i in uriStrings) {
- var uri = null;
- try {
- // Relative URIs are okay, but to ensure we send the reports to the
- // right spot, the relative URIs are expanded here during parsing.
- // The resulting CSPRep instance will have only absolute URIs.
- uri = gIoService.newURI(uriStrings[i],null,selfUri);
-
- // if there's no host, this will throw NS_ERROR_FAILURE, causing a
- // parse failure.
- uri.host;
-
- // warn about, but do not prohibit non-http and non-https schemes for
- // reporting URIs. The spec allows unrestricted URIs resolved
- // relative to "self", but we should let devs know if the scheme is
- // abnormal and may fail a POST.
- if (!uri.schemeIs("http") && !uri.schemeIs("https")) {
- cspWarn(aCSPR, CSPLocalizer.getFormatStr("reportURInotHttpsOrHttp2",
- [uri.asciiSpec]));
- }
- } catch(e) {
- switch (e.result) {
- case Components.results.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS:
- case Components.results.NS_ERROR_HOST_IS_IP_ADDRESS:
- if (uri.host !== selfUri.host) {
- cspWarn(aCSPR,
- CSPLocalizer.getFormatStr("pageCannotSendReportsTo",
- [selfUri.host, uri.host]));
- continue;
- }
- break;
-
- default:
- cspWarn(aCSPR, CSPLocalizer.getFormatStr("couldNotParseReportURI",
- [uriStrings[i]]));
- continue;
- }
- }
- // all verification passed
- okUriStrings.push(uri.asciiSpec);
- }
- aCSPR._directives[UD.REPORT_URI] = okUriStrings.join(' ');
- continue directive;
- }
-
- // POLICY URI //////////////////////////////////////////////////////////
- if (dirname === UD.POLICY_URI) {
- // POLICY_URI can only be alone
- if (aCSPR._directives.length > 0 || dirs.length > 1) {
- cspError(aCSPR, CSPLocalizer.getStr("policyURINotAlone"));
- return CSPRep.fromString("default-src 'none'", null, reportOnly);
- }
- // if we were called without a reference to the parent document request
- // we won't be able to suspend it while we fetch the policy -> fail closed
- if (!docRequest || !csp) {
- cspError(aCSPR, CSPLocalizer.getStr("noParentRequest"));
- return CSPRep.fromString("default-src 'none'", null, reportOnly);
- }
-
- var uri = '';
- try {
- uri = gIoService.newURI(dirvalue, null, selfUri);
- } catch(e) {
- cspError(aCSPR, CSPLocalizer.getFormatStr("policyURIParseError",
- [dirvalue]));
- return CSPRep.fromString("default-src 'none'", null, reportOnly);
- }
-
- // Verify that policy URI comes from the same origin
- if (selfUri) {
- if (selfUri.host !== uri.host) {
- cspError(aCSPR, CSPLocalizer.getFormatStr("nonMatchingHost",
- [uri.host]));
- return CSPRep.fromString("default-src 'none'", null, reportOnly);
- }
- if (selfUri.port !== uri.port) {
- cspError(aCSPR, CSPLocalizer.getFormatStr("nonMatchingPort",
- [uri.port.toString()]));
- return CSPRep.fromString("default-src 'none'", null, reportOnly);
- }
- if (selfUri.scheme !== uri.scheme) {
- cspError(aCSPR, CSPLocalizer.getFormatStr("nonMatchingScheme",
- [uri.scheme]));
- return CSPRep.fromString("default-src 'none'", null, reportOnly);
- }
- }
-
- // suspend the parent document request while we fetch the policy-uri
- try {
- docRequest.suspend();
- var chan = gIoService.newChannel(uri.asciiSpec, null, null);
- // make request anonymous (no cookies, etc.) so the request for the
- // policy-uri can't be abused for CSRF
- chan.loadFlags |= Ci.nsIChannel.LOAD_ANONYMOUS;
- chan.loadGroup = docRequest.loadGroup;
- chan.asyncOpen(new CSPPolicyURIListener(uri, docRequest, csp, reportOnly), null);
- }
- catch (e) {
- // resume the document request and apply most restrictive policy
- docRequest.resume();
- cspError(aCSPR, CSPLocalizer.getFormatStr("errorFetchingPolicy",
- [e.toString()]));
- return CSPRep.fromString("default-src 'none'", null, reportOnly);
- }
-
- // return a fully-open policy to be used until the contents of the
- // policy-uri come back.
- return CSPRep.fromString("default-src *", null, reportOnly);
- }
-
- // UNIDENTIFIED DIRECTIVE /////////////////////////////////////////////
- cspWarn(aCSPR, CSPLocalizer.getFormatStr("couldNotProcessUnknownDirective",
- [dirname]));
-
- } // end directive: loop
-
- // the X-Content-Security-Policy syntax requires an allow or default-src
- // directive to be present.
- if (!aCSPR._directives[SD.DEFAULT_SRC]) {
- cspWarn(aCSPR, CSPLocalizer.getStr("allowOrDefaultSrcRequired"));
- return CSPRep.fromString("default-src 'none'", null, reportOnly);
- }
-
- // If this is a Report-Only header and report-uri is not in the directive
- // list, tell developer either specify report-uri directive or use
- // a non-Report-Only CSP header.
- if (aCSPR._reportOnlyMode && !aCSPR._directives.hasOwnProperty(UD.REPORT_URI)) {
- cspWarn(aCSPR, CSPLocalizer.getFormatStr("reportURInotInReportOnlyHeader",
- [selfUri ? selfUri.prePath : "undefined"]))
- }
-
- return aCSPR;
-};
-
/**
* Factory to create a new CSPRep, parsed from a string, compliant
* with the CSP 1.0 spec.
@@ -556,13 +268,11 @@ CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp,
* @returns
* an instance of CSPRep
*/
-// When we deprecate our original CSP implementation, we rename this to
-// CSPRep.fromString and remove the existing CSPRep.fromString above.
-CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, csp,
- enforceSelfChecks) {
- var SD = CSPRep.SRC_DIRECTIVES_NEW;
+CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp,
+ enforceSelfChecks) {
+ var SD = CSPRep.SRC_DIRECTIVES;
var UD = CSPRep.URI_DIRECTIVES;
- var aCSPR = new CSPRep(true);
+ var aCSPR = new CSPRep();
aCSPR._originalText = aStr;
aCSPR._innerWindowID = innerWindowFromRequest(docRequest);
if (typeof reportOnly === 'undefined') reportOnly = false;
@@ -587,7 +297,10 @@ CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, cs
var dirname = dir.split(/\s+/)[0].toLowerCase();
var dirvalue = dir.substring(dirname.length).trim();
- dirs[dirname] = dirvalue;
+ // skip duplicates
+ if (!dirs.hasOwnProperty(dirname)) {
+ dirs[dirname] = dirvalue;
+ }
}
// Spec compliant policies have different default behavior for inline
@@ -712,13 +425,13 @@ CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, cs
// POLICY_URI can only be alone
if (aCSPR._directives.length > 0 || dirs.length > 1) {
cspError(aCSPR, CSPLocalizer.getStr("policyURINotAlone"));
- return CSPRep.fromStringSpecCompliant("default-src 'none'", null, reportOnly);
+ return CSPRep.fromString("default-src 'none'", null, reportOnly);
}
// if we were called without a reference to the parent document request
// we won't be able to suspend it while we fetch the policy -> fail closed
if (!docRequest || !csp) {
cspError(aCSPR, CSPLocalizer.getStr("noParentRequest"));
- return CSPRep.fromStringSpecCompliant("default-src 'none'", null, reportOnly);
+ return CSPRep.fromString("default-src 'none'", null, reportOnly);
}
var uri = '';
@@ -726,22 +439,22 @@ CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, cs
uri = gIoService.newURI(dirvalue, null, selfUri);
} catch(e) {
cspError(aCSPR, CSPLocalizer.getFormatStr("policyURIParseError", [dirvalue]));
- return CSPRep.fromStringSpecCompliant("default-src 'none'", null, reportOnly);
+ return CSPRep.fromString("default-src 'none'", null, reportOnly);
}
// Verify that policy URI comes from the same origin
if (selfUri) {
if (selfUri.host !== uri.host){
cspError(aCSPR, CSPLocalizer.getFormatStr("nonMatchingHost", [uri.host]));
- return CSPRep.fromStringSpecCompliant("default-src 'none'", null, reportOnly);
+ return CSPRep.fromString("default-src 'none'", null, reportOnly);
}
if (selfUri.port !== uri.port){
cspError(aCSPR, CSPLocalizer.getFormatStr("nonMatchingPort", [uri.port.toString()]));
- return CSPRep.fromStringSpecCompliant("default-src 'none'", null, reportOnly);
+ return CSPRep.fromString("default-src 'none'", null, reportOnly);
}
if (selfUri.scheme !== uri.scheme){
cspError(aCSPR, CSPLocalizer.getFormatStr("nonMatchingScheme", [uri.scheme]));
- return CSPRep.fromStringSpecCompliant("default-src 'none'", null, reportOnly);
+ return CSPRep.fromString("default-src 'none'", null, reportOnly);
}
}
@@ -759,12 +472,12 @@ CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, cs
// resume the document request and apply most restrictive policy
docRequest.resume();
cspError(aCSPR, CSPLocalizer.getFormatStr("errorFetchingPolicy", [e.toString()]));
- return CSPRep.fromStringSpecCompliant("default-src 'none'", null, reportOnly);
+ return CSPRep.fromString("default-src 'none'", null, reportOnly);
}
// return a fully-open policy to be used until the contents of the
// policy-uri come back
- return CSPRep.fromStringSpecCompliant("default-src *", null, reportOnly);
+ return CSPRep.fromString("default-src *", null, reportOnly);
}
// UNIDENTIFIED DIRECTIVE /////////////////////////////////////////////
@@ -819,10 +532,6 @@ CSPRep.prototype = {
function csp_toString() {
var dirs = [];
- if (!this._specCompliant && (this._allowEval || this._allowInlineScripts)) {
- dirs.push("options" + (this._allowEval ? " eval-script" : "")
- + (this._allowInlineScripts ? " inline-script" : ""));
- }
for (var i in this._directives) {
if (this._directives[i]) {
dirs.push(i + " " + this._directives[i].toString());
@@ -867,7 +576,7 @@ CSPRep.prototype = {
return true;
// make sure the right directive set is used
- let DIRS = this._specCompliant ? CSPRep.SRC_DIRECTIVES_NEW : CSPRep.SRC_DIRECTIVES_OLD;
+ let DIRS = CSPRep.SRC_DIRECTIVES;
let directiveInPolicy = false;
for (var i in DIRS) {
@@ -904,8 +613,8 @@ CSPRep.prototype = {
}
// no relevant directives present -- this means for CSP 1.0 that the load
- // should be permitted (and for the old CSP, to block it).
- return this._specCompliant;
+ // should be permitted.
+ return true;
},
/**
@@ -1541,7 +1250,11 @@ CSPSource.prototype = {
s = s + this.scheme + "://";
if (this._host)
s = s + this._host;
- if (this.port)
+
+ // CSP 1.0 4.11 says the report should use URI-reference from RFC 3986,
+ // 3.2.3 and indicates that the default port should be omitted.
+ // Non-default ports are included.
+ if (this.port && gIoService.getProtocolHandler(this.scheme).defaultPort != this.port)
s = s + ":" + this.port;
return s;
},
diff --git a/content/base/src/contentSecurityPolicy.js b/content/base/src/contentSecurityPolicy.js
index 21e78a14ce0a..07e204b1dff5 100644
--- a/content/base/src/contentSecurityPolicy.js
+++ b/content/base/src/contentSecurityPolicy.js
@@ -24,11 +24,6 @@ const Cu = Components.utils;
const CSP_VIOLATION_TOPIC = "csp-on-violate-policy";
-// Needed to support CSP 1.0 spec and our original CSP implementation - should
-// be removed when our original implementation is deprecated.
-const CSP_TYPE_XMLHTTPREQUEST_SPEC_COMPLIANT = "csp_type_xmlhttprequest_spec_compliant";
-const CSP_TYPE_WEBSOCKET_SPEC_COMPLIANT = "csp_type_websocket_spec_compliant";
-
const WARN_FLAG = Ci.nsIScriptError.warningFlag;
const ERROR_FLAG = Ci.nsIScriptError.ERROR_FLAG;
@@ -71,14 +66,13 @@ function ContentSecurityPolicy() {
{
let cp = Ci.nsIContentPolicy;
let csp = ContentSecurityPolicy;
- let cspr_sd_old = CSPRep.SRC_DIRECTIVES_OLD;
- let cspr_sd_new = CSPRep.SRC_DIRECTIVES_NEW;
+ let cspr_sd = CSPRep.SRC_DIRECTIVES;
csp._MAPPINGS=[];
/* default, catch-all case */
// This is the same in old and new CSP so use the new mapping.
- csp._MAPPINGS[cp.TYPE_OTHER] = cspr_sd_new.DEFAULT_SRC;
+ csp._MAPPINGS[cp.TYPE_OTHER] = cspr_sd.DEFAULT_SRC;
/* self */
csp._MAPPINGS[cp.TYPE_DOCUMENT] = null;
@@ -87,44 +81,26 @@ function ContentSecurityPolicy() {
csp._MAPPINGS[cp.TYPE_REFRESH] = null;
/* categorized content types */
- // These are the same in old and new CSP's so just use the new mappings.
- csp._MAPPINGS[cp.TYPE_SCRIPT] = cspr_sd_new.SCRIPT_SRC;
- csp._MAPPINGS[cp.TYPE_IMAGE] = cspr_sd_new.IMG_SRC;
- csp._MAPPINGS[cp.TYPE_STYLESHEET] = cspr_sd_new.STYLE_SRC;
- csp._MAPPINGS[cp.TYPE_OBJECT] = cspr_sd_new.OBJECT_SRC;
- csp._MAPPINGS[cp.TYPE_OBJECT_SUBREQUEST] = cspr_sd_new.OBJECT_SRC;
- csp._MAPPINGS[cp.TYPE_SUBDOCUMENT] = cspr_sd_new.FRAME_SRC;
- csp._MAPPINGS[cp.TYPE_MEDIA] = cspr_sd_new.MEDIA_SRC;
- csp._MAPPINGS[cp.TYPE_FONT] = cspr_sd_new.FONT_SRC;
- csp._MAPPINGS[cp.TYPE_XSLT] = cspr_sd_new.SCRIPT_SRC;
- csp._MAPPINGS[cp.TYPE_BEACON] = cspr_sd_new.CONNECT_SRC;
-
- /* Our original CSP implementation's mappings for XHR and websocket
- * These should be changed to be = cspr_sd.CONNECT_SRC when we remove
- * the original implementation - NOTE: order in this array is important !!!
- */
- csp._MAPPINGS[cp.TYPE_XMLHTTPREQUEST] = cspr_sd_old.XHR_SRC;
- csp._MAPPINGS[cp.TYPE_WEBSOCKET] = cspr_sd_old.XHR_SRC;
+ csp._MAPPINGS[cp.TYPE_SCRIPT] = cspr_sd.SCRIPT_SRC;
+ csp._MAPPINGS[cp.TYPE_IMAGE] = cspr_sd.IMG_SRC;
+ csp._MAPPINGS[cp.TYPE_STYLESHEET] = cspr_sd.STYLE_SRC;
+ csp._MAPPINGS[cp.TYPE_OBJECT] = cspr_sd.OBJECT_SRC;
+ csp._MAPPINGS[cp.TYPE_OBJECT_SUBREQUEST] = cspr_sd.OBJECT_SRC;
+ csp._MAPPINGS[cp.TYPE_SUBDOCUMENT] = cspr_sd.FRAME_SRC;
+ csp._MAPPINGS[cp.TYPE_MEDIA] = cspr_sd.MEDIA_SRC;
+ csp._MAPPINGS[cp.TYPE_FONT] = cspr_sd.FONT_SRC;
+ csp._MAPPINGS[cp.TYPE_XSLT] = cspr_sd.SCRIPT_SRC;
+ csp._MAPPINGS[cp.TYPE_BEACON] = cspr_sd.CONNECT_SRC;
+ csp._MAPPINGS[cp.TYPE_XMLHTTPREQUEST] = cspr_sd.CONNECT_SRC;
+ csp._MAPPINGS[cp.TYPE_WEBSOCKET] = cspr_sd.CONNECT_SRC;
/* CSP cannot block CSP reports */
csp._MAPPINGS[cp.TYPE_CSP_REPORT] = null;
/* These must go through the catch-all */
- csp._MAPPINGS[cp.TYPE_XBL] = cspr_sd_new.DEFAULT_SRC;
- csp._MAPPINGS[cp.TYPE_PING] = cspr_sd_new.DEFAULT_SRC;
- csp._MAPPINGS[cp.TYPE_DTD] = cspr_sd_new.DEFAULT_SRC;
-
- /* CSP 1.0 spec compliant mappings for XHR and websocket */
- // The directive name for XHR, websocket, and EventSource is different
- // in the 1.0 spec than in our original implementation, these mappings
- // address this. These won't be needed when we deprecate our original
- // implementation.
- csp._MAPPINGS[CSP_TYPE_XMLHTTPREQUEST_SPEC_COMPLIANT] = cspr_sd_new.CONNECT_SRC;
- csp._MAPPINGS[CSP_TYPE_WEBSOCKET_SPEC_COMPLIANT] = cspr_sd_new.CONNECT_SRC;
- // TODO : EventSource will be here and also will use connect-src
- // after we fix Bug 802872 - CSP should restrict EventSource using the connect-src
- // directive. For background see Bug 667490 - EventSource should use the same
- // nsIContentPolicy type as XHR (which is fixed)
+ csp._MAPPINGS[cp.TYPE_XBL] = cspr_sd.DEFAULT_SRC;
+ csp._MAPPINGS[cp.TYPE_PING] = cspr_sd.DEFAULT_SRC;
+ csp._MAPPINGS[cp.TYPE_DTD] = cspr_sd.DEFAULT_SRC;
}
ContentSecurityPolicy.prototype = {
@@ -157,7 +133,7 @@ ContentSecurityPolicy.prototype = {
_buildViolatedDirectiveString:
function(aDirectiveName, aPolicy) {
- var SD = CSPRep.SRC_DIRECTIVES_NEW;
+ var SD = CSPRep.SRC_DIRECTIVES;
var cspContext = (SD[aDirectiveName] in aPolicy._directives) ? SD[aDirectiveName] : SD.DEFAULT_SRC;
var directive = aPolicy._directives[cspContext];
return cspContext + ' ' + directive.toString();
@@ -410,8 +386,7 @@ ContentSecurityPolicy.prototype = {
*/
appendPolicy:
function csp_appendPolicy(aPolicy, selfURI, aReportOnly, aSpecCompliant) {
- return this._appendPolicyInternal(aPolicy, selfURI, aReportOnly,
- aSpecCompliant, true);
+ return this._appendPolicyInternal(aPolicy, selfURI, aReportOnly, true);
},
/**
@@ -420,12 +395,10 @@ ContentSecurityPolicy.prototype = {
* @returns the count of policies.
*/
_appendPolicyInternal:
- function csp_appendPolicy(aPolicy, selfURI, aReportOnly, aSpecCompliant,
- aEnforceSelfChecks) {
+ function csp_appendPolicy(aPolicy, selfURI, aReportOnly, aEnforceSelfChecks) {
#ifndef MOZ_B2G
CSPdebug("APPENDING POLICY: " + aPolicy);
CSPdebug(" SELF: " + (selfURI ? selfURI.asciiSpec : " null"));
- CSPdebug("CSP 1.0 COMPLIANT : " + aSpecCompliant);
#endif
// For nested schemes such as view-source: make sure we are taking the
@@ -446,26 +419,9 @@ ContentSecurityPolicy.prototype = {
// Note that we pass the full URI since when it's parsed as 'self' to construct a
// CSPSource only the scheme, host, and port are kept.
- // If we want to be CSP 1.0 spec compliant, use the new parser.
- // The old one will be deprecated in the future and will be
- // removed at that time.
- if (aSpecCompliant) {
- newpolicy = CSPRep.fromStringSpecCompliant(aPolicy,
- selfURI,
- aReportOnly,
- this._weakDocRequest.get(),
- this,
- aEnforceSelfChecks);
- } else {
- newpolicy = CSPRep.fromString(aPolicy,
- selfURI,
- aReportOnly,
- this._weakDocRequest.get(),
- this,
- aEnforceSelfChecks);
- }
-
- newpolicy._specCompliant = !!aSpecCompliant;
+ newpolicy = CSPRep.fromString(aPolicy, selfURI, aReportOnly,
+ this._weakDocRequest.get(),
+ this, aEnforceSelfChecks);
newpolicy._isInitialized = true;
this._policies.push(newpolicy);
this._cache.clear(); // reset cache since effective policy changes
@@ -711,7 +667,7 @@ ContentSecurityPolicy.prototype = {
// scan the discovered ancestors
// frame-ancestors is the same in both old and new source directives,
// so don't need to differentiate here.
- let cspContext = CSPRep.SRC_DIRECTIVES_NEW.FRAME_ANCESTORS;
+ let cspContext = CSPRep.SRC_DIRECTIVES.FRAME_ANCESTORS;
for (let i in ancestors) {
let ancestor = ancestors[i];
if (!policy.permits(ancestor, cspContext)) {
@@ -806,22 +762,11 @@ ContentSecurityPolicy.prototype = {
for (let policyIndex=0; policyIndex < this._policies.length; policyIndex++) {
let policy = this._policies[policyIndex];
+ cspContext = ContentSecurityPolicy._MAPPINGS[aContentType];
+
#ifndef MOZ_B2G
- CSPdebug("policy is " + (policy._specCompliant ?
- "1.0 compliant" : "pre-1.0"));
CSPdebug("policy is " + (policy._reportOnlyMode ?
"report-only" : "blocking"));
-#endif
-
- if (aContentType == cp.TYPE_XMLHTTPREQUEST && this._policies[policyIndex]._specCompliant) {
- cspContext = ContentSecurityPolicy._MAPPINGS[CSP_TYPE_XMLHTTPREQUEST_SPEC_COMPLIANT];
- } else if (aContentType == cp.TYPE_WEBSOCKET && this._policies[policyIndex]._specCompliant) {
- cspContext = ContentSecurityPolicy._MAPPINGS[CSP_TYPE_WEBSOCKET_SPEC_COMPLIANT];
- } else {
- cspContext = ContentSecurityPolicy._MAPPINGS[aContentType];
- }
-
-#ifndef MOZ_B2G
CSPdebug("shouldLoad cspContext = " + cspContext);
#endif
@@ -979,11 +924,9 @@ ContentSecurityPolicy.prototype = {
for (let pCount = aStream.read32(); pCount > 0; pCount--) {
let polStr = aStream.readString();
let reportOnly = aStream.readBoolean();
- let specCompliant = aStream.readBoolean();
// don't need self info because when the policy is turned back into a
// string, 'self' is replaced with the explicit source expression.
- this._appendPolicyInternal(polStr, null, reportOnly, specCompliant,
- false);
+ this._appendPolicyInternal(polStr, null, reportOnly, false);
}
// NOTE: the document instance that's deserializing this object (via its
@@ -1010,7 +953,6 @@ ContentSecurityPolicy.prototype = {
for each (var policy in this._policies) {
aStream.writeWStringZ(policy.toString());
aStream.writeBoolean(policy._reportOnlyMode);
- aStream.writeBoolean(policy._specCompliant);
}
},
};
diff --git a/content/base/src/nsCSPContext.cpp b/content/base/src/nsCSPContext.cpp
index cef82a50e746..1fe8527b7140 100644
--- a/content/base/src/nsCSPContext.cpp
+++ b/content/base/src/nsCSPContext.cpp
@@ -821,6 +821,7 @@ class CSPReportSenderRunnable MOZ_FINAL : public nsRunnable
CSPReportSenderRunnable(nsISupports* aBlockedContentSource,
nsIURI* aOriginalURI,
uint32_t aViolatedPolicyIndex,
+ bool aReportOnlyFlag,
const nsAString& aViolatedDirective,
const nsAString& aObserverSubject,
const nsAString& aSourceFile,
@@ -831,6 +832,7 @@ class CSPReportSenderRunnable MOZ_FINAL : public nsRunnable
: mBlockedContentSource(aBlockedContentSource)
, mOriginalURI(aOriginalURI)
, mViolatedPolicyIndex(aViolatedPolicyIndex)
+ , mReportOnlyFlag(aReportOnlyFlag)
, mViolatedDirective(aViolatedDirective)
, mSourceFile(aSourceFile)
, mScriptSample(aScriptSample)
@@ -887,7 +889,9 @@ class CSPReportSenderRunnable MOZ_FINAL : public nsRunnable
nsString blockedDataChar16 = NS_ConvertUTF8toUTF16(blockedDataStr);
const char16_t* params[] = { mViolatedDirective.get(),
blockedDataChar16.get() };
- CSP_LogLocalizedStr(NS_LITERAL_STRING("CSPViolationWithURI").get(),
+
+ CSP_LogLocalizedStr(mReportOnlyFlag ? NS_LITERAL_STRING("CSPROViolationWithURI").get() :
+ NS_LITERAL_STRING("CSPViolationWithURI").get(),
params, ArrayLength(params),
mSourceFile, mScriptSample, mLineNum, 0,
nsIScriptError::errorFlag, "CSP", mInnerWindowID);
@@ -899,6 +903,7 @@ class CSPReportSenderRunnable MOZ_FINAL : public nsRunnable
nsCOMPtr mBlockedContentSource;
nsCOMPtr mOriginalURI;
uint32_t mViolatedPolicyIndex;
+ bool mReportOnlyFlag;
nsString mViolatedDirective;
nsCOMPtr mObserverSubject;
nsString mSourceFile;
@@ -943,9 +948,12 @@ nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
const nsAString& aScriptSample,
uint32_t aLineNum)
{
+ NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
+
NS_DispatchToMainThread(new CSPReportSenderRunnable(aBlockedContentSource,
aOriginalURI,
aViolatedPolicyIndex,
+ mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(),
aViolatedDirective,
aObserverSubject,
aSourceFile,
diff --git a/content/base/src/nsContentList.cpp b/content/base/src/nsContentList.cpp
index 7c3ed5b7b68e..ed0027825dad 100644
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -519,7 +519,7 @@ nsContentList::Item(uint32_t aIndex, bool aDoFlush)
}
if (mState != LIST_UP_TO_DATE)
- PopulateSelf(std::min(aIndex, uint32_t(UINT32_MAX - 1)) + 1);
+ PopulateSelf(std::min(aIndex, UINT32_MAX - 1) + 1);
ASSERT_IN_SYNC;
NS_ASSERTION(!mRootNode || mState != LIST_DIRTY,
diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp
index 1076ddd26c81..a6153a1be76b 100644
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -2682,18 +2682,9 @@ nsDocument::InitCSP(nsIChannel* aChannel)
}
nsAutoCString tCspHeaderValue, tCspROHeaderValue;
- nsAutoCString tCspOldHeaderValue, tCspOldROHeaderValue;
nsCOMPtr httpChannel = do_QueryInterface(aChannel);
if (httpChannel) {
- httpChannel->GetResponseHeader(
- NS_LITERAL_CSTRING("x-content-security-policy"),
- tCspOldHeaderValue);
-
- httpChannel->GetResponseHeader(
- NS_LITERAL_CSTRING("x-content-security-policy-report-only"),
- tCspOldROHeaderValue);
-
httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("content-security-policy"),
tCspHeaderValue);
@@ -2704,35 +2695,6 @@ nsDocument::InitCSP(nsIChannel* aChannel)
}
NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
- NS_ConvertASCIItoUTF16 cspOldHeaderValue(tCspOldHeaderValue);
- NS_ConvertASCIItoUTF16 cspOldROHeaderValue(tCspOldROHeaderValue);
-
- // Only use the CSP 1.0 spec compliant headers if a pref to do so
- // is set. This lets us turn on the 1.0 parser per platform. This
- // pref is also set by the tests for 1.0 spec compliant CSP.
- bool specCompliantEnabled =
- Preferences::GetBool("security.csp.speccompliant");
-
- // If spec compliant pref isn't set, pretend we never got these headers.
- if ((!cspHeaderValue.IsEmpty() || !cspROHeaderValue.IsEmpty()) &&
- !specCompliantEnabled) {
- PR_LOG(gCspPRLog, PR_LOG_DEBUG,
- ("Got spec compliant CSP headers but pref was not set"));
- cspHeaderValue.Truncate();
- cspROHeaderValue.Truncate();
- }
-
- // If both the new header AND the old header are present, warn that
- // the old header will be ignored. Otherwise, if the old header is
- // present, warn that it will be deprecated.
- bool oldHeaderIsPresent = !cspOldHeaderValue.IsEmpty() || !cspOldROHeaderValue.IsEmpty();
- bool newHeaderIsPresent = !cspHeaderValue.IsEmpty() || !cspROHeaderValue.IsEmpty();
-
- if (oldHeaderIsPresent && newHeaderIsPresent) {
- mCSPWebConsoleErrorQueue.Add("BothCSPHeadersPresent");
- } else if (oldHeaderIsPresent) {
- mCSPWebConsoleErrorQueue.Add("OldCSPHeaderDeprecated");
- }
// Figure out if we need to apply an app default CSP or a CSP from an app manifest
nsIPrincipal* principal = NodePrincipal();
@@ -2760,9 +2722,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
if (!applyAppDefaultCSP &&
!applyAppManifestCSP &&
cspHeaderValue.IsEmpty() &&
- cspROHeaderValue.IsEmpty() &&
- cspOldHeaderValue.IsEmpty() &&
- cspOldROHeaderValue.IsEmpty()) {
+ cspROHeaderValue.IsEmpty()) {
#ifdef PR_LOGGING
nsCOMPtr chanURI;
aChannel->GetURI(getter_AddRefs(chanURI));
@@ -2812,7 +2772,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
// * however, we still support XCSP headers during the transition phase
// and fall back to the JS implementation if we find an XCSP header.
- if (newHeaderIsPresent && CSPService::sNewBackendEnabled) {
+ if (CSPService::sNewBackendEnabled) {
csp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
}
else {
@@ -2845,36 +2805,25 @@ nsDocument::InitCSP(nsIChannel* aChannel)
}
if (appCSP) {
- // Use the 1.0 CSP parser for apps if the pref to do so is set.
- csp->AppendPolicy(appCSP, selfURI, false, specCompliantEnabled);
+ csp->AppendPolicy(appCSP, selfURI, false, true);
}
}
// ----- if the doc is an app and specifies a CSP in its manifest, apply it.
if (applyAppManifestCSP) {
- // Use the 1.0 CSP parser for apps if the pref to do so is set.
- csp->AppendPolicy(appManifestCSP, selfURI, false, specCompliantEnabled);
+ csp->AppendPolicy(appManifestCSP, selfURI, false, true);
}
- // While we are supporting both CSP 1.0 and the x- headers, the 1.0 headers
- // take priority. If both are present, the x-* headers are ignored.
-
// ----- if there's a full-strength CSP header, apply it.
if (!cspHeaderValue.IsEmpty()) {
rv = AppendCSPFromHeader(csp, cspHeaderValue, selfURI, false, true);
NS_ENSURE_SUCCESS(rv, rv);
- } else if (!cspOldHeaderValue.IsEmpty()) {
- rv = AppendCSPFromHeader(csp, cspOldHeaderValue, selfURI, false, false);
- NS_ENSURE_SUCCESS(rv, rv);
}
// ----- if there's a report-only CSP header, apply it.
if (!cspROHeaderValue.IsEmpty()) {
rv = AppendCSPFromHeader(csp, cspROHeaderValue, selfURI, true, true);
NS_ENSURE_SUCCESS(rv, rv);
- } else if (!cspOldROHeaderValue.IsEmpty()) {
- rv = AppendCSPFromHeader(csp, cspOldROHeaderValue, selfURI, true, false);
- NS_ENSURE_SUCCESS(rv, rv);
}
// ----- Enforce frame-ancestor policy on any applied policies
diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h
index c6c8864fa191..5e1e505e224f 100644
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -1715,7 +1715,7 @@ private:
nsRefPtr mImportManager;
#ifdef DEBUG
-protected:
+public:
bool mWillReparent;
#endif
};
diff --git a/content/base/test/moz.build b/content/base/test/moz.build
index f1a059ae904b..9a8b309ce7eb 100644
--- a/content/base/test/moz.build
+++ b/content/base/test/moz.build
@@ -6,7 +6,6 @@
TEST_TOOL_DIRS += [
'csp',
- 'xcsp',
'websocket_hybi',
]
diff --git a/content/base/test/unit/test_bug558431.js b/content/base/test/unit/test_bug558431.js
deleted file mode 100644
index 2842f3cabf4e..000000000000
--- a/content/base/test/unit/test_bug558431.js
+++ /dev/null
@@ -1,163 +0,0 @@
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cr = Components.results;
-
-Cu.import('resource://gre/modules/CSPUtils.jsm');
-
-var httpserv = null;
-
-const POLICY_FROM_URI = "allow 'self'; img-src *";
-const POLICY_PORT = 9000;
-const POLICY_URI = "http://localhost:" + POLICY_PORT + "/policy";
-const POLICY_URI_RELATIVE = "/policy";
-const DOCUMENT_URI = "http://localhost:" + POLICY_PORT + "/document";
-const CSP_DOC_BODY = "CSP doc content";
-const SD = CSPRep.SRC_DIRECTIVES;
-
-// this will get populated by run_tests()
-var TESTS = [];
-
-// helper to make URIs
-function mkuri(foo) {
- return Cc["@mozilla.org/network/io-service;1"]
- .getService(Ci.nsIIOService)
- .newURI(foo, null, null);
-}
-
-// helper to use .equals on stuff
-function do_check_equivalent(foo, bar, stack) {
- if (!stack)
- stack = Components.stack.caller;
-
- var text = foo + ".equals(" + bar + ")";
-
- if (foo.equals && foo.equals(bar)) {
- dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
- stack.lineNumber + "] " + text + "\n");
- return;
- }
- do_throw(text, stack);
-}
-
-function listener(csp, cspr_static) {
- this.buffer = "";
- this._csp = csp;
- this._cspr_static = cspr_static;
-}
-
-listener.prototype = {
- onStartRequest: function (request, ctx) {
- },
-
- onDataAvailable: function (request, ctx, stream, offset, count) {
- var sInputStream = Cc["@mozilla.org/scriptableinputstream;1"]
- .createInstance(Ci.nsIScriptableInputStream);
- sInputStream.init(stream);
- this.buffer = this.buffer.concat(sInputStream.read(count));
- },
-
- onStopRequest: function (request, ctx, status) {
- // make sure that we have the full document content, guaranteeing that
- // the document channel has been resumed, before we do the comparisons
- if (this.buffer == CSP_DOC_BODY) {
-
- // need to re-grab cspr since it may have changed inside the document's
- // nsIContentSecurityPolicy instance. The problem is, this cspr_str is a
- // string and not a policy due to the way it's exposed from
- // nsIContentSecurityPolicy, so we have to re-parse it.
- let cspr_str = this._csp.getPolicy(0);
- let cspr = CSPRep.fromString(cspr_str, mkuri(DOCUMENT_URI));
-
- // and in reparsing it, we lose the 'self' relationships, so need to also
- // reparse the static one (or find a way to resolve 'self' in the parsed
- // policy when doing comparisons).
- let cspr_static_str = this._cspr_static.toString();
- let cspr_static_reparse = CSPRep.fromString(cspr_static_str, mkuri(DOCUMENT_URI));
-
- // not null, and one policy .equals the other one
- do_check_neq(null, cspr);
- do_check_true(cspr.equals(cspr_static_reparse));
-
- // final teardown
- if (TESTS.length == 0) {
- httpserv.stop(do_test_finished);
- } else {
- do_test_finished();
- (TESTS.shift())();
- }
- }
- }
-};
-
-function run_test() {
- httpserv = new HttpServer();
- httpserv.registerPathHandler("/document", csp_doc_response);
- httpserv.registerPathHandler("/policy", csp_policy_response);
- httpserv.start(POLICY_PORT);
- TESTS = [ test_CSPRep_fromPolicyURI, test_CSPRep_fromRelativePolicyURI ];
-
- // when this triggers the "onStopRequest" callback, it'll
- // go to the next test.
- (TESTS.shift())();
-}
-
-function makeChan(url) {
- var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
- var chan = ios.newChannel(url, null, null).QueryInterface(Ci.nsIHttpChannel);
- return chan;
-}
-
-function csp_doc_response(metadata, response) {
- response.setStatusLine(metadata.httpVersion, 200, "OK");
- response.setHeader("Content-Type", "text/html", false);
- response.bodyOutputStream.write(CSP_DOC_BODY, CSP_DOC_BODY.length);
-}
-
-function csp_policy_response(metadata, response) {
- response.setStatusLine(metadata.httpVersion, 200, "OK");
- response.setHeader("Content-Type", "text/csp", false);
- response.bodyOutputStream.write(POLICY_FROM_URI, POLICY_FROM_URI.length);
-}
-
-///////////////////// TEST POLICY_URI //////////////////////
-function test_CSPRep_fromPolicyURI() {
- do_test_pending();
- let csp = Cc["@mozilla.org/contentsecuritypolicy;1"]
- .createInstance(Ci.nsIContentSecurityPolicy);
- // once the policy-uri is returned we will compare our static CSPRep with one
- // we generated from the content we got back from the network to make sure
- // they are equivalent
- let cspr_static = CSPRep.fromString(POLICY_FROM_URI, mkuri(DOCUMENT_URI));
-
- // simulates the request for the parent document
- var docChan = makeChan(DOCUMENT_URI);
- docChan.asyncOpen(new listener(csp, cspr_static), null);
-
- // the resulting policy here can be discarded, since it's going to be
- // "allow *"; when the policy-uri fetching call-back happens, the *real*
- // policy will be in csp.policy
- CSPRep.fromString("policy-uri " + POLICY_URI,
- mkuri(DOCUMENT_URI), false, docChan, csp);
-}
-
-function test_CSPRep_fromRelativePolicyURI() {
- do_test_pending();
- let csp = Cc["@mozilla.org/contentsecuritypolicy;1"]
- .createInstance(Ci.nsIContentSecurityPolicy);
- // once the policy-uri is returned we will compare our static CSPRep with one
- // we generated from the content we got back from the network to make sure
- // they are equivalent
- let cspr_static = CSPRep.fromString(POLICY_FROM_URI, mkuri(DOCUMENT_URI));
-
- // simulates the request for the parent document
- var docChan = makeChan(DOCUMENT_URI);
- docChan.asyncOpen(new listener(csp, cspr_static), null);
-
- // the resulting policy here can be discarded, since it's going to be
- // "allow *"; when the policy-uri fetching call-back happens, the *real*
- // policy will be in csp.policy
- CSPRep.fromString("policy-uri " + POLICY_URI_RELATIVE,
- mkuri(DOCUMENT_URI), false, docChan, csp);
-}
diff --git a/content/base/test/unit/test_csp_ignores_path.js b/content/base/test/unit/test_csp_ignores_path.js
index 7c514f2b39c5..d76e27fcaef4 100644
--- a/content/base/test/unit/test_csp_ignores_path.js
+++ b/content/base/test/unit/test_csp_ignores_path.js
@@ -27,7 +27,7 @@ function testValidSRCsHostSourceWithSchemeAndPath() {
]
var obj;
- var expected = "http://test1.example.com:80";
+ var expected = "http://test1.example.com";
for (let i in csps) {
var src = csps[i];
obj = CSPSourceList.fromString(src, undefined, self);
@@ -53,7 +53,7 @@ function testValidSRCsRegularHost() {
]
var obj;
- var expected = "http://test1.example.com:80";
+ var expected = "http://test1.example.com";
for (let i in csps) {
var src = csps[i];
obj = CSPSourceList.fromString(src, undefined, self);
@@ -77,7 +77,7 @@ function testValidSRCsWildCardHost() {
]
var obj;
- var expected = "http://*.example.com:80";
+ var expected = "http://*.example.com";
for (let i in csps) {
var src = csps[i];
obj = CSPSourceList.fromString(src, undefined, self);
@@ -99,7 +99,7 @@ function testValidSRCsRegularPort() {
]
var obj;
- var expected = "http://test1.example.com:80";
+ var expected = "http://test1.example.com";
for (let i in csps) {
var src = csps[i];
obj = CSPSourceList.fromString(src, undefined, self);
diff --git a/content/base/test/unit/test_cspreports.js b/content/base/test/unit/test_cspreports.js
index 7be4b9aad27c..20e752a5dbf7 100644
--- a/content/base/test/unit/test_cspreports.js
+++ b/content/base/test/unit/test_cspreports.js
@@ -63,8 +63,9 @@ function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) {
// set up a new CSP instance for each test.
var csp = Cc["@mozilla.org/contentsecuritypolicy;1"]
+ //var csp = Cc["@mozilla.org/cspcontext;1"]
.createInstance(Ci.nsIContentSecurityPolicy);
- var policy = "allow 'none'; " +
+ var policy = "default-src 'none'; " +
"report-uri " + REPORT_SERVER_URI +
":" + REPORT_SERVER_PORT +
"/test" + id;
@@ -80,7 +81,7 @@ function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) {
// Load up the policy
// set as report-only if that's the case
- csp.appendPolicy(policy, selfuri, useReportOnlyPolicy, false);
+ csp.appendPolicy(policy, selfuri, useReportOnlyPolicy, true);
// prime the report server
var handler = makeReportHandler("/test" + id, "Test " + id, expectedJSON);
diff --git a/content/base/test/unit/test_csputils.js b/content/base/test/unit/test_csputils.js
index f4731df6833a..0d0002bb6a49 100644
--- a/content/base/test/unit/test_csputils.js
+++ b/content/base/test/unit/test_csputils.js
@@ -35,7 +35,7 @@ function do_check_in_array(arr, val, stack) {
var text = val + " in [" + arr.join(",") + "]";
for(var i in arr) {
- dump(".......... " + i + "> " + arr[i] + "\n");
+ //dump(".......... " + i + "> " + arr[i] + "\n");
if(arr[i] == val) {
//succeed
++_passedChecks;
@@ -261,7 +261,7 @@ test(
test(
function test_CSPSourceList_fromString_twohost() {
var str = "foo.bar:21 https://ras.bar";
- var parsed = "http://foo.bar:21 https://ras.bar:443";
+ var parsed = "http://foo.bar:21 https://ras.bar";
var sd = CSPSourceList.fromString(str, undefined, URI("http://self.com:80"));
//"two-host list should parse"
do_check_neq(null,sd);
@@ -321,43 +321,26 @@ test(
do_check_false(wildcardHostSourceList.permits("http://barbaz.com"));
});
-///////////////////// Test the Whole CSP rep object //////////////////////
-
+//////////////// TEST CSP REP SPEC COMPLIANT PARSER ////////////
test(
function test_CSPRep_fromString() {
- // check default init
- //ASSERT(!(new CSPRep())._isInitialized, "Uninitialized rep thinks it is.")
-
var cspr;
var cspr_allowval;
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
+ var SD = CSPRep.SRC_DIRECTIVES;
+ var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC, SD.SCRIPT_SRC, SD.FONT_SRC,
+ SD.OBJECT_SRC, SD.FRAME_SRC, SD.CONNECT_SRC];
- // check default policy "allow *"
- cspr = CSPRep.fromString("allow *", URI("http://self.com:80"));
- // "DEFAULT_SRC directive is missing when specified in fromString"
- do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
-
- });
-
-
-test(
- function test_CSPRep_defaultSrc() {
- var cspr, cspr_default_val, cspr_allow;
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
-
- // apply policy of "default-src *" (e.g. "allow *")
+ // check default policy "default-src *"
cspr = CSPRep.fromString("default-src *", URI("http://self.com:80"));
// "DEFAULT_SRC directive is missing when specified in fromString"
do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
- // check that |allow *| and |default-src *| are parsed equivalently and
- // result in the same set of explicit policy directives
- cspr = CSPRep.fromString("default-src *", URI("http://self.com:80"));
- cspr_allow = CSPRep.fromString("allow *", URI("http://self.com:80"));
-
- do_check_equivalent(cspr._directives['default-src'],
- cspr_allow._directives['default-src']);
+ for(var x in DEFAULTS) {
+ // each of these should be equivalent to DEFAULT_SRC
+ //DEFAULTS[x] + " does not use default rule."
+ do_check_true(cspr.permits("http://bar.com", DEFAULTS[x]));
+ }
});
@@ -365,11 +348,12 @@ test(
function test_CSPRep_fromString_oneDir() {
var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
- var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC, SD.FRAME_SRC];
+ var SD = CSPRep.SRC_DIRECTIVES;
+ var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC,
+ SD.FRAME_SRC, SD.CONNECT_SRC];
// check one-directive policies
- cspr = CSPRep.fromString("allow bar.com; script-src https://foo.com",
+ cspr = CSPRep.fromString("default-src bar.com; script-src https://foo.com",
URI("http://self.com"));
for(var x in DEFAULTS) {
@@ -389,15 +373,18 @@ test(
});
test(
- function test_CSPRep_fromString_twodir() {
+ function test_CSPRep_fromString_twoDir() {
var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
- var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.FRAME_SRC];
+
+ var SD = CSPRep.SRC_DIRECTIVES;
+
+ var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.FRAME_SRC,
+ SD.CONNECT_SRC];
// check two-directive policies
- var polstr = "allow allow.com; "
- + "script-src https://foo.com; "
- + "img-src bar.com:*";
+ var polstr = "default-src allow.com; " +
+ "script-src https://foo.com; " +
+ "img-src bar.com:*";
cspr = CSPRep.fromString(polstr, URI("http://self.com"));
for(var x in DEFAULTS) {
@@ -425,123 +412,12 @@ test(
test(function test_CSPRep_fromString_withself() {
var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
var self = "https://self.com:34";
+ var SD = CSPRep.SRC_DIRECTIVES;
// check one-directive policies
- cspr = CSPRep.fromString("allow 'self'; script-src 'self' https://*:*",
- URI(self));
- //"img-src does not enforce default rule, 'self'.
- do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
- //"img-src does not allow self
- do_check_true(cspr.permits(self, SD.IMG_SRC));
- //"script-src is too relaxed
- do_check_false(cspr.permits("http://evil.com", SD.SCRIPT_SRC));
- //"script-src should allow self
- do_check_true(cspr.permits(self, SD.SCRIPT_SRC));
- //"script-src is too strict on host/port
- do_check_true(cspr.permits("https://evil.com:100", SD.SCRIPT_SRC));
- });
-
-
-//////////////// TEST CSP REP SPEC COMPLIANT PARSER ////////////
-test(
- function test_CSPRep_fromStringSpecCompliant() {
-
- var cspr;
- var cspr_allowval;
- var SD = CSPRep.SRC_DIRECTIVES_NEW;
- var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC, SD.SCRIPT_SRC, SD.FONT_SRC,
- SD.OBJECT_SRC, SD.FRAME_SRC, SD.CONNECT_SRC];
-
- // check default policy "default-src *"
- cspr = CSPRep.fromStringSpecCompliant("default-src *", URI("http://self.com:80"));
- // "DEFAULT_SRC directive is missing when specified in
- // fromStringSpecCompliant"
- do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
-
- for(var x in DEFAULTS) {
- // each of these should be equivalent to DEFAULT_SRC
- //DEFAULTS[x] + " does not use default rule."
- do_check_true(cspr.permits("http://bar.com", DEFAULTS[x]));
- }
- });
-
-
-test(
- function test_CSPRep_fromStringSpecCompliant_oneDir() {
-
- var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_NEW;
- var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC,
- SD.FRAME_SRC, SD.CONNECT_SRC];
-
- // check one-directive policies
- cspr = CSPRep.fromStringSpecCompliant("default-src bar.com; script-src https://foo.com",
- URI("http://self.com"));
-
- for(var x in DEFAULTS) {
- //DEFAULTS[x] + " does not use default rule."
- do_check_false(cspr.permits("http://bar.com:22", DEFAULTS[x]));
- //DEFAULTS[x] + " does not use default rule."
- do_check_true(cspr.permits("http://bar.com:80", DEFAULTS[x]));
- //DEFAULTS[x] + " does not use default rule."
- do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
- //DEFAULTS[x] + " does not use default rule."
- do_check_false(cspr.permits("https://foo.com", DEFAULTS[x]));
- }
- //"script-src false positive in policy.
- do_check_false(cspr.permits("http://bar.com:22", SD.SCRIPT_SRC));
- //"script-src false negative in policy.
- do_check_true(cspr.permits("https://foo.com:443", SD.SCRIPT_SRC));
- });
-
-test(
- function test_CSPRep_fromStringSpecCompliant_twodir() {
- var cspr;
-
- var SD = CSPRep.SRC_DIRECTIVES_NEW;
-
- var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.FRAME_SRC,
- SD.CONNECT_SRC];
-
- // check two-directive policies
- var polstr = "default-src allow.com; " +
- "script-src https://foo.com; " +
- "img-src bar.com:*";
- cspr = CSPRep.fromStringSpecCompliant(polstr, URI("http://self.com"));
-
- for(var x in DEFAULTS) {
- do_check_true(cspr.permits("http://allow.com", DEFAULTS[x]));
- //DEFAULTS[x] + " does not use default rule.
- do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
- //DEFAULTS[x] + " does not use default rule.
- do_check_false(cspr.permits("http://bar.com:400", DEFAULTS[x]));
- //DEFAULTS[x] + " does not use default rule.
- }
- //"img-src does not use default rule.
- do_check_false(cspr.permits("http://allow.com:22", SD.IMG_SRC));
- //"img-src does not use default rule.
- do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
- //"img-src does not use default rule.
- do_check_true(cspr.permits("http://bar.com:88", SD.IMG_SRC));
-
- //"script-src does not use default rule.
- do_check_false(cspr.permits("http://allow.com:22", SD.SCRIPT_SRC));
- //"script-src does not use default rule.
- do_check_true(cspr.permits("https://foo.com:443", SD.SCRIPT_SRC));
- //"script-src does not use default rule.
- do_check_false(cspr.permits("http://bar.com:400", SD.SCRIPT_SRC));
- });
-
-test(function test_CSPRep_fromStringSpecCompliant_withself() {
- var cspr;
- var self = "https://self.com:34";
- var SD = CSPRep.SRC_DIRECTIVES_NEW;
-
- // check one-directive policies
- cspr = CSPRep.fromStringSpecCompliant("default-src 'self'; script-src 'self' https://*:*",
- URI(self));
+ cspr = CSPRep.fromString("default-src 'self'; script-src 'self' https://*:*",
+ URI(self));
//"img-src does not enforce default rule, 'self'.
do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
//"img-src does not allow self
@@ -559,34 +435,10 @@ test(function test_CSPRep_fromStringSpecCompliant_withself() {
// (see bug 555068)
test(function test_FrameAncestor_defaults() {
var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
var self = "http://self.com:34";
+ var SD = CSPRep.SRC_DIRECTIVES;
- cspr = CSPRep.fromString("allow 'none'", URI(self));
-
- //"frame-ancestors should default to * not 'allow' value"
- do_check_true(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
- do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
- do_check_true(cspr.permits("https://self.com:34", SD.FRAME_ANCESTORS));
- do_check_true(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
- do_check_true(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
-
- cspr = CSPRep.fromString("allow 'none'; frame-ancestors 'self'", URI(self));
-
- //"frame-ancestors should only allow self"
- do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
- do_check_false(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
- do_check_false(cspr.permits("https://self.com:34", SD.FRAME_ANCESTORS));
- do_check_false(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
- do_check_false(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
- });
-
-test(function test_FrameAncestor_defaults_specCompliant() {
- var cspr;
- var self = "http://self.com:34";
- var SD = CSPRep.SRC_DIRECTIVES_NEW;
-
- cspr = CSPRep.fromStringSpecCompliant("default-src 'none'", URI(self));
+ cspr = CSPRep.fromString("default-src 'none'", URI(self));
//"frame-ancestors should default to * not 'default-src' value"
do_check_true(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
@@ -595,7 +447,7 @@ test(function test_FrameAncestor_defaults_specCompliant() {
do_check_true(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
do_check_true(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
- cspr = CSPRep.fromStringSpecCompliant("default-src 'none'; frame-ancestors 'self'", URI(self));
+ cspr = CSPRep.fromString("default-src 'none'; frame-ancestors 'self'", URI(self));
//"frame-ancestors should only allow self"
do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
@@ -608,10 +460,10 @@ test(function test_FrameAncestor_defaults_specCompliant() {
test(function test_FrameAncestor_TLD_defaultPorts() {
var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
+ var SD = CSPRep.SRC_DIRECTIVES;
var self = "http://self"; //TLD only, no .com or anything.
- cspr = CSPRep.fromString("allow 'self'; frame-ancestors 'self' http://foo:80 bar:80 http://three", URI(self));
+ cspr = CSPRep.fromString("default-src 'self'; frame-ancestors 'self' http://foo:80 bar:80 http://three", URI(self));
//"frame-ancestors should default to * not 'allow' value"
do_check_true(cspr.permits("http://self", SD.FRAME_ANCESTORS));
@@ -630,7 +482,7 @@ test(function test_FrameAncestor_TLD_defaultPorts() {
test(function test_FrameAncestor_ignores_userpass_bug779918() {
var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
+ var SD = CSPRep.SRC_DIRECTIVES;
var self = "http://self.com/bar";
var testPolicy = "default-src 'self'; frame-ancestors 'self'";
@@ -678,7 +530,7 @@ test(function test_FrameAncestor_ignores_userpass_bug779918() {
test(function test_CSP_ReportURI_parsing() {
var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_NEW;
+ var SD = CSPRep.SRC_DIRECTIVES;
var self = "http://self.com:34";
var parsedURIs = [];
@@ -692,48 +544,48 @@ test(function test_CSP_ReportURI_parsing() {
var uri_other_scheme_absolute = "https://self.com/report.py";
var uri_other_scheme_and_host_absolute = "https://foo.com/report.py";
- cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_valid_absolute, URI(self));
+ cspr = CSPRep.fromString("default-src *; report-uri " + uri_valid_absolute, URI(self));
parsedURIs = cspr.getReportURIs().split(/\s+/);
do_check_in_array(parsedURIs, uri_valid_absolute);
do_check_eq(parsedURIs.length, 1);
- cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_other_host_absolute, URI(self));
+ cspr = CSPRep.fromString("default-src *; report-uri " + uri_other_host_absolute, URI(self));
parsedURIs = cspr.getReportURIs().split(/\s+/);
do_check_in_array(parsedURIs, uri_other_host_absolute);
do_check_eq(parsedURIs.length, 1); // the empty string is in there.
- cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_invalid_relative, URI(self));
+ cspr = CSPRep.fromString("default-src *; report-uri " + uri_invalid_relative, URI(self));
parsedURIs = cspr.getReportURIs().split(/\s+/);
do_check_in_array(parsedURIs, "");
do_check_eq(parsedURIs.length, 1);
- cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_valid_relative, URI(self));
+ cspr = CSPRep.fromString("default-src *; report-uri " + uri_valid_relative, URI(self));
parsedURIs = cspr.getReportURIs().split(/\s+/);
do_check_in_array(parsedURIs, uri_valid_relative_expanded);
do_check_eq(parsedURIs.length, 1);
- cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_valid_relative2, URI(self));
+ cspr = CSPRep.fromString("default-src *; report-uri " + uri_valid_relative2, URI(self));
parsedURIs = cspr.getReportURIs().split(/\s+/);
dump(parsedURIs.length);
do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
do_check_eq(parsedURIs.length, 1);
// make sure cross-scheme reporting works
- cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_other_scheme_absolute, URI(self));
+ cspr = CSPRep.fromString("default-src *; report-uri " + uri_other_scheme_absolute, URI(self));
parsedURIs = cspr.getReportURIs().split(/\s+/);
dump(parsedURIs.length);
do_check_in_array(parsedURIs, uri_other_scheme_absolute);
do_check_eq(parsedURIs.length, 1);
// make sure cross-scheme, cross-host reporting works
- cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_other_scheme_and_host_absolute, URI(self));
+ cspr = CSPRep.fromString("default-src *; report-uri " + uri_other_scheme_and_host_absolute, URI(self));
parsedURIs = cspr.getReportURIs().split(/\s+/);
dump(parsedURIs.length);
do_check_in_array(parsedURIs, uri_other_scheme_and_host_absolute);
do_check_eq(parsedURIs.length, 1);
// combination!
- cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " +
+ cspr = CSPRep.fromString("default-src *; report-uri " +
uri_valid_relative2 + " " +
uri_valid_absolute, URI(self));
parsedURIs = cspr.getReportURIs().split(/\s+/);
@@ -741,7 +593,7 @@ test(function test_CSP_ReportURI_parsing() {
do_check_in_array(parsedURIs, uri_valid_absolute);
do_check_eq(parsedURIs.length, 2);
- cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " +
+ cspr = CSPRep.fromString("default-src *; report-uri " +
uri_valid_relative2 + " " +
uri_other_host_absolute + " " +
uri_valid_absolute, URI(self));
@@ -755,32 +607,22 @@ test(function test_CSP_ReportURI_parsing() {
test(
function test_bug634778_duplicateDirective_Detection() {
var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_OLD;
+ var SD = CSPRep.SRC_DIRECTIVES;
var self = "http://self.com:34";
var firstDomain = "http://first.com";
var secondDomain = "http://second.com";
var thirdDomain = "http://third.com";
// check for duplicate "default-src" directives
+ // Spec says first directive persists (subsequent re-statement is
+ // ignored)
cspr = CSPRep.fromString("default-src " + self + "; default-src " +
firstDomain, URI(self));
do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
do_check_false(cspr.permits(firstDomain, SD.DEFAULT_SRC));
- // check for duplicate "allow" directives
- cspr = CSPRep.fromString("allow " + self + "; allow " + firstDomain,
- URI(self));
- do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
- do_check_false(cspr.permits(firstDomain, SD.DEFAULT_SRC));
-
- // check for duplicate "allow" + "default-src" directives
- cspr = CSPRep.fromString("allow " + self + "; default-src " + firstDomain,
- URI(self));
- do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
- do_check_false(cspr.permits(firstDomain, SD.DEFAULT_SRC));
-
// check for duplicate report-uri directives
- cspr = CSPRep.fromString("allow *; report-uri " + self + "/report.py; report-uri "
+ cspr = CSPRep.fromString("default-src *; report-uri " + self + "/report.py; report-uri "
+ firstDomain + "/report.py", URI(self));
parsedURIs = cspr.getReportURIs().split(/\s+/);
do_check_in_array(parsedURIs, self + "/report.py");
@@ -896,9 +738,7 @@ test(
test(
function test_bug764937_defaultSrcMissing() {
- var cspObjSpecCompliant = Cc["@mozilla.org/contentsecuritypolicy;1"]
- .createInstance(Ci.nsIContentSecurityPolicy);
- var cspObjOld = Cc["@mozilla.org/contentsecuritypolicy;1"]
+ var cspObj = Cc["@mozilla.org/contentsecuritypolicy;1"]
.createInstance(Ci.nsIContentSecurityPolicy);
var selfURI = URI("http://self.com/");
@@ -908,39 +748,21 @@ test(
};
const policy = "script-src 'self'";
- cspObjSpecCompliant.appendPolicy(policy, selfURI, false, true);
+ cspObj.appendPolicy(policy, selfURI, false, true);
// Spec-Compliant policy default-src defaults to *.
// This means all images are allowed, and only 'self'
// script is allowed.
- do_check_true(testPermits(cspObjSpecCompliant,
+ do_check_true(testPermits(cspObj,
URI("http://bar.com/foo.png"),
Ci.nsIContentPolicy.TYPE_IMAGE));
- do_check_true(testPermits(cspObjSpecCompliant,
+ do_check_true(testPermits(cspObj,
URI("http://self.com/foo.png"),
Ci.nsIContentPolicy.TYPE_IMAGE));
- do_check_true(testPermits(cspObjSpecCompliant,
+ do_check_true(testPermits(cspObj,
URI("http://self.com/foo.js"),
Ci.nsIContentPolicy.TYPE_SCRIPT));
- do_check_false(testPermits(cspObjSpecCompliant,
- URI("http://bar.com/foo.js"),
- Ci.nsIContentPolicy.TYPE_SCRIPT));
-
- cspObjOld.appendPolicy(policy, selfURI, false, false);
-
- // non-Spec-Compliant policy default-src defaults to 'none'
- // This means all images are blocked, and so are all scripts (because the
- // policy is ignored and fails closed).
- do_check_false(testPermits(cspObjOld,
- URI("http://bar.com/foo.png"),
- Ci.nsIContentPolicy.TYPE_IMAGE));
- do_check_false(testPermits(cspObjOld,
- URI("http://self.com/foo.png"),
- Ci.nsIContentPolicy.TYPE_IMAGE));
- do_check_false(testPermits(cspObjOld,
- URI("http://self.com/foo.js"),
- Ci.nsIContentPolicy.TYPE_SCRIPT));
- do_check_false(testPermits(cspObjOld,
+ do_check_false(testPermits(cspObj,
URI("http://bar.com/foo.js"),
Ci.nsIContentPolicy.TYPE_SCRIPT));
@@ -955,10 +777,10 @@ test(function test_equals_does_case_insensitive_comparison() {
// CSPSource equals ignores case
var upperCaseHost = "http://FOO.COM";
var lowerCaseHost = "http://foo.com";
- src1 = CSPSource.fromString(lowerCaseHost);
- src2 = CSPSource.fromString(lowerCaseHost);
+ var src1 = CSPSource.fromString(lowerCaseHost);
+ var src2 = CSPSource.fromString(lowerCaseHost);
do_check_true(src1.equals(src2))
- src3 = CSPSource.fromString(upperCaseHost);
+ var src3 = CSPSource.fromString(upperCaseHost);
do_check_true(src1.equals(src3))
// CSPHost equals ignores case
@@ -983,7 +805,7 @@ test(function test_equals_does_case_insensitive_comparison() {
test(function test_csp_permits_case_insensitive() {
var cspr;
- var SD = CSPRep.SRC_DIRECTIVES_NEW;
+ var SD = CSPRep.SRC_DIRECTIVES;
// checks directives can be case-insensitive
var selfHost = "http://self.com";
@@ -1042,12 +864,15 @@ function run_test() {
httpServer.registerPathHandler("/policy", policyresponder);
for(let i in tests) {
- tests[i]();
+ add_task(tests[i]);
}
- //teardown
- httpServer.stop(function() { });
- do_test_finished();
+ do_register_cleanup(function () {
+ //teardown
+ httpServer.stop(function() { });
+ });
+
+ run_next_test();
}
diff --git a/content/base/test/unit/xpcshell.ini b/content/base/test/unit/xpcshell.ini
index fa8717b221ca..b0951dbb278a 100644
--- a/content/base/test/unit/xpcshell.ini
+++ b/content/base/test/unit/xpcshell.ini
@@ -21,7 +21,6 @@ support-files =
4_result_6.xml
[test_bug553888.js]
-[test_bug558431.js]
[test_bug737966.js]
[test_csputils.js]
[test_cspreports.js]
diff --git a/content/base/test/xcsp/chrome.ini b/content/base/test/xcsp/chrome.ini
deleted file mode 100644
index fb55f3e12726..000000000000
--- a/content/base/test/xcsp/chrome.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-
-[test_csp_bug768029.html]
-[test_csp_bug773891.html]
diff --git a/content/base/test/xcsp/file_CSP.css b/content/base/test/xcsp/file_CSP.css
deleted file mode 100644
index 25e1a5b9dacc..000000000000
--- a/content/base/test/xcsp/file_CSP.css
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Moved this CSS from an inline stylesheet to an external file when we added
- * inline-style blocking in bug 763879.
- * This test may hang if the load for this .css file is blocked due to a
- * malfunction of CSP, but should pass if the style_good test passes.
- */
-
-/* CSS font embedding tests */
-@font-face {
- font-family: "arbitrary_good";
- src: url('file_CSP.sjs?testid=font_good&type=application/octet-stream');
-}
-@font-face {
- font-family: "arbitrary_bad";
- src: url('http://example.org/tests/content/base/test/xcsp/file_CSP.sjs?testid=font_bad&type=application/octet-stream');
-}
-
-.div_arbitrary_good { font-family: "arbitrary_good"; }
-.div_arbitrary_bad { font-family: "arbitrary_bad"; }
-
diff --git a/content/base/test/xcsp/file_CSP.sjs b/content/base/test/xcsp/file_CSP.sjs
deleted file mode 100644
index 85c2df3ba474..000000000000
--- a/content/base/test/xcsp/file_CSP.sjs
+++ /dev/null
@@ -1,26 +0,0 @@
-// SJS file for CSP mochitests
-
-function handleRequest(request, response)
-{
- var query = {};
- request.queryString.split('&').forEach(function (val) {
- var [name, value] = val.split('=');
- query[name] = unescape(value);
- });
-
- var isPreflight = request.method == "OPTIONS";
-
-
- //avoid confusing cache behaviors
- response.setHeader("Cache-Control", "no-cache", false);
-
- if ("type" in query) {
- response.setHeader("Content-Type", unescape(query['type']), false);
- } else {
- response.setHeader("Content-Type", "text/html", false);
- }
-
- if ("content" in query) {
- response.write(unescape(query['content']));
- }
-}
diff --git a/content/base/test/xcsp/file_CSP_bug916446.html b/content/base/test/xcsp/file_CSP_bug916446.html
deleted file mode 100644
index bc8bdb3ad502..000000000000
--- a/content/base/test/xcsp/file_CSP_bug916446.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
Inline script (green if allowed, black if blocked)
-
-
-
-
-
-
-
-
diff --git a/content/base/test/xcsp/file_CSP_bug916446.html^headers^ b/content/base/test/xcsp/file_CSP_bug916446.html^headers^
deleted file mode 100644
index 888789cb6fec..000000000000
--- a/content/base/test/xcsp/file_CSP_bug916446.html^headers^
+++ /dev/null
@@ -1 +0,0 @@
-x-content-security-policy-report-only: options eval-script; script-src 'self' ; report-uri /csp_report
diff --git a/content/base/test/xcsp/file_CSP_evalscript_main.html b/content/base/test/xcsp/file_CSP_evalscript_main.html
deleted file mode 100644
index 15495296109f..000000000000
--- a/content/base/test/xcsp/file_CSP_evalscript_main.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- CSP eval script tests
-
-
-
-
- Foo.
-
-
-
diff --git a/content/base/test/xcsp/file_CSP_evalscript_main.html^headers^ b/content/base/test/xcsp/file_CSP_evalscript_main.html^headers^
deleted file mode 100644
index a9c761cfc144..000000000000
--- a/content/base/test/xcsp/file_CSP_evalscript_main.html^headers^
+++ /dev/null
@@ -1,2 +0,0 @@
-Cache-Control: no-cache
-X-Content-Security-Policy: default-src 'self'
diff --git a/content/base/test/xcsp/file_CSP_evalscript_main.js b/content/base/test/xcsp/file_CSP_evalscript_main.js
deleted file mode 100644
index a00fbb8362e5..000000000000
--- a/content/base/test/xcsp/file_CSP_evalscript_main.js
+++ /dev/null
@@ -1,126 +0,0 @@
-// some javascript for the CSP eval() tests
-
-function logResult(str, passed) {
- var elt = document.createElement('div');
- var color = passed ? "#cfc;" : "#fcc";
- elt.setAttribute('style', 'background-color:' + color + '; width:100%; border:1px solid black; padding:3px; margin:4px;');
- elt.innerHTML = str;
- document.body.appendChild(elt);
-}
-
-window._testResults = {};
-
-// callback for when stuff is allowed by CSP
-var onevalexecuted = (function(window) {
- return function(shouldrun, what, data) {
- window._testResults[what] = "ran";
- window.parent.scriptRan(shouldrun, what, data);
- logResult((shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data, shouldrun);
- };})(window);
-
-// callback for when stuff is blocked
-var onevalblocked = (function(window) {
- return function(shouldrun, what, data) {
- window._testResults[what] = "blocked";
- window.parent.scriptBlocked(shouldrun, what, data);
- logResult((shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data, !shouldrun);
- };})(window);
-
-
-// Defer until document is loaded so that we can write the pretty result boxes
-// out.
-addEventListener('load', function() {
- // setTimeout(String) test -- mutate something in the window._testResults
- // obj, then check it.
- {
- var str_setTimeoutWithStringRan = 'onevalexecuted(false, "setTimeout(String)", "setTimeout with a string was enabled.");';
- function fcn_setTimeoutWithStringCheck() {
- if (this._testResults["setTimeout(String)"] !== "ran") {
- onevalblocked(false, "setTimeout(String)",
- "setTimeout with a string was blocked");
- }
- }
- setTimeout(fcn_setTimeoutWithStringCheck.bind(window), 10);
- setTimeout(str_setTimeoutWithStringRan, 10);
- }
-
- // setTimeout(function) test -- mutate something in the window._testResults
- // obj, then check it.
- {
- function fcn_setTimeoutWithFunctionRan() {
- onevalexecuted(true, "setTimeout(function)",
- "setTimeout with a function was enabled.")
- }
- function fcn_setTimeoutWithFunctionCheck() {
- if (this._testResults["setTimeout(function)"] !== "ran") {
- onevalblocked(true, "setTimeout(function)",
- "setTimeout with a function was blocked");
- }
- }
- setTimeout(fcn_setTimeoutWithFunctionRan.bind(window), 10);
- setTimeout(fcn_setTimeoutWithFunctionCheck.bind(window), 10);
- }
-
- // eval() test -- should throw exception as per spec
- try {
- eval('onevalexecuted(false, "eval(String)", "eval() was enabled.");');
- } catch (e) {
- onevalblocked(false, "eval(String)",
- "eval() was blocked");
- }
-
- // eval(foo,bar) test -- should throw exception as per spec
- try {
- eval('onevalexecuted(false, "eval(String,scope)", "eval() was enabled.");',1);
- } catch (e) {
- onevalblocked(false, "eval(String,object)",
- "eval() with scope was blocked");
- }
-
- // [foo,bar].sort(eval) test -- should throw exception as per spec
- try {
- ['onevalexecuted(false, "[String, obj].sort(eval)", "eval() was enabled.");',1].sort(eval);
- } catch (e) {
- onevalblocked(false, "[String, obj].sort(eval)",
- "eval() with scope via sort was blocked");
- }
-
- // [].sort.call([foo,bar], eval) test -- should throw exception as per spec
- try {
- [].sort.call(['onevalexecuted(false, "[String, obj].sort(eval)", "eval() was enabled.");',1], eval);
- } catch (e) {
- onevalblocked(false, "[].sort.call([String, obj], eval)",
- "eval() with scope via sort/call was blocked");
- }
-
- // new Function() test -- should throw exception as per spec
- try {
- var fcn = new Function('onevalexecuted(false, "new Function(String)", "new Function(String) was enabled.");');
- fcn();
- } catch (e) {
- onevalblocked(false, "new Function(String)",
- "new Function(String) was blocked.");
- }
-
- // setTimeout(eval, 0, str)
- {
- // error is not catchable here, instead, we're going to side-effect
- // 'worked'.
- var worked = false;
-
- setTimeout(eval, 0, 'worked = true');
- setTimeout(function(worked) {
- if (worked) {
- onevalexecuted(false, "setTimeout(eval, 0, str)",
- "setTimeout(eval, 0, string) was enabled.");
- } else {
- onevalblocked(false, "setTimeout(eval, 0, str)",
- "setTimeout(eval, 0, str) was blocked.");
- }
- }, 0, worked);
- }
-
-}, false);
-
-
-
diff --git a/content/base/test/xcsp/file_CSP_evalscript_main_getCRMFRequest.html b/content/base/test/xcsp/file_CSP_evalscript_main_getCRMFRequest.html
deleted file mode 100644
index 7b122389be54..000000000000
--- a/content/base/test/xcsp/file_CSP_evalscript_main_getCRMFRequest.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- CSP eval script tests
-
-
-
-
- Foo.
-
-
-
diff --git a/content/base/test/xcsp/file_CSP_evalscript_main_getCRMFRequest.html^headers^ b/content/base/test/xcsp/file_CSP_evalscript_main_getCRMFRequest.html^headers^
deleted file mode 100644
index a9c761cfc144..000000000000
--- a/content/base/test/xcsp/file_CSP_evalscript_main_getCRMFRequest.html^headers^
+++ /dev/null
@@ -1,2 +0,0 @@
-Cache-Control: no-cache
-X-Content-Security-Policy: default-src 'self'
diff --git a/content/base/test/xcsp/file_CSP_evalscript_main_getCRMFRequest.js b/content/base/test/xcsp/file_CSP_evalscript_main_getCRMFRequest.js
deleted file mode 100644
index 90826e3bc9de..000000000000
--- a/content/base/test/xcsp/file_CSP_evalscript_main_getCRMFRequest.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// some javascript for the CSP eval() tests
-
-function logResult(str, passed) {
- var elt = document.createElement('div');
- var color = passed ? "#cfc;" : "#fcc";
- elt.setAttribute('style', 'background-color:' + color + '; width:100%; border:1px solid black; padding:3px; margin:4px;');
- elt.innerHTML = str;
- document.body.appendChild(elt);
-}
-
-window._testResults = {};
-
-// callback for when stuff is allowed by CSP
-var onevalexecuted = (function(window) {
- return function(shouldrun, what, data) {
- window._testResults[what] = "ran";
- window.parent.scriptRan(shouldrun, what, data);
- logResult((shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data, shouldrun);
- };})(window);
-
-// callback for when stuff is blocked
-var onevalblocked = (function(window) {
- return function(shouldrun, what, data) {
- window._testResults[what] = "blocked";
- window.parent.scriptBlocked(shouldrun, what, data);
- logResult((shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data, !shouldrun);
- };})(window);
-
-
-// Defer until document is loaded so that we can write the pretty result boxes
-// out.
-addEventListener('load', function() {
- // generateCRMFRequest test -- make sure we cannot eval the callback if CSP is in effect
- try {
- var script = 'console.log("dynamic script eval\'d in crypto.generateCRMFRequest should be disallowed")';
- crypto.generateCRMFRequest('CN=0', 0, 0, null, script, 384, null, 'rsa-dual-use');
- onevalexecuted(false, "crypto.generateCRMFRequest()",
- "crypto.generateCRMFRequest() should not run!");
- } catch (e) {
- onevalblocked(false, "eval(script) inside crypto.generateCRMFRequest",
- "eval was blocked during crypto.generateCRMFRequest");
- }
-
-
-}, false);
-
-
-
diff --git a/content/base/test/xcsp/file_CSP_evalscript_no_CSP_at_all.html b/content/base/test/xcsp/file_CSP_evalscript_no_CSP_at_all.html
deleted file mode 100644
index d36aeaaf1064..000000000000
--- a/content/base/test/xcsp/file_CSP_evalscript_no_CSP_at_all.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- CSP eval script tests: no CSP specified
-
-
-
-
- Foo. See bug 824652
-
-
-
diff --git a/content/base/test/xcsp/file_CSP_evalscript_no_CSP_at_all.html^headers^ b/content/base/test/xcsp/file_CSP_evalscript_no_CSP_at_all.html^headers^
deleted file mode 100644
index 9e23c73b7ffb..000000000000
--- a/content/base/test/xcsp/file_CSP_evalscript_no_CSP_at_all.html^headers^
+++ /dev/null
@@ -1 +0,0 @@
-Cache-Control: no-cache
diff --git a/content/base/test/xcsp/file_CSP_evalscript_no_CSP_at_all.js b/content/base/test/xcsp/file_CSP_evalscript_no_CSP_at_all.js
deleted file mode 100644
index 520491fb8ef7..000000000000
--- a/content/base/test/xcsp/file_CSP_evalscript_no_CSP_at_all.js
+++ /dev/null
@@ -1,42 +0,0 @@
-// some javascript for the CSP eval() tests
-// all of these evals should succeed, as the document loading this script
-// has script-src 'self' 'unsafe-eval'
-
-function logResult(str, passed) {
- var elt = document.createElement('div');
- var color = passed ? "#cfc;" : "#fcc";
- elt.setAttribute('style', 'background-color:' + color + '; width:100%; border:1px solid black; padding:3px; margin:4px;');
- elt.innerHTML = str;
- document.body.appendChild(elt);
-}
-
-// callback for when stuff is allowed by CSP
-var onevalexecuted = (function(window) {
- return function(shouldrun, what, data) {
- window.parent.scriptRan(shouldrun, what, data);
- logResult((shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data, shouldrun);
- };})(window);
-
-// callback for when stuff is blocked
-var onevalblocked = (function(window) {
- return function(shouldrun, what, data) {
- window.parent.scriptBlocked(shouldrun, what, data);
- logResult((shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data, !shouldrun);
- };})(window);
-
-
-// Defer until document is loaded so that we can write the pretty result boxes
-// out.
-addEventListener('load', function() {
- // test that allows crypto.generateCRMFRequest eval to run when there is no CSP at all in place
- try {
- var script =
- 'console.log("dynamic script passed to crypto.generateCRMFRequest should execute")';
- crypto.generateCRMFRequest('CN=0', 0, 0, null, script, 384, null, 'rsa-dual-use');
- onevalexecuted(true, "eval(script) inside crypto.generateCRMFRequest: no CSP at all",
- "eval executed during crypto.generateCRMFRequest where no CSP is set at all");
- } catch (e) {
- onevalblocked(true, "eval(script) inside crypto.generateCRMFRequest",
- "eval was blocked during crypto.generateCRMFRequest");
- }
-}, false);
diff --git a/content/base/test/xcsp/file_CSP_frameancestors.sjs b/content/base/test/xcsp/file_CSP_frameancestors.sjs
deleted file mode 100644
index 20dfef973217..000000000000
--- a/content/base/test/xcsp/file_CSP_frameancestors.sjs
+++ /dev/null
@@ -1,54 +0,0 @@
-// SJS file for CSP frame ancestor mochitests
-function handleRequest(request, response)
-{
- var query = {};
- request.queryString.split('&').forEach(function (val) {
- var [name, value] = val.split('=');
- query[name] = unescape(value);
- });
-
- var isPreflight = request.method == "OPTIONS";
-
-
- //avoid confusing cache behaviors
- response.setHeader("Cache-Control", "no-cache", false);
-
- // grab the desired policy from the query, and then serve a page
- if (query['csp'])
- response.setHeader("X-Content-Security-Policy",
- unescape(query['csp']),
- false);
- if (query['scriptedreport']) {
- // spit back a script that records that the page loaded
- response.setHeader("Content-Type", "text/javascript", false);
- if (query['double'])
- response.write('window.parent.parent.parent.postMessage({call: "frameLoaded", testname: "' + query['scriptedreport'] + '", uri: "window.location.toString()"}, "*");');
- else
- response.write('window.parent.parent.postMessage({call: "frameLoaded", testname: "' + query['scriptedreport'] + '", uri: "window.location.toString()"}, "*");');
- } else if (query['internalframe']) {
- // spit back an internal iframe (one that might be blocked)
- response.setHeader("Content-Type", "text/html", false);
- response.write('');
- if (query['double'])
- response.write('');
- else
- response.write('');
- response.write('');
- response.write(unescape(query['internalframe']));
- response.write('');
- } else if (query['externalframe']) {
- // spit back an internal iframe (one that won't be blocked, and probably
- // has no CSP)
- response.setHeader("Content-Type", "text/html", false);
- response.write('');
- response.write('');
- response.write(unescape(query['externalframe']));
- response.write('');
- } else {
- // default case: error.
- response.setHeader("Content-Type", "text/html", false);
- response.write('');
- response.write("ERROR: not sure what to serve.");
- response.write('');
- }
-}
diff --git a/content/base/test/xcsp/file_CSP_frameancestors_main.html b/content/base/test/xcsp/file_CSP_frameancestors_main.html
deleted file mode 100644
index d35655e5218f..000000000000
--- a/content/base/test/xcsp/file_CSP_frameancestors_main.html
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
- CSP frame ancestors tests
-
-
-
-
-
-
-
-
- aa_allow: /* innermost frame allows a */
-
-
- aa_block: /* innermost frame denies a */
-
-
- ab_allow: /* innermost frame allows a */
-
-
- ab_block: /* innermost frame denies a */
-
-
- aba_allow: /* innermost frame allows b,a */
-
-
- aba_block: /* innermost frame denies b */
-
-
- aba2_block: /* innermost frame denies a */
-
-
- abb_allow: /* innermost frame allows b,a */
-
-
- abb_block: /* innermost frame denies b */
-
-
- abb2_block: /* innermost frame denies a */
-
-
-
-
-
diff --git a/content/base/test/xcsp/file_CSP_frameancestors_main.js b/content/base/test/xcsp/file_CSP_frameancestors_main.js
deleted file mode 100644
index a819580edcbb..000000000000
--- a/content/base/test/xcsp/file_CSP_frameancestors_main.js
+++ /dev/null
@@ -1,65 +0,0 @@
-// Script to populate the test frames in the frame ancestors mochitest.
-//
-function setupFrames() {
-
- var $ = function(v) { return document.getElementById(v); }
- var base = {
- self: '/tests/content/base/test/xcsp/file_CSP_frameancestors.sjs',
- a: 'http://mochi.test:8888/tests/content/base/test/xcsp/file_CSP_frameancestors.sjs',
- b: 'http://example.com/tests/content/base/test/xcsp/file_CSP_frameancestors.sjs'
- };
-
- var host = { a: 'http://mochi.test:8888', b: 'http://example.com:80' };
-
- var innerframeuri = null;
- var elt = null;
-
- elt = $('aa_allow');
- elt.src = base.a + "?testid=aa_allow&internalframe=aa_a&csp=" +
- escape("allow 'none'; frame-ancestors " + host.a + "; script-src 'self'");
-
- elt = $('aa_block');
- elt.src = base.a + "?testid=aa_block&internalframe=aa_b&csp=" +
- escape("allow 'none'; frame-ancestors 'none'; script-src 'self'");
-
- elt = $('ab_allow');
- elt.src = base.b + "?testid=ab_allow&internalframe=ab_a&csp=" +
- escape("allow 'none'; frame-ancestors " + host.a + "; script-src 'self'");
-
- elt = $('ab_block');
- elt.src = base.b + "?testid=ab_block&internalframe=ab_b&csp=" +
- escape("allow 'none'; frame-ancestors 'none'; script-src 'self'");
-
- /* .... two-level framing */
- elt = $('aba_allow');
- innerframeuri = base.a + "?testid=aba_allow&double=1&internalframe=aba_a&csp=" +
- escape("allow 'none'; frame-ancestors " + host.a + " " + host.b + "; script-src 'self'");
- elt.src = base.b + "?externalframe=" + escape('');
-
- elt = $('aba_block');
- innerframeuri = base.a + "?testid=aba_allow&double=1&internalframe=aba_b&csp=" +
- escape("allow 'none'; frame-ancestors " + host.a + "; script-src 'self'");
- elt.src = base.b + "?externalframe=" + escape('');
-
- elt = $('aba2_block');
- innerframeuri = base.a + "?testid=aba_allow&double=1&internalframe=aba2_b&csp=" +
- escape("allow 'none'; frame-ancestors " + host.b + "; script-src 'self'");
- elt.src = base.b + "?externalframe=" + escape('');
-
- elt = $('abb_allow');
- innerframeuri = base.b + "?testid=abb_allow&double=1&internalframe=abb_a&csp=" +
- escape("allow 'none'; frame-ancestors " + host.a + " " + host.b + "; script-src 'self'");
- elt.src = base.b + "?externalframe=" + escape('');
-
- elt = $('abb_block');
- innerframeuri = base.b + "?testid=abb_allow&double=1&internalframe=abb_b&csp=" +
- escape("allow 'none'; frame-ancestors " + host.a + "; script-src 'self'");
- elt.src = base.b + "?externalframe=" + escape('');
-
- elt = $('abb2_block');
- innerframeuri = base.b + "?testid=abb_allow&double=1&internalframe=abb2_b&csp=" +
- escape("allow 'none'; frame-ancestors " + host.b + "; script-src 'self'");
- elt.src = base.b + "?externalframe=" + escape('');
-}
-
-window.addEventListener('load', setupFrames, false);
diff --git a/content/base/test/xcsp/file_CSP_inlinescript_main.html b/content/base/test/xcsp/file_CSP_inlinescript_main.html
deleted file mode 100644
index bc6f2e6e37c3..000000000000
--- a/content/base/test/xcsp/file_CSP_inlinescript_main.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
- CSP inline script tests
-
-
-
-
-
-
-
- stuff
-
-
diff --git a/content/base/test/xcsp/file_CSP_inlinescript_main.html^headers^ b/content/base/test/xcsp/file_CSP_inlinescript_main.html^headers^
deleted file mode 100644
index 0b777e954ebf..000000000000
--- a/content/base/test/xcsp/file_CSP_inlinescript_main.html^headers^
+++ /dev/null
@@ -1,2 +0,0 @@
-X-Content-Security-Policy: allow 'self'
-Cache-Control: no-cache
diff --git a/content/base/test/xcsp/file_CSP_inlinestyle_main.html b/content/base/test/xcsp/file_CSP_inlinestyle_main.html
deleted file mode 100644
index 0c7db9e15148..000000000000
--- a/content/base/test/xcsp/file_CSP_inlinestyle_main.html
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
- CSP inline script tests
-
-
-
-
-
-
-
-
Link tag (external) stylesheet test (should be green)