bug 836922 - (CSP) remove intersectWith once multiple policies are supported. r=grobinson
authorSid Stamm <sstamm@mozilla.com>
Thu, 12 Sep 2013 09:25:33 -0700
changeset 159771 1a475fdee12b899962f76fd92b763686c7e349b5
parent 159770 5e4b386dc081977cd40bc1d58d82f6d72ed16d5c
child 159772 ac1bcd6c981dd02d66b0bf0092e4d2e1405c32d7
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgrobinson
bugs836922
milestone26.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 836922 - (CSP) remove intersectWith once multiple policies are supported. r=grobinson
content/base/src/CSPUtils.jsm
content/base/test/unit/test_csputils.js
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -460,18 +460,18 @@ CSPRep.fromString = function(aStr, self,
       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'");
       }
 
-      // return a fully-open policy to be intersected with the contents of the
-      // policy-uri when it returns
+      // return a fully-open policy to be used until the contents of the
+      // policy-uri come back.
       return CSPRep.fromString("default-src *");
     }
 
     // UNIDENTIFIED DIRECTIVE /////////////////////////////////////////////
     cspWarn(aCSPR, CSPLocalizer.getFormatStr("couldNotProcessUnknownDirective",
                                              [dirname]));
 
   } // end directive: loop
@@ -718,18 +718,18 @@ CSPRep.fromStringSpecCompliant = functio
       }
       catch (e) {
         // resume the document request and apply most restrictive policy
         docRequest.resume();
         cspError(aCSPR, CSPLocalizer.getFormatStr("errorFetchingPolicy", [e.toString()]));
         return CSPRep.fromStringSpecCompliant("default-src 'none'");
       }
 
-      // return a fully-open policy to be intersected with the contents of the
-      // policy-uri when it returns
+      // return a fully-open policy to be used until the contents of the
+      // policy-uri come back
       return CSPRep.fromStringSpecCompliant("default-src *");
     }
 
     // UNIDENTIFIED DIRECTIVE /////////////////////////////////////////////
     cspWarn(aCSPR, CSPLocalizer.getFormatStr("couldNotProcessUnknownDirective", [dirname]));
 
   } // end directive: loop
 
