Revision: 5481
Author:   [email protected]
Date:     Wed Jul 10 16:40:25 2013
Log:      Bundle virtualization info used by CSS sanitizer into one object.
https://codereview.appspot.com/11052043

Replace domicile.suffixStr and domicile.tagPolicy with an object
domicile.virtualization which contains the same information, and
distinguishes the container class name from the ID suffix. This
reduces the number of independent values passed around and reduces
the number of places that independently compute class from suffix
or vice versa.

Also removed unused function domicile.ident.

[email protected]


http://code.google.com/p/google-caja/source/detail?r=5481

Modified:
 /trunk/src/com/google/caja/plugin/domado.js
 /trunk/src/com/google/caja/plugin/html-emitter.js
 /trunk/src/com/google/caja/plugin/sanitizecss.js
 /trunk/tests/com/google/caja/plugin/css-stylesheet-test.js
 /trunk/tests/com/google/caja/plugin/sanitizecss_test.js

=======================================
--- /trunk/src/com/google/caja/plugin/domado.js Wed Jul 10 16:24:53 2013
+++ /trunk/src/com/google/caja/plugin/domado.js Wed Jul 10 16:40:25 2013
@@ -1792,6 +1792,14 @@
       // directly available to us here).
       taming.untame(naiveUriPolicy);

+      if (!/^-/.test(idSuffix)) {
+ throw new Error('id suffix "' + idSuffix + '" must start with "-"');
+      }
+      if (!/___$/.test(idSuffix)) {
+ throw new Error('id suffix "' + idSuffix + '" must end with "___"');
+      }
+      var idClass = idSuffix.substring(1);
+
       var domicile = {
         // True when we're executing a handler for events like click
         handlingUserAction: false
@@ -2054,6 +2062,22 @@
       }
       var htmlSanitizer = html.makeHtmlSanitizer(tagPolicy);

+      // Bundle of all virtualization info, for use by CSS sanitizer
+      var virtualization = cajaVM.def({
+ // Class name matching the virtual document container. May be null (not
+        // undefined) if we are taming a complete document and there is no
+        // container (note: this case is not yet fully implemented).
+        containerClass: containerNode === document ? null : idClass,
+
+        // Suffix to append to all IDs and ID references.
+        idSuffix: idSuffix,
+
+        // Element/attribute rewriter
+        tagPolicy: tagPolicy
+      });
+      // needed by HtmlEmitter for stylesheet processing
+      domicile.virtualization = virtualization;
+
       /**
        * If str ends with suffix,
        * and str is not identical to suffix,
@@ -3337,10 +3361,7 @@
       }
       function tameQuerySelector(rootFeralNode, guestSelector, returnAll) {
         var virtualizedSelectors = sanitizeCssSelectors(
-          lexCss(guestSelector),
-          idClass,
-          tagPolicy,
-          querySelectorFail);
+          lexCss(guestSelector), virtualization, querySelectorFail);
         var historyInsensitiveVirtualizedSelectors =
           virtualizedSelectors[0].join(',');
         if (returnAll) {
@@ -6380,6 +6401,8 @@
               "CSS_PROP": prop
             });
       });
+      // TODO(kpreid): Consider moving domicile.suffix into the
+      // domicile.virtualization object. Used by caja-flash.js only.
       domicile.suffix = cajaVM.constFunc(function(nmtokens) {
         var p = String(nmtokens).replace(/^\s+|\s+$/g, '').split(/\s+/g);
         var out = [];
@@ -6388,17 +6411,6 @@
           if (!nmtoken) { throw new Error(nmtokens); }
           out.push(nmtoken);
         }
-        return out.join(' ');
-      });
-      domicile.suffixStr = idSuffix;
-      domicile.ident = cajaVM.constFunc(function(nmtokens) {
-        var p = String(nmtokens).replace(/^\s+|\s+$/g, '').split(/\s+/g);
-        var out = [];
-        for (var i = 0; i < p.length; ++i) {
- var nmtoken = rewriteAttribute(null, null, html4.atype.CLASSES, p[+i]);
-          if (!nmtoken) { throw new Error(nmtokens); }
-          out.push(nmtoken);
-        }
         return out.join(' ');
       });
domicile.rewriteUriInCss = cajaVM.constFunc(function(value, propName) {
@@ -6656,15 +6668,7 @@
         e = makeDOMAccessible(e);
         return e;
       });
-      domicile.tagPolicy = tagPolicy;  // used by CSS rewriter

-      if (!/^-/.test(idSuffix)) {
- throw new Error('id suffix "' + idSuffix + '" must start with "-"');
-      }
-      if (!/___$/.test(idSuffix)) {
- throw new Error('id suffix "' + idSuffix + '" must end with "___"');
-      }
-      var idClass = idSuffix.substring(1);
       var idClassPattern = new RegExp(
           '(?:^|\\s)' + idClass.replace(/[\.$]/g, '\\$&') + '(?:\\s|$)');
       /**
=======================================
--- /trunk/src/com/google/caja/plugin/html-emitter.js Mon Jun 24 11:58:58 2013 +++ /trunk/src/com/google/caja/plugin/html-emitter.js Wed Jul 10 16:40:25 2013
@@ -514,10 +514,9 @@
       }
       if (domicile && domicile.emitCss) {
         var sanitized = sanitizeStylesheetWithExternals(styleBaseUri,
-            cssText, domicile.suffixStr.replace(/^-/, ''),
+            cssText, domicile.virtualization,
             makeCssUriSanitizer(styleBaseUri),
             makeCssUriFetcher(styleBaseUri),
-            domicile.tagPolicy,
             continuation);
         if (!sanitized.moreToCome) {
           emitCss(sanitized.result);
=======================================
--- /trunk/src/com/google/caja/plugin/sanitizecss.js Wed Jul 3 20:17:56 2013 +++ /trunk/src/com/google/caja/plugin/sanitizecss.js Wed Jul 10 16:40:25 2013
@@ -308,14 +308,20 @@
   /**
    * Given a series of tokens, returns two lists of sanitized selectors.
    * @param {Array.<string>} selectors In the form produces by csslexer.js.
-   * @param {string} suffix a suffix that is added to all IDs and which is
- * used as a CLASS names so that the returned selectors will only match
-   *    nodes under one with suffix as a class name.
-   *    If suffix is {@code "sfx"}, the selector
+   * @param {{
+   *     containerClass: ?string,
+   *     idSuffix: string,
+   *     tagPolicy: function(string, Array.<string>): ?Array.<string>
+   *   }} virtualization An object like <pre<{
+ * containerClass: class name prepended to all selectors to scope them (if
+   *       not null)
+   *   idSuffix: appended to all ids to scope them
+   *   tagPolicy: As in html-sanitizer, used for rewriting element names.
+   * }</pre>
+ * If containerClass is {@code "sfx"} and idSuffix is {@code "-sfx"}, the
+   *    selector
    *    {@code ["a", "#foo", " ", "b", ".bar"]} will be namespaced to
    *    {@code [".sfx", " ", "a", "#foo-sfx", " ", "b", ".bar"]}.
-   * @param {function(string, Array.<string>): ?Array.<string>} tagPolicy
-   *     As in html-sanitizer, used for rewriting element names.
* @param {function(Array.<string>): boolean} opt_onUntranslatableSelector * When a selector cannot be translated, this function is called with the * non-whitespace/comment tokens comprising the selector and returns a
@@ -328,8 +334,12 @@
    *    contains history-sensitive selectors.
* Null when the untraslatable compound selector handler aborts processing.
    */
-  sanitizeCssSelectors = function (
-      selectors, suffix, tagPolicy, opt_onUntranslatableSelector) {
+  sanitizeCssSelectors = function(
+      selectors, virtualization, opt_onUntranslatableSelector) {
+    var containerClass = virtualization.containerClass;
+    var idSuffix = virtualization.idSuffix;
+    var tagPolicy = virtualization.tagPolicy;
+
// Produce two distinct lists of selectors to sequester selectors that are // history sensitive (:visited), so that we can disallow properties in the
     // property groups for the history sensitive ones.
@@ -430,7 +440,7 @@
               valid = false;
             } else {
               // Rewrite ID elements to include the suffix.
-              classId += tok + '-' + suffix;
+              classId += tok + idSuffix;
             }
           } else if (tok === '.') {
             if (++start < end
@@ -485,7 +495,7 @@
                 // The suffix is case-sensitive, so we can't translate case
                 // ignoring matches.
                 value = '"'
-                  + value.substring(1, value.length-1) + "-" + suffix
+                  + value.substring(1, value.length-1) + idSuffix
                   + '"';
               } else if (op === '|=' || op === '') {
// Ok. a|=b -> a == b || a.startsWith(b + "-") and since we
@@ -547,10 +557,12 @@
       if (valid) {
         if (out.length) {
           var safeSelector = out.join('');
-
+
           // Namespace the selector so that it only matches under
           // a node with suffix in its CLASS attribute.
-          safeSelector = '.' + suffix + ' ' + safeSelector;
+          if (containerClass !== null) {
+            safeSelector = '.' + containerClass + ' ' + safeSelector;
+          }

           (historySensitive
            ? historySensitiveSelectors
@@ -634,27 +646,32 @@
      * @param {string} baseUri a string against which relative urls are
      *    resolved.
      * @param {string} cssText a string containing a CSS stylesheet.
- * @param {string} suffix a suffix that is added to all IDs and which is - * used as a CLASS names so that the returned selectors will only match
-     *    nodes under one with suffix as a class name.
-     *    If suffix is {@code "sfx"}, the selector
+     * @param {{
+     *     containerClass: ?string,
+     *     idSuffix: string,
+     *     tagPolicy: function(string, Array.<string>): ?Array.<string>
+     *   }} virtualization An object like <pre<{
+ * containerClass: class name prepended to all selectors to scope them (if
+     *       not null)
+     *   idSuffix: appended to all ids to scope them
+     *   tagPolicy: As in html-sanitizer, used for rewriting element names.
+     * }</pre>
+ * If containerClass is {@code "sfx"} and idSuffix is {@code "-sfx"}, the
+     *    selector
      *    {@code ["a", "#foo", " ", "b", ".bar"]} will be namespaced to
      *    {@code [".sfx", " ", "a", "#foo-sfx", " ", "b", ".bar"]}.
* @param {function(string, string)} naiveUriRewriter maps URLs of media
      *    (images, sounds) that appear as CSS property values to sanitized
* URLs or null if the URL should not be allowed as an external media
      *    file in sanitized CSS.
-     * @param {function(string, Array.<string>): ?Array.<string>} tagPolicy
-     *     As in html-sanitizer, used for rewriting element names.
* @param {undefined|function(string, boolean)} continuation callback from
      *     external CSS URLs.
* The callback is called with a string, the CSS contents and a boolean, * which is true if the external url itself contained other external
      *     URLs.
      */
-    function sanitizeStylesheetInternal(baseUri, cssText, suffix,
-      naiveUriRewriter, naiveUriFetcher, tagPolicy,
-      continuation) {
+    function sanitizeStylesheetInternal(baseUri, cssText, virtualization,
+      naiveUriRewriter, naiveUriFetcher, continuation) {
       var safeCss = void 0;
       var moreToCome = false;
       // A stack describing the { ... } regions.
@@ -692,9 +709,8 @@
                         function(result) {
                           var sanitized =
                             sanitizeStylesheetInternal(cssUrl, result.html,
-                              suffix,
-                              naiveUriRewriter, naiveUriFetcher, tagPolicy,
-                              continuation);
+                              virtualization,
+ naiveUriRewriter, naiveUriFetcher, continuation); continuation(sanitized.result, sanitized.moreToCome);
                         },
                         naiveUriFetcher);
@@ -737,8 +753,8 @@
               var historySensitiveSelectors = void 0;
               var removeHistoryInsensitiveSelectors = false;
               if (!elide) {
-                var selectors = sanitizeCssSelectors(selectorArray, suffix,
-                    tagPolicy);
+                var selectors = sanitizeCssSelectors(selectorArray,
+                    virtualization);
                 var historyInsensitiveSelectors = selectors[0];
                 historySensitiveSelectors = selectors[1];
                 if (!historyInsensitiveSelectors.length
@@ -823,16 +839,15 @@
     }

     sanitizeStylesheet = function (
-        baseUri, cssText, suffix, naiveUriRewriter, tagPolicy) {
-      return sanitizeStylesheetInternal(baseUri, cssText, suffix,
-        naiveUriRewriter, undefined, tagPolicy, undefined).result;
+        baseUri, cssText, virtualization, naiveUriRewriter) {
+      return sanitizeStylesheetInternal(baseUri, cssText, virtualization,
+        naiveUriRewriter, undefined, undefined).result;
     };

-    sanitizeStylesheetWithExternals = function (baseUri, cssText, suffix,
-      naiveUriRewriter, naiveUriFetcher, tagPolicy,
-      continuation) {
-      return sanitizeStylesheetInternal(baseUri, cssText, suffix,
-        naiveUriRewriter, naiveUriFetcher, tagPolicy, continuation);
+    sanitizeStylesheetWithExternals = function (baseUri, cssText,
+      virtualization, naiveUriRewriter, naiveUriFetcher, continuation) {
+      return sanitizeStylesheetInternal(baseUri, cssText, virtualization,
+        naiveUriRewriter, naiveUriFetcher, continuation);
     };
   })();
 })();
=======================================
--- /trunk/tests/com/google/caja/plugin/css-stylesheet-test.js Mon Apr 29 12:40:55 2013 +++ /trunk/tests/com/google/caja/plugin/css-stylesheet-test.js Wed Jul 10 16:40:25 2013
@@ -14,6 +14,26 @@

 // Called from css-stylesheet-tests.js in a JSONP style.
 function runCssSelectorTests(testGroups) {
+  var virtualization = {
+    containerClass: 'namespace__',
+    idSuffix: '-namespace__',
+    tagPolicy: function(t, a) {
+      // Implementation of virtualization policy for test cases -- the
+      // real version of this lives in html-schema.js.
+      // TODO(kpreid): Arrange so that we can exercise the sanitizer's
+      // behavior given an alternate policy function.
+      var eflags = t in html4.ELEMENTS ? html4.ELEMENTS[t]
+                                       : html4.eflags.VIRTUALIZED;
+      if (eflags & html4.eflags.VIRTUALIZED) {
+        return {'tagName': 'caja-v-' + t};
+      } else if (!(eflags & html4.eflags.UNSAFE)) {
+        return {};
+      } else {
+        return null;
+      }
+    }
+  };
+
   function testCssStylesheets() {
     for (var j = 0, m = testGroups.length; j < m; ++j) {
       var testGroup = testGroups[j];
@@ -30,22 +50,7 @@
             name + ' tests[' + i + '].golden', 'string', typeof golden);

         var actual = sanitizeStylesheet('',
-            test.cssText, 'namespace__', sanitizeUri,
-            function (t, a) {
- // Implementation of virtualization policy for test cases -- the
-              // real version of this lives in html-schema.js.
- // TODO(kpreid): Arrange so that we can exercise the sanitizer's
-              // behavior given an alternate policy function.
-              var eflags = t in html4.ELEMENTS ? html4.ELEMENTS[t]
-                                               : html4.eflags.VIRTUALIZED;
-              if (eflags & html4.eflags.VIRTUALIZED) {
-                return {'tagName': 'caja-v-' + t};
-              } else if (!(eflags & html4.eflags.UNSAFE)) {
-                return {};
-              } else {
-                return null;
-              }
-            });
+            test.cssText, virtualization, sanitizeUri);
         // The Java version produces property groups without a trailing
         // ';' since the semicolon is technically a separator in CSS.
         // This JavaScript version does not because it is simpler to
=======================================
--- /trunk/tests/com/google/caja/plugin/sanitizecss_test.js Wed Jul 3 20:17:56 2013 +++ /trunk/tests/com/google/caja/plugin/sanitizecss_test.js Wed Jul 10 16:40:25 2013
@@ -18,7 +18,12 @@
     source, prefix, expected, opt_onUntranslatableSelector) {
   var tokens = lexCss(source);
   var sanitized = sanitizeCssSelectors(
-    tokens, prefix, function(el, args) { return { tagName: el }; },
+    tokens,
+    {
+      containerClass: prefix,
+      idSuffix: '-' + prefix,
+      tagPolicy: function(el, args) { return { tagName: el }; }
+    },
     opt_onUntranslatableSelector);
   assertArrayEquals(expected, sanitized);
 }
@@ -237,7 +242,12 @@
   var source = 'input.cl\\:a\\3a ss[type = "text"], input#foo\\:bar';
   var tokens = lexCss(source);
   var sanitized = sanitizeCssSelectors(
-    tokens, 'sfx', function(el, args) { return { tagName: el }; });
+    tokens,
+    {
+      containerClass: 'sfx',
+      idSuffix: '-sfx',
+      tagPolicy: function(el, args) { return { tagName: el }; }
+    });
   assertArrayEquals(
     [['.sfx input.cl\\:a\\:ss[type="text"]',
       '.sfx input#foo\\:bar-sfx'], []],

--

--- You received this message because you are subscribed to the Google Groups "Google Caja Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to