Bug 766569 - add l10n support to existing CSP errors and warnings. (r=bz)
authorMark Goodwin <mgoodwin@mozilla.com>
Fri, 29 Jun 2012 12:51:24 -0700
changeset 97978 63212e0a927bf92e28b050ddf62d4e0a504dbb7e
parent 97977 b1f1aeec713261b6ad5adf839a99a670512ac80c
child 97979 924b157541bc8269eb5ef871e624edbd1c4ba748
push id23017
push userryanvm@gmail.com
push dateSat, 30 Jun 2012 19:29:24 +0000
treeherdermozilla-central@4c2ddc60f360 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs766569
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 766569 - add l10n support to existing CSP errors and warnings. (r=bz)
content/base/src/CSPUtils.jsm
content/base/src/contentSecurityPolicy.js
dom/locales/en-US/chrome/security/csp.properties
dom/locales/jar.mn
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -5,21 +5,29 @@
 /**
  * Content Security Policy Utilities
  * 
  * Overview
  * This contains a set of classes and utilities for CSP.  It is in this
  * separate file for testing purposes.
  */
 
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+                                  "resource://gre/modules/Services.jsm");
+
 // Module stuff
 var EXPORTED_SYMBOLS = ["CSPRep", "CSPSourceList", "CSPSource", "CSPHost",
                         "CSPWarning", "CSPError", "CSPdebug",
-                        "CSPViolationReportListener"];
+                        "CSPViolationReportListener", "CSPLocalizer"];
 
+var STRINGS_URI = "chrome://global/locale/security/csp.properties";
 
 // these are not exported
 var gIoService = Components.classes["@mozilla.org/network/io-service;1"]
                  .getService(Components.interfaces.nsIIOService);
 
 var gETLDService = Components.classes["@mozilla.org/network/effective-tld-service;1"]
                    .getService(Components.interfaces.nsIEffectiveTLDService);
 
@@ -217,17 +225,17 @@ CSPRep.fromString = function(aStr, self,
       // 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
-          CSPWarning("don't understand option '" + opt + "'.  Ignoring it.");
+          CSPWarning(CSPLocalizer.getFormatStr("doNotUnderstandOption", [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) {
@@ -270,115 +278,115 @@ CSPRep.fromString = function(aStr, self,
           uri.host;
 
           // Verify that each report URI is in the same etld + 1 and that the
           // scheme and port match "self" if "self" is defined, and just that
           // it's valid otherwise.
           if (self) {
             if (gETLDService.getBaseDomain(uri) !==
                 gETLDService.getBaseDomain(selfUri)) {
-              CSPWarning("can't use report URI from non-matching eTLD+1: "
-                         + gETLDService.getBaseDomain(uri));
+              CSPWarning(CSPLocalizer.getFormatStr("notETLDPlus1",
+                         [gETLDService.getBaseDomain(uri)]));
               continue;
             }
             if (!uri.schemeIs(selfUri.scheme)) {
-              CSPWarning("can't use report URI with different scheme from "
-                         + "originating document: " + uri.asciiSpec);
+              CSPWarning(CSPLocalizer.getFormatStr("notSameScheme",
+                         [uri.asciiSpec]));
               continue;
             }
             if (uri.port && uri.port !== selfUri.port) {
-              CSPWarning("can't use report URI with different port from "
-                         + "originating document: " + uri.asciiSpec);
+              CSPWarning(CSPLocalizer.getFormatStr("notSamePort",
+                         [uri.asciiSpec]));
               continue;
             }
           }
         } 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) {
-                CSPWarning("page on " + selfUri.host
-                           + " cannot send reports to " + uri.host);
+                CSPWarning(CSPLocalizer.getFormatStr("pageCannotSendReportsTo",
+                         [selfUri.host, uri.host]));
                 continue;
               }
               break;
 
             default:
-              CSPWarning("couldn't parse report URI: " + uriStrings[i]);
+              CSPWarning(CSPLocalizer.getFormatStr("couldNotParseReportURI", [uriStrings[i]]));
               continue;
           }
         }
         // all verification passed: same ETLD+1, scheme, and port.
         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("policy-uri directive can only appear alone");
+        CSPError(CSPLocalizer.getStr("policyURINotAlone"));
         return CSPRep.fromString("default-src 'none'");
       }
       // 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("The policy-uri cannot be fetched without a parent request and a CSP.");
+        CSPError(CSPLocalizer.getStr("noParentRequest"));
         return CSPRep.fromString("default-src 'none'");
       }
 
       var uri = '';
       try {
         uri = gIoService.newURI(dirvalue, null, selfUri);
       } catch(e) {
-        CSPError("could not parse URI in policy URI: " + dirvalue);
+        CSPError(CSPLocalizer.getFormatStr("policyURIParseError", [dirvalue]));
         return CSPRep.fromString("default-src 'none'");
       }
 
       // Verify that policy URI comes from the same origin
       if (selfUri) {
         if (selfUri.host !== uri.host){
-          CSPError("can't fetch policy uri from non-matching hostname: " + uri.host);
+          CSPError(CSPLocalizer.getFormatStr("nonMatchingHost", [uri.host]));
           return CSPRep.fromString("default-src 'none'");
         }
         if (selfUri.port !== uri.port){
-          CSPError("can't fetch policy uri from non-matching port: " + uri.port);
+          CSPError(CSPLocalizer.getFormatStr("nonMatchingPort", [uri.port.toString()]));
           return CSPRep.fromString("default-src 'none'");
         }
         if (selfUri.scheme !== uri.scheme){
-          CSPError("can't fetch policy uri from non-matching scheme: " + uri.scheme);
+          CSPError(CSPLocalizer.getFormatStr("nonMatchingScheme", [uri.scheme]));
           return CSPRep.fromString("default-src 'none'");
         }
       }
 
       // 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 |= Components.interfaces.nsIChannel.LOAD_ANONYMOUS;
         chan.asyncOpen(new CSPPolicyURIListener(uri, docRequest, csp), null);
       }
       catch (e) {
         // resume the document request and apply most restrictive policy
         docRequest.resume();
-        CSPError("Error fetching policy-uri: " + e);
+        CSPError(CSPLocalizer.getFormatStr("errorFetchingPolicy", [e.toString()]));
         return CSPRep.fromString("default-src 'none'");
       }
 
       // return a fully-open policy to be intersected with the contents of the
       // policy-uri when it returns
       return CSPRep.fromString("default-src *");
     }
 
     // UNIDENTIFIED DIRECTIVE /////////////////////////////////////////////
-    CSPWarning("Couldn't process unknown directive '" + dirname + "'");
+    CSPWarning(CSPLocalizer.getFormatStr("couldNotProcessUnknownDirective", [dirname]));
 
   } // end directive: loop
 
   // if makeExplicit fails for any reason, default to default-src 'none'.  This
   // includes the case where "default-src" is not present.
   if (aCSPR.makeExplicit())
     return aCSPR;
   return CSPRep.fromString("default-src 'none'", self);
@@ -511,17 +519,17 @@ CSPRep.prototype = {
    *      true  if the makeExplicit succeeds
    *      false if it fails (for some weird reason)
    */
   makeExplicit:
   function cspsd_makeExplicit() {
     var SD = CSPRep.SRC_DIRECTIVES;
     var defaultSrcDir = this._directives[SD.DEFAULT_SRC];
     if (!defaultSrcDir) {
-      CSPWarning("'allow' or 'default-src' directive required but not present.  Reverting to \"default-src 'none'\"");
+      CSPWarning(CSPLocalizer.getStr("allowOrDefaultSrcRequired"));
       return false;
     }
 
     for (var dir in SD) {
       var dirv = SD[dir];
       if (dirv === SD.DEFAULT_SRC) continue;
       if (!this._directives[dirv]) {
         // implicit directive, make explicit.
@@ -601,17 +609,17 @@ CSPSourceList.fromString = function(aStr
     return slObj;
   }
 
   var tokens = aStr.split(/\s+/);
   for (var i in tokens) {
     if (tokens[i] === "") continue;
     var src = CSPSource.create(tokens[i], self, enforceSelfChecks);
     if (!src) {
-      CSPWarning("Failed to parse unrecoginzied source " + tokens[i]);
+      CSPWarning(CSPLocalizer.getFormatStr("failedToParseUnrecognizedSource", [tokens[i]]));
       continue;
     }
     slObj._sources.push(src);
   }
 
   return slObj;
 };
 
@@ -827,22 +835,22 @@ CSPSource.create = function(aData, self,
  * @param enforceSelfChecks (optional)
  *        if present, and "true", will check to be sure "self" has the
  *        appropriate values to inherit when they are omitted from aURI.
  * @returns
  *        an instance of CSPSource 
  */
 CSPSource.fromURI = function(aURI, self, enforceSelfChecks) {
   if (!(aURI instanceof Components.interfaces.nsIURI)){
-    CSPError("Provided argument is not an nsIURI");
+    CSPError(CSPLocalizer.getStr("cspSourceNotURI"));
     return null;
   }
 
   if (!self && enforceSelfChecks) {
-    CSPError("Can't use 'self' if self data is not provided");
+    CSPError(CSPLocalizer.getStr("selfDataNotProvided"));
     return null;
   }
 
   if (self && !(self instanceof CSPSource)) {
     self = CSPSource.create(self, undefined, false);
   }
 
   var sObj = new CSPSource();
@@ -851,17 +859,17 @@ CSPSource.fromURI = function(aURI, self,
   // PARSE
   // If 'self' is undefined, then use default port for scheme if there is one.
 
   // grab scheme (if there is one)
   try {
     sObj._scheme = aURI.scheme;
   } catch(e) {
     sObj._scheme = undefined;
-    CSPError("can't parse a URI without a scheme: " + aURI.asciiSpec);
+    CSPError(CSPLocalizer.getFormatStr("uriWithoutScheme", [aURI.asciiSpec]));
     return null;
   }
 
   // grab host (if there is one)
   try {
     // if there's no host, an exception will get thrown
     // (NS_ERROR_FAILURE)
     sObj._host = CSPHost.fromString(aURI.host);
@@ -907,36 +915,36 @@ CSPSource.fromURI = function(aURI, self,
  * @returns
  *        an instance of CSPSource 
  */
 CSPSource.fromString = function(aStr, self, enforceSelfChecks) {
   if (!aStr)
     return null;
 
   if (!(typeof aStr === 'string')) {
-    CSPError("Provided argument is not a string");
+    CSPError(CSPLocalizer.getStr("argumentIsNotString"));
     return null;
   }
 
   if (!self && enforceSelfChecks) {
-    CSPError("Can't use 'self' if self data is not provided");
+    CSPError(CSPLocalizer.getStr("selfDataNotProvided"));
     return null;
   }
 
   if (self && !(self instanceof CSPSource)) {
     self = CSPSource.create(self, undefined, false);
   }
 
   var sObj = new CSPSource();
   sObj._self = self;
 
   // take care of 'self' keyword
   if (aStr === "'self'") {
     if (!self) {
-      CSPError("self keyword used, but no self data specified");
+      CSPError(CSPLocalizer.getStr("selfKeywordNoSelfData"));
       return null;
     }
     sObj._self = self.clone();
     sObj._isSelf = true;
     return sObj;
   }
 
   // We could just create a URI and then send this off to fromURI, but
@@ -945,25 +953,25 @@ CSPSource.fromString = function(aStr, se
 
   // split it up
   var chunks = aStr.split(":");
 
   // If there is only one chunk, it's gotta be a host.
   if (chunks.length == 1) {
     sObj._host = CSPHost.fromString(chunks[0]);
     if (!sObj._host) {
-      CSPError("Couldn't parse invalid source " + aStr);
+      CSPError(CSPLocalizer.getFormatStr("couldntParseInvalidSource",[aStr]));
       return null;
     }
 
     // enforce 'self' inheritance
     if (enforceSelfChecks) {
       // note: the non _scheme accessor checks sObj._self
       if (!sObj.scheme || !sObj.port) {
-        CSPError("Can't create host-only source " + aStr + " without 'self' data");
+        CSPError(CSPLocalizer.getFormatStr("hostSourceWithoutData",[aStr]));
         return null;
       }
     }
     return sObj;
   }
 
   // If there are two chunks, it's either scheme://host or host:port
   //   ... but scheme://host can have an empty host.
@@ -972,27 +980,27 @@ CSPSource.fromString = function(aStr, se
 
     // is the last bit a port?
     if (chunks[1] === "*" || chunks[1].match(/^\d+$/)) {
       sObj._port = chunks[1];
       // then the previous chunk *must* be a host or empty.
       if (chunks[0] !== "") {
         sObj._host = CSPHost.fromString(chunks[0]);
         if (!sObj._host) {
-          CSPError("Couldn't parse invalid source " + aStr);
+          CSPError(CSPLocalizer.getFormatStr("couldntParseInvalidSource",[aStr]));
           return null;
         }
       }
       // enforce 'self' inheritance 
       // (scheme:host requires port, host:port does too.  Wildcard support is
       // only available if the scheme and host are wildcarded)
       if (enforceSelfChecks) {
         // note: the non _scheme accessor checks sObj._self
         if (!sObj.scheme || !sObj.host || !sObj.port) {
-          CSPError("Can't create source " + aStr + " without 'self' data");
+          CSPError(CSPLocalizer.getFormatStr("sourceWithoutData",[aStr]));
           return null;
         }
       }
     }
     // is the first bit a scheme?
     else if (CSPSource.validSchemeName(chunks[0])) {
       sObj._scheme = chunks[0];
       // then the second bit *must* be a host or empty
@@ -1004,48 +1012,48 @@ CSPSource.fromString = function(aStr, se
         if (!sObj._port) sObj._port = "*";
       } else {
         // some host was defined.
         // ... remove <= 3 leading slashes (from the scheme) and parse
         var cleanHost = chunks[1].replace(/^\/{0,3}/,"");
         // ... and parse
         sObj._host = CSPHost.fromString(cleanHost);
         if (!sObj._host) {
-          CSPError("Couldn't parse invalid host " + cleanHost);
+          CSPError(CSPLocalizer.getFormatStr("couldntParseInvalidHost",[cleanHost]));
           return null;
         }
       }
 
       // enforce 'self' inheritance (scheme-only should be scheme:*:* now, and
       // if there was a host provided it should be scheme:host:selfport
       if (enforceSelfChecks) {
         // note: the non _scheme accessor checks sObj._self
         if (!sObj.scheme || !sObj.host || !sObj.port) {
-          CSPError("Can't create source " + aStr + " without 'self' data");
+          CSPError(CSPLocalizer.getFormatStr("sourceWithoutData",[aStr]));
           return null;
         }
       }
     }
     else  {
       // AAAH!  Don't know what to do!  No valid scheme or port!
-      CSPError("Couldn't parse invalid source " + aStr);
+      CSPError(CSPLocalizer.getFormatStr("couldntParseInvalidSource",[aStr]));
       return null;
     }
 
     return sObj;
   }
 
   // If there are three chunks, we got 'em all!
   if (!CSPSource.validSchemeName(chunks[0])) {
-    CSPError("Couldn't parse scheme in " + aStr);
+    CSPError(CSPLocalizer.getFormatStr("couldntParseScheme",[aStr]));
     return null;
   }
   sObj._scheme = chunks[0];
   if (!(chunks[2] === "*" || chunks[2].match(/^\d+$/))) {
-    CSPError("Couldn't parse port in " + aStr);
+    CSPError(CSPLocalizer.getFormatStr("couldntParsePort",[aStr]));
     return null;
   }
 
   sObj._port = chunks[2];
 
   // ... remove <= 3 leading slashes (from the scheme) and parse
   var cleanHost = chunks[1].replace(/^\/{0,3}/,"");
   sObj._host = CSPHost.fromString(cleanHost);
@@ -1197,58 +1205,55 @@ CSPSource.prototype = {
       newSource._port = this._port;
     else if (this._port === "*") 
       newSource._port = that._port;
     else if (that._port === "*")
       newSource._port = this._port;
     else if (that._port === this._port)
       newSource._port = this._port;
     else {
-      CSPError("Could not intersect " + this + " with " + that
-               + " due to port problems.");
+      CSPError(CSPLocalizer.getFormatStr("notIntersectPort", [this.toString(), that.toString()]));
       return null;
     }
 
     // scheme
     if (!this._scheme)
       newSource._scheme = that._scheme;
     else if (!that._scheme)
       newSource._scheme = this._scheme;
     if (this._scheme === "*")
       newSource._scheme = that._scheme;
     else if (that._scheme === "*")
       newSource._scheme = this._scheme;
     else if (that._scheme === this._scheme)
       newSource._scheme = this._scheme;
     else {
-      CSPError("Could not intersect " + this + " with " + that
-               + " due to scheme problems.");
+      CSPError(CSPLocalizer.getFormatStr("notIntersectScheme", [this.toString(), that.toString()]));
       return null;
     }
 
     // NOTE: Both sources must have a host, if they don't, something funny is
     // going on.  The fromString() factory method should have set the host to
     // * if there's no host specified in the input. Regardless, if a host is
     // not present either the scheme is hostless or any host should be allowed.
     // This means we can use the other source's host as the more restrictive
     // host expression, or if neither are present, we can use "*", but the
     // error should still be reported.
 
     // host
     if (this._host && that._host) {
       newSource._host = this._host.intersectWith(that._host);
     } else if (this._host) {
-      CSPError("intersecting source with undefined host: " + that.toString());
+      CSPError(CSPLocalizer.getFormatStr("intersectingSourceWithUndefinedHost", [that.toString()]));
       newSource._host = this._host.clone();
     } else if (that._host) {
-      CSPError("intersecting source with undefined host: " + this.toString());
+      CSPError(CSPLocalizer.getFormatStr("intersectingSourceWithUndefinedHost", [this.toString()]));
       newSource._host = that._host.clone();
     } else {
-      CSPError("intersecting two sources with undefined hosts: " +
-               this.toString() + " and " + that.toString());
+      CSPError(CSPLocalizer.getFormatStr("intersectingSourcesWithUndefinedHosts", [this.toString(), that.toString()]));
       newSource._host = CSPHost.fromString("*");
     }
 
     return newSource;
   },
 
   /**
    * Compares one CSPSource to another.
@@ -1481,8 +1486,60 @@ CSPViolationReportListener.prototype = {
   onStartRequest:
   function(request, context) { },
 
   onDataAvailable:
   function(request, context, inputStream, offset, count) { },
 
 };
 
+//////////////////////////////////////////////////////////////////////
+
+CSPLocalizer = {
+  /**
+   * Retrieve a localized string.
+   *
+   * @param string aName
+   *        The string name you want from the CSP string bundle.
+   * @return string
+   *         The localized string.
+   */
+  getStr: function CSPLoc_getStr(aName)
+  {
+    let result;
+    try {
+      result = this.stringBundle.GetStringFromName(aName);
+    }
+    catch (ex) {
+      Cu.reportError("Failed to get string: " + aName);
+      throw ex;
+    }
+    return result;
+  },
+
+  /**
+   * Retrieve a localized string formatted with values coming from the given
+   * array.
+   *
+   * @param string aName
+   *        The string name you want from the CSP string bundle.
+   * @param array aArray
+   *        The array of values you want in the formatted string.
+   * @return string
+   *         The formatted local string.
+   */
+  getFormatStr: function CSPLoc_getFormatStr(aName, aArray)
+  {
+    let result;
+    try {
+      result = this.stringBundle.formatStringFromName(aName, aArray, aArray.length);
+    }
+    catch (ex) {
+      Cu.reportError("Failed to format string: " + aName);
+      throw ex;
+    }
+    return result;
+  },
+};
+
+XPCOMUtils.defineLazyGetter(CSPLocalizer, "stringBundle", function() {
+  return Services.strings.createBundle(STRINGS_URI);
+});
--- a/content/base/src/contentSecurityPolicy.js
+++ b/content/base/src/contentSecurityPolicy.js
@@ -279,18 +279,23 @@ ContentSecurityPolicy.prototype = {
       if (aScriptSample)
         report["csp-report"]["script-sample"] = aScriptSample;
       if (aLineNum)
         report["csp-report"]["line-number"] = aLineNum;
 
       var reportString = JSON.stringify(report);
       CSPdebug("Constructed violation report:\n" + reportString);
 
-      CSPWarning("Directive \"" + violatedDirective + "\" violated"
-               + (blockedUri['asciiSpec'] ? " by " + blockedUri.asciiSpec : ""),
+      var violationMessage = null;
+      if(blockedUri["asciiSpec"]){
+         violationMessage = CSPLocalizer.getFormatStr("directiveViolatedWithURI", [violatedDirective, blockedUri.asciiSpec]);
+      } else {
+         violationMessage = CSPLocalizer.getFormatStr("directiveViolated", [violatedDirective]);
+      }
+      CSPWarning(violationMessage,
                  this.innerWindowID,
                  (aSourceFile) ? aSourceFile : null,
                  (aScriptSample) ? decodeURIComponent(aScriptSample) : null,
                  (aLineNum) ? aLineNum : null);
 
       // For each URI in the report list, send out a report.
       // We make the assumption that all of the URIs are absolute URIs; this
       // should be taken care of in CSPRep.fromString (where it converts any
@@ -342,18 +347,18 @@ ContentSecurityPolicy.prototype = {
           }
 
           //send data (and set up error notifications)
           chan.asyncOpen(new CSPViolationReportListener(uris[i]), null);
           CSPdebug("Sent violation report to " + uris[i]);
         } catch(e) {
           // it's possible that the URI was invalid, just log a
           // warning and skip over that.
-          CSPWarning("Tried to send report to invalid URI: \"" + uris[i] + "\"", this.innerWindowID);
-          CSPWarning("error was: \"" + e + "\"", this.innerWindowID);
+          CSPWarning(CSPLocalizer.getFormatStr("triedToSendReport", [uris[i]]), this.innerWindowID);
+          CSPWarning(CSPLocalizer.getFormatStr("errorWas", [e.toString()]), this.innerWindowID);
         }
       }
     }
   },
 
   /**
    * Exposed Method to analyze docShell for approved frame ancestry.
    * Also sends violation reports if necessary.
@@ -545,18 +550,17 @@ CSPReportRedirectSink.prototype = {
       return this;
 
     throw Components.results.NS_ERROR_NO_INTERFACE;
   },
 
   // nsIChannelEventSink
   asyncOnChannelRedirect: function channel_redirect(oldChannel, newChannel,
                                                     flags, callback) {
-    CSPWarning("Post of violation report to " + oldChannel.URI.asciiSpec +
-               " failed, as a redirect occurred", this.innerWindowID);
+    CSPWarning(CSPLocalizer.getFormatStr("reportPostRedirect", [oldChannel.URI.asciiSpec]));
 
     // cancel the old channel so XHR failure callback happens
     oldChannel.cancel(Cr.NS_ERROR_ABORT);
 
     // notify an observer that we have blocked the report POST due to a redirect,
     // used in testing, do this async since we're in an async call now to begin with
     Services.tm.mainThread.dispatch(
       function() {
new file mode 100644
--- /dev/null
+++ b/dom/locales/en-US/chrome/security/csp.properties
@@ -0,0 +1,106 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# CSP Warnings:
+# LOCALIZATION NOTE (directiveViolated):
+# %1$S is the directive that has been violated.
+directiveViolated = Directive %1$S violated
+# LOCALIZATION NOTE (directiveViolatedWithURI):
+# %1$S is the directive that has been violated.
+# %2$S is the URI of the resource which violated the directive.
+directiveViolatedWithURI = Directive %1$S violated by %2$S
+# LOCALIZATION NOTE (triedToSendReport):
+# %1$S is the URI we attempted to send a report to.
+triedToSendReport = Tried to send report to invalid URI: "%1$S"
+# LOCALIZATION NOTE (errorWas):
+# %1$S is the error resulting from attempting to send the report
+errorWas = error was: "%1$S"
+# LOCALIZATION NOTE (couldNotParseReportURI):
+# %1$S is the report URI that could not be parsed
+couldNotParseReportURI = couldn't parse report URI: %1$S
+# LOCALIZATION NOTE (couldNotProcessUnknownDirective):
+# %1$S is the unknown directive
+couldNotProcessUnknownDirective = Couldn't process unknown directive '%1$S'
+# LOCALIZATION NOTE (doNotUnderstandOption):
+# %1$S is the option that could not be understood
+doNotUnderstandOption = don't understand option '%1$S'.  Ignoring it.
+# LOCALIZATION NOTE (notETLDPlus1):
+# %1$S is the ETLD of the report URI that could not be used
+notETLDPlus1 = can't use report URI from non-matching eTLD+1: %1$S
+# LOCALIZATION NOTE (notSameScheme):
+# %1$S is the report URI that could not be used
+notSameScheme = can't use report URI with different scheme from originating document: %1$S
+# LOCALIZATION NOTE (notSamePort):
+# %1$S is the report URI that could not be used
+notSamePort = can't use report URI with different port from originating document: %1$S
+# LOCALIZATION NOTE (pageCannotSendReportsTo):
+# %1$S is the URI of the page with the policy
+# %2$S is the report URI that could not be used
+pageCannotSendReportsTo = page on %1$S cannot send reports to %2$S
+allowOrDefaultSrcRequired = 'allow' or 'default-src' directive required but not present.  Reverting to "default-src 'none'"
+# LOCALIZATION NOTE (failedToParseUnrecognizedSource):
+# %1$S is the CSP Source that could not be parsed
+failedToParseUnrecognizedSource = Failed to parse unrecoginzied source %1$S
+# LOCALIZATION NOTE (reportPostRedirect):
+# %1$S is the specified report URI before redirect
+reportPostRedirect = Post of violation report to %1$S failed, as a redirect occurred
+
+# CSP Errors:
+policyURINotAlone = policy-uri directive can only appear alone
+noParentRequest = The policy-uri cannot be fetched without a parent request and a CSP.
+# LOCALIZATION NOTE (policyURIParseError):
+# %1$S is the URI that could not be parsed
+policyURIParseError = could not parse URI in policy URI: %1$S
+# LOCALIZATION NOTE (nonMatchingHost):
+# %1$S is the URI host that does not match
+nonMatchingHost = can't fetch policy uri from non-matching hostname: %1$S
+# LOCALIZATION NOTE (nonMatchingPort):
+# %1$S is the URI port that does not match
+nonMatchingPort = can't fetch policy uri from non-matching port: %1$S
+# LOCALIZATION NOTE (nonMatchingScheme):
+# %1$S is the URI scheme that does not match
+nonMatchingScheme = can't fetch policy uri from non-matching scheme: %1$S
+# LOCALIZATION NOTE (errorFetchingPolicy):
+# %1$S is the error that caused fetching to fail
+errorFetchingPolicy = Error fetching policy-uri: %1$S
+cspSourceNotURI = Provided argument is not an nsIURI
+argumentIsNotString = Provided argument is not a string
+selfDataNotProvided = Can't use 'self' if self data is not provided
+# LOCALIZATION NOTE (uriWithoutScheme):
+# %1$S is the URI without a scheme
+uriWithoutScheme = can't parse a URI without a scheme: %1$S
+selfKeywordNoSelfData = self keyword used, but no self data specified
+# LOCALIZATION NOTE (couldntParseInvalidSource):
+# %1$S is the source that could not be parsed
+couldntParseInvalidSource = Couldn't parse invalid source %1$S
+# LOCALIZATION NOTE (hostSourceWithoutData):
+# %1$S is the source
+hostSourceWithoutData = Can't create host-only source %1$S without 'self' data
+# LOCALIZATION NOTE (sourceWithoutData):
+# %1$S is the source
+sourceWithoutData = Can't create source %1$S without 'self' data
+# LOCALIZATION NOTE (couldntParseInvalidHost):
+# %1$S is the host that's invalid
+couldntParseInvalidHost = Couldn't parse invalid host %1$S
+# LOCALIZATION NOTE (couldntParseScheme):
+# %1$S is the string source
+couldntParseScheme = Couldn't parse scheme in %1$S
+# LOCALIZATION NOTE (couldntParsePort):
+# %1$S is the string source
+couldntParsePort = Couldn't parse port in %1$S
+# LOCALIZATION NOTE (notIntersectPort):
+# %1$S is one source we tried to intersect
+# %2$S is the other
+notIntersectPort = Could not intersect %1$S with %2$S due to port problems.
+# LOCALIZATION NOTE (notIntersectScheme):
+# %1$S is one source we tried to intersect
+# %2$S is the other
+notIntersectScheme = Could not intersect %1$S with %2$S due to scheme problems.
+# LOCALIZATION NOTE (intersectingSourceWithUndefinedHost):
+# %1$S is the source
+intersectingSourceWithUndefinedHost = intersecting source with undefined host: %1$S
+# LOCALIZATION NOTE (intersectingSourcesWithUndefinedHosts):
+# %1$S is the first source
+# %2$S is the second source
+intersectingSourcesWithUndefinedHosts = intersecting two sources with undefined hosts: %1$S and %2$S
--- a/dom/locales/jar.mn
+++ b/dom/locales/jar.mn
@@ -21,13 +21,14 @@
   locale/@AB_CD@/global/xslt/xslt.properties                   (%chrome/xslt/xslt.properties)
   locale/@AB_CD@/global/dom/dom.properties                     (%chrome/dom/dom.properties)
   locale/@AB_CD@/global/svg/svg.properties                     (%chrome/svg/svg.properties)
   locale/@AB_CD@/global/layout/MediaDocument.properties        (%chrome/layout/MediaDocument.properties)
   locale/@AB_CD@/global/layout/htmlparser.properties           (%chrome/layout/htmlparser.properties)
   locale/@AB_CD@/global/layout/xmlparser.properties            (%chrome/layout/xmlparser.properties)
   locale/@AB_CD@/global/layout/HtmlForm.properties             (%chrome/layout/HtmlForm.properties)
   locale/@AB_CD@/global/security/caps.properties               (%chrome/security/caps.properties)
+  locale/@AB_CD@/global/security/csp.properties                (%chrome/security/csp.properties)
   locale/@AB_CD@/global/xml/prettyprint.dtd                    (%chrome/xml/prettyprint.dtd)
   locale/@AB_CD@/global-platform/win/accessible.properties     (%chrome/accessibility/win/accessible.properties)
   locale/@AB_CD@/global-platform/mac/accessible.properties     (%chrome/accessibility/mac/accessible.properties)
   locale/@AB_CD@/global-platform/unix/accessible.properties    (%chrome/accessibility/unix/accessible.properties)
   locale/@AB_CD@/global/AccessFu.properties                    (%chrome/accessibility/AccessFu.properties)