Bug 1384789 - Check ancestor URLs to avoid sheet cycles. r=bgrins draft
authorJ. Ryan Stinnett <jryans@gmail.com>
Thu, 27 Jul 2017 17:23:22 -0500
changeset 618604 6a09ae11ef368cfd10dda7e486623b080332bcb0
parent 618603 c9fa2d9bd1d83b419c613120ab1a9f1fa3a81a93
child 640135 65ea92745f36fd13580feff7abee4aaae2009f00
push id71403
push userbmo:jryans@gmail.com
push dateMon, 31 Jul 2017 20:25:59 +0000
reviewersbgrins
bugs1384789
milestone56.0a1
Bug 1384789 - Check ancestor URLs to avoid sheet cycles. r=bgrins With Stylo, an import rule from a cycle _will_ have a `styleSheet` object, so we need to also check the sheet's ancestors to see if the URL is unique. MozReview-Commit-ID: B33REaSGGYU
devtools/server/actors/stylesheets.js
--- a/devtools/server/actors/stylesheets.js
+++ b/devtools/server/actors/stylesheets.js
@@ -926,19 +926,24 @@ var StyleSheetsActor = protocol.ActorCla
   _getImported: function (doc, styleSheet) {
     return Task.spawn(function* () {
       let rules = yield styleSheet.getCSSRules();
       let imported = [];
 
       for (let i = 0; i < rules.length; i++) {
         let rule = rules[i];
         if (rule.type == Ci.nsIDOMCSSRule.IMPORT_RULE) {
-          // Associated styleSheet may be null if it has already been seen due
-          // to duplicate @imports for the same URL.
-          if (!rule.styleSheet || !this._shouldListSheet(doc, rule.styleSheet)) {
+          // With the Gecko style system, the associated styleSheet may be null
+          // if it has already been seen because an import cycle for the same
+          // URL.  With Stylo, the styleSheet will exist (which is correct per
+          // the latest CSSOM spec), so we also need to check ancestors for the
+          // same URL to avoid cycles.
+          let sheet = rule.styleSheet;
+          if (!sheet || this._haveAncestorWithSameURL(sheet) ||
+              !this._shouldListSheet(doc, sheet)) {
             continue;
           }
           let actor = this.parentActor.createStyleSheetActor(rule.styleSheet);
           imported.push(actor);
 
           // recurse imports in this stylesheet as well
           let children = yield this._getImported(doc, actor);
           imported = imported.concat(children);
@@ -948,16 +953,33 @@ var StyleSheetsActor = protocol.ActorCla
         }
       }
 
       return imported;
     }.bind(this));
   },
 
   /**
+   * Check all ancestors to see if this sheet's URL matches theirs as a way to
+   * detect an import cycle.
+   *
+   * @param {DOMStyleSheet} sheet
+   */
+  _haveAncestorWithSameURL(sheet) {
+    let sheetHref = sheet.href;
+    while (sheet.parentStyleSheet) {
+      if (sheet.parentStyleSheet.href == sheetHref) {
+        return true;
+      }
+      sheet = sheet.parentStyleSheet;
+    }
+    return false;
+  },
+
+  /**
    * Create a new style sheet in the document with the given text.
    * Return an actor for it.
    *
    * @param  {object} request
    *         Debugging protocol request object, with 'text property'
    * @return {object}
    *         Object with 'styelSheet' property for form on new actor.
    */