@@ -839,130 +839,16 @@ 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;
   },
 
   /**
-   * Intersects with another CSPRep, deciding the subset policy
-   * that should be enforced, and returning a new instance.
-   * This assumes that either both CSPReps are specCompliant or they are both
-   * not.
-   * @param aCSPRep
-   *        a CSPRep instance to use as "other" CSP
-   * @returns
-   *        a new CSPRep instance of the intersection
-   */
-  intersectWith:
-  function cspsd_intersectWith(aCSPRep) {
-    var newRep = new CSPRep();
-
-    let DIRS = aCSPRep._specCompliant ? CSPRep.SRC_DIRECTIVES_NEW :
-                                        CSPRep.SRC_DIRECTIVES_OLD;
-
-    // one or more of the two CSPReps may not have any given directive.  In
-    // these cases, we need to pick "all" or "none" based on the type of CSPRep
-    // (spec compliant or not).
-    let thisHasDefault = this._directives.hasOwnProperty(DIRS.DEFAULT_SRC),
-        thatHasDefault = aCSPRep._directives.hasOwnProperty(DIRS.DEFAULT_SRC);
-    for (var dir in DIRS) {
-      let dirv = DIRS[dir];
-      let thisHasDir = this._directives.hasOwnProperty(dirv),
-          thatHasDir = aCSPRep._directives.hasOwnProperty(dirv);
-
-
-      // if both specific src directives are absent, skip this (new policy will
-      // rely on default-src)
-      if (!thisHasDir && !thatHasDir) {
-        continue;
-      }
-
-      // frame-ancestors is a special case; it doesn't fall back to
-      // default-src, so only add it to newRep if one or both of the policies
-      // have it.
-      if (dirv === DIRS.FRAME_ANCESTORS) {
-        if (thisHasDir && thatHasDir) {
-          // both have frame-ancestors, intersect them.
-          newRep._directives[dirv] =
-            aCSPRep._directives[dirv].intersectWith(this._directives[dirv]);
-        } else if (thisHasDir || thatHasDir) {
-          // one or the other has frame-ancestors, copy it.
-          newRep._directives[dirv] =
-            ( thisHasDir ? this : aCSPRep )._directives[dirv].clone();
-        }
-      }
-      else if (aCSPRep._specCompliant) {
-        // CSP 1.0 doesn't require default-src, so an intersection only makes
-        // sense if there is a default-src or both policies have the directive.
-
-        if (!thisHasDir && !thisHasDefault) {
-          // only aCSPRep has a relevant directive
-          newRep._directives[dirv] = aCSPRep._directives[dirv].clone();
-        }
-        else if (!thatHasDir && !thatHasDefault) {
-          // only "this" has a relevant directive
-          newRep._directives[dirv] = this._directives[dirv].clone();
-        }
-        else {
-          // both policies have a relevant directive (may be default-src)
-          var isect1 = thisHasDir ?
-                       this._directives[dirv] :
-                       this._directives[DIRS.DEFAULT_SRC];
-          var isect2 = thatHasDir ?
-                       aCSPRep._directives[dirv] :
-                       aCSPRep._directives[DIRS.DEFAULT_SRC];
-          newRep._directives[dirv] = isect1.intersectWith(isect2);
-        }
-      }
-      else {
-        // pre-1.0 CSP requires a default-src, so we can assume it's here
-        // (since the parser created one).
-        var isect1 = thisHasDir ?
-                     this._directives[dirv] :
-                     this._directives[DIRS.DEFAULT_SRC];
-        var isect2 = thatHasDir ?
-                     aCSPRep._directives[dirv] :
-                     aCSPRep._directives[DIRS.DEFAULT_SRC];
-        newRep._directives[dirv] = isect1.intersectWith(isect2);
-      }
-    }
-
-    // REPORT_URI
-    var reportURIDir = CSPRep.URI_DIRECTIVES.REPORT_URI;
-    if (this._directives[reportURIDir] && aCSPRep._directives[reportURIDir]) {
-      newRep._directives[reportURIDir] =
-        this._directives[reportURIDir].concat(aCSPRep._directives[reportURIDir]);
-    }
-    else if (this._directives[reportURIDir]) {
-      // blank concat makes a copy of the string.
-      newRep._directives[reportURIDir] = this._directives[reportURIDir].concat();
-    }
-    else if (aCSPRep._directives[reportURIDir]) {
-      // blank concat makes a copy of the string.
-      newRep._directives[reportURIDir] = aCSPRep._directives[reportURIDir].concat();
-    }
-
-    newRep._allowEval =          this.allowsEvalInScripts
-                           && aCSPRep.allowsEvalInScripts;
-
-    newRep._allowInlineScripts = this.allowsInlineScripts
-                           && aCSPRep.allowsInlineScripts;
-
-    newRep._allowInlineStyles = this.allowsInlineStyles
-                           && aCSPRep.allowsInlineStyles;
-
-    newRep._innerWindowID = this._innerWindowID ?
-                              this._innerWindowID : aCSPRep._innerWindowID;
-
-    return newRep;
-  },
-
-  /**
    * Returns true if "eval" is enabled through the "eval" keyword.
    */
   get allowsEvalInScripts () {
     return this._allowEval;
   },
 
   /**
    * Returns true if inline scripts are enabled through the "inline"
@@ -1194,72 +1080,16 @@ CSPSourceList.prototype = {
     if (this.isAll())     return true;
 
     for (var i in this._sources) {
       if (this._sources[i].permits(aURI)) {
         return true;
       }
     }
     return false;
-  },
-
-  /**
-   * Intersects with another CSPSourceList, deciding the subset directive
-   * that should be enforced, and returning a new instance.
-   * @param that
-   *        the other CSPSourceList to intersect "this" with
-   * @returns
-   *        a new instance of a CSPSourceList representing the intersection
-   */
-  intersectWith:
-  function cspsd_intersectWith(that) {
-
-    var newCSPSrcList = null;
-
-    if (!that) return this.clone();
-
-    if (this.isNone() || that.isNone())
-      newCSPSrcList = CSPSourceList.fromString("'none'", this._CSPRep);
-
-    if (this.isAll()) newCSPSrcList = that.clone();
-    if (that.isAll()) newCSPSrcList = this.clone();
-
-    if (!newCSPSrcList) {
-      // the shortcuts didn't apply, must do intersection the hard way.
-      // --  find only common sources
-
-      // XXX (sid): we should figure out a better algorithm for this.
-      // This is horribly inefficient.
-      var isrcs = [];
-      for (var i in this._sources) {
-        for (var j in that._sources) {
-          var s = that._sources[j].intersectWith(this._sources[i]);
-          if (s) {
-            isrcs.push(s);
-          }
-        }
-      }
-      // Next, remove duplicates
-      dup: for (var i = 0; i < isrcs.length; i++) {
-        for (var j = 0; j < i; j++) {
-          if (isrcs[i].equals(isrcs[j])) {
-            isrcs.splice(i, 1);
-            i--;
-            continue dup;
-          }
-        }
-      }
-      newCSPSrcList = new CSPSourceList();
-      newCSPSrcList._sources = isrcs;
-    }
-
-    if ((!newCSPSrcList._CSPRep) && that._CSPRep) {
-      newCSPSrcList._CSPRep = that._CSPRep;
-    }
-    return newCSPSrcList;
   }
 }
 
 //////////////////////////////////////////////////////////////////////
 /**
  * Class to model a source (scheme, host, port)
  */
 this.CSPSource = function CSPSource() {
@@ -1664,103 +1494,16 @@ CSPSource.prototype = {
     if (this.host && !this.host.permits(aSource.host))
       return false;
 
     // all scheme, host and port matched!
     return true;
   },
 
   /**
-   * Determines the intersection of two sources.
-   * Returns a null object if intersection generates no
-   * hosts that satisfy it.
-   * @param that
-   *        the other CSPSource to intersect "this" with
-   * @returns
-   *        a new instance of a CSPSource representing the intersection
-   */
-  intersectWith:
-  function(that) {
-    var newSource = new CSPSource();
-
-    // 'self' is not part of the intersection.  Intersect the raw values from
-    // the source, self must be set by someone creating this source.
-    // When intersecting, we take the more specific of the two: if one scheme,
-    // host or port is undefined, the other is taken.  (This is contrary to
-    // when "permits" is called -- there, the value of 'self' is looked at
-    // when a scheme, host or port is undefined.)
-
-    // port
-    if (!this.port)
-      newSource._port = that.port;
-    else if (!that.port)
-      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 {
-      let msg = CSPLocalizer.getFormatStr("notIntersectPort",
-                                          [this.toString(), that.toString()]);
-      cspError(this._CSPRep, msg);
-      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 {
-      var msg = CSPLocalizer.getFormatStr("notIntersectScheme",
-                                          [this.toString(), that.toString()]);
-      cspError(this._CSPRep, msg);
-      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) {
-      let msg = CSPLocalizer.getFormatStr("intersectingSourceWithUndefinedHost",
-                                          [that.toString()]);
-      cspError(this._CSPRep, msg);
-      newSource._host = this.host.clone();
-    } else if (that.host) {
-      let msg = CSPLocalizer.getFormatStr("intersectingSourceWithUndefinedHost",
-                                          [this.toString()]);
-      cspError(this._CSPRep, msg);
-      newSource._host = that.host.clone();
-    } else {
-      let msg = CSPLocalizer.getFormatStr("intersectingSourcesWithUndefinedHosts",
-                                          [this.toString(), that.toString()]);
-      cspError(this._CSPRep, msg);
-      newSource._host = CSPHost.fromString("*");
-    }
-
-    return newSource;
-  },
-
-  /**
    * Compares one CSPSource to another.
    *
    * @param that
    *        another CSPSource
    * @param resolveSelf (optional)
    *        if present, and 'true', implied values are obtained from 'self'
    *        instead of assumed to be "anything"
    * @returns
@@ -1899,46 +1642,16 @@ CSPHost.prototype = {
       }
     }
 
     // at this point, all conditions are met, so the host is allowed
     return true;
   },
 
   /**
-   * Determines the intersection of two Hosts.
-   * Basically, they must be the same, or one must have a wildcard.
-   * @param that
-   *        the other CSPHost to intersect "this" with
-   * @returns
-   *        a new instance of a CSPHost representing the intersection
-   *        (or null, if they can't be intersected)
-   */
-  intersectWith:
-  function(that) {
-    if (!(this.permits(that) || that.permits(this))) {
-      // host definitions cannot co-exist without a more general host
-      // ... one must be a subset of the other, or intersection makes no sense.
-      return null;
-    }
-
-    // pick the more specific one, if both are same length.
-    if (this._segments.length == that._segments.length) {
-      // *.a vs b.a : b.a
-      return (this._segments[0] === "*") ? that.clone() : this.clone();
-    }
-
-    // different lengths...
-    // *.b.a vs *.a : *.b.a
-    // *.b.a vs d.c.b.a : d.c.b.a
-    return (this._segments.length > that._segments.length) ?
-            this.clone() : that.clone();
-  },
-
-  /**
    * Compares one CSPHost to another.
    *
    * @param that
    *        another CSPHost
    * @returns
    *        true if they have the same data
    */
   equals:
--- a/content/base/test/unit/test_csputils.js
+++ b/content/base/test/unit/test_csputils.js
@@ -136,25 +136,16 @@ test(
     do_check_true( h.permits("a.b.c"));  //"CSPHost *.b.c should allow string a.b.c"
     do_check_false(h.permits("b.c"));    //"CSPHost *.b.c should not allow string b.c"
     do_check_false(h.permits("a.a.c"));  //"CSPHost *.b.c should not allow string a.a.c"
     do_check_false(h2.permits(h));       //"CSPHost a.b.c should not allow CSPHost *.b.c"
     do_check_false(h2.permits("b.c"));   //"CSPHost a.b.c should not allow string b.c"
     do_check_true( h2.permits("a.b.c")); //"CSPHost a.b.c should allow string a.b.c"
   });
 
-test(
-    function test_CSPHost_intersectWith() {
-      var h = CSPHost.fromString("*.b.c");
-      //"*.a.b.c ^ *.b.c should be *.a.b.c"
-      do_check_eq("*.a.b.c", h.intersectWith(CSPHost.fromString("*.a.b.c")).toString());
-
-      //"*.b.c ^ *.d.e should not work (null)"
-      do_check_eq(null, h.intersectWith(CSPHost.fromString("*.d.e")));
-    });
 
 ///////////////////// Test the Source object //////////////////////
 
 test(
     function test_CSPSource_fromString() {
     // can't do these tests because "self" is not defined.
       //"basic source should not be null.");
       do_check_neq(null, CSPSource.fromString("a.com", undefined, "http://abc.com"));
@@ -312,52 +303,16 @@ test(
       do_check_false(allGarbageHostSourceList.permits("http://barbaz.com"));
 
       //"*.foo.com does not permit somerandom.foo.com"
       do_check_true(wildcardHostSourceList.permits("http://somerandom.foo.com"));
       //"*.foo.com permits all"
       do_check_false(wildcardHostSourceList.permits("http://barbaz.com"));
     });
 
-test(
-    function test_CSPSourceList_intersect() {
-      // for this test, 'self' values are irrelevant
-      // policy a /\ policy b intersects policies, not context (where 'self'
-      // values come into play)
-      var nullSourceList = CSPSourceList.fromString("'none'");
-      var simpleSourceList = CSPSourceList.fromString("http://a.com");
-      var doubleSourceList = CSPSourceList.fromString("https://foo.com http://bar.com:88");
-      var singleFooSourceList = CSPSourceList.fromString("https://foo.com");
-      var allSourceList = CSPSourceList.fromString("*");
-
-      //"Intersection of one source with 'none' source list should be none.");
-      do_check_true(nullSourceList.intersectWith(simpleSourceList).isNone());
-      //"Intersection of two sources with 'none' source list should be none.");
-      do_check_true(nullSourceList.intersectWith(doubleSourceList).isNone());
-      //"Intersection of '*' with 'none' source list should be none.");
-      do_check_true(nullSourceList.intersectWith(allSourceList).isNone());
-
-      //"Intersection of one source with '*' source list should be one source.");
-      do_check_equivalent(allSourceList.intersectWith(simpleSourceList),
-                          simpleSourceList);
-      //"Intersection of two sources with '*' source list should be two sources.");
-      do_check_equivalent(allSourceList.intersectWith(doubleSourceList),
-                          doubleSourceList);
-
-      //"Non-overlapping source lists should intersect to 'none'");
-      do_check_true(simpleSourceList.intersectWith(doubleSourceList).isNone());
-
-      //"subset and superset should intersect to subset.");
-      do_check_equivalent(singleFooSourceList,
-                          doubleSourceList.intersectWith(singleFooSourceList));
-
-      //TODO: write more tests?
-
-    });
-
 ///////////////////// Test the Whole CSP rep object //////////////////////
 
 test(
     function test_CSPRep_fromString() {
 
       // check default init
       //ASSERT(!(new CSPRep())._isInitialized, "Uninitialized rep thinks it is.")