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 100693 63212e0a927bf92e28b050ddf62d4e0a504dbb7e
parent 100692 b1f1aeec713261b6ad5adf839a99a670512ac80c
child 100694 924b157541bc8269eb5ef871e624edbd1c4ba748
push idunknown
push userunknown
push dateunknown
reviewersbz
bugs766569
milestone16.0a1
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)