Fixes #776 - edge case in quoted data URIs.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 1 Jun 2016 09:10:17 +0000 (11:10 +0200)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 1 Jun 2016 09:19:14 +0000 (11:19 +0200)
Regardless of whether data URI is quoted or not the end of URI should
always be fuzzy matched.

History.md
lib/urls/reduce.js
test/text/urls-processor-test.js

index 07658eb..1b57ee9 100644 (file)
@@ -6,6 +6,7 @@
 [3.4.15 / 2016-xx-xx](https://github.com/jakubpawlowicz/clean-css/compare/v3.4.14...3.4)
 ==================
 
+* Fixed issue [#776](https://github.com/jakubpawlowicz/clean-css/issues/776) - edge case in quoted data URIs.
 * Fixed issue [#779](https://github.com/jakubpawlowicz/clean-css/issues/779) - merging `background-(position|size)`.
 * Fixed issue [#780](https://github.com/jakubpawlowicz/clean-css/issues/780) - space after inlined variables.
 
index 54c4ee7..8dcbab6 100644 (file)
@@ -1,7 +1,9 @@
 var URL_PREFIX = 'url(';
 var UPPERCASE_URL_PREFIX = 'URL(';
 var URL_SUFFIX = ')';
-var DATA_URI_PREFIX = 'data:';
+
+var DATA_URI_PREFIX_PATTERN = /^\s*['"]?\s*data:/;
+var DATA_URI_END_FUZZY_PATTERN = /^\)[\s\{\};]/;
 
 var IMPORT_URL_PREFIX = '@import';
 var UPPERCASE_IMPORT_URL_PREFIX = '@IMPORT';
@@ -27,27 +29,29 @@ function byUrl(data, context, callback) {
     if (nextStart == -1 && nextStartUpperCase > -1)
       nextStart = nextStartUpperCase;
 
+    isDataURI = DATA_URI_PREFIX_PATTERN.test(data.substring(nextStart + URL_PREFIX.length));
 
-    if (data[nextStart + URL_PREFIX.length] == '"') {
-      nextEnd = data.indexOf('"', nextStart + URL_PREFIX.length + 1);
-    } else if (data[nextStart + URL_PREFIX.length] == '\'') {
-      nextEnd = data.indexOf('\'', nextStart + URL_PREFIX.length + 1);
-    } else {
-      isDataURI = data.substring(nextStart + URL_PREFIX.length).trim().indexOf(DATA_URI_PREFIX) === 0;
+    if (isDataURI) {
       nextEnd = data.indexOf(URL_SUFFIX, nextStart);
 
-      if (isDataURI) {
-        // this is a fuzzy matching logic for unqoted data URIs
-        while (true) {
-          nextEndAhead = data.indexOf(URL_SUFFIX, nextEnd + 1);
-          // if it has whitespace, curly braces, or semicolon then we should be out of URL,
-          // otherwise keep iterating if it has not but content is not escaped,
-          // it has to be quoted so it will be captured by either of two clauses above
-          if (nextEndAhead == -1 || /[\s\{\};]/.test(data.substring(nextEnd, nextEndAhead)))
-            break;
-
-          nextEnd = nextEndAhead;
-        }
+      // this is a fuzzy matching logic for unqoted data URIs
+      while (true) {
+        nextEndAhead = data.indexOf(URL_SUFFIX, nextEnd + 1);
+        // if it has whitespace, curly braces, or semicolon then we should be out of URL,
+        // otherwise keep iterating if it has not but content is not escaped,
+        // it has to be quoted so it will be captured by either of two clauses above
+        if (nextEndAhead == -1 || DATA_URI_END_FUZZY_PATTERN.test(data.substring(nextEnd, nextEndAhead)))
+          break;
+
+        nextEnd = nextEndAhead;
+      }
+    } else {
+      if (data[nextStart + URL_PREFIX.length] == '"') {
+        nextEnd = data.indexOf('"', nextStart + URL_PREFIX.length + 1);
+      } else if (data[nextStart + URL_PREFIX.length] == '\'') {
+        nextEnd = data.indexOf('\'', nextStart + URL_PREFIX.length + 1);
+      } else {
+        nextEnd = data.indexOf(URL_SUFFIX, nextStart);
       }
     }
 
index ff66f76..04974ed 100644 (file)
@@ -85,6 +85,16 @@ vows.describe(UrlsProcessor)
         'a{background:url(url)}div:not([test]){color:red}',
         'a{background:__ESCAPED_URL_CLEAN_CSS0__}div:not([test]){color:red}',
         'a{background:url(url)}div:not([test]){color:red}'
+      ],
+      'data URI with single brackets': [
+        'a{background-image:url(\'data:image/svg+xml;charset=utf-8,<svg viewBox=\'0 0 120 120\'><g transform=\'rotate(30 60,60)\'></g></svg>\')}',
+        'a{background-image:__ESCAPED_URL_CLEAN_CSS0__}',
+        'a{background-image:url(\'data:image/svg+xml;charset=utf-8,<svg viewBox=\'0 0 120 120\'><g transform=\'rotate(30 60,60)\'></g></svg>\')}'
+      ],
+      'data URI with double brackets': [
+        'a{background-image:url("data:image/svg+xml;charset=utf-8,<svg viewBox=\'0 0 120 120\'><g transform=\'rotate(30 60,60)\'></g></svg>")}',
+        'a{background-image:__ESCAPED_URL_CLEAN_CSS0__}',
+        'a{background-image:url("data:image/svg+xml;charset=utf-8,<svg viewBox=\'0 0 120 120\'><g transform=\'rotate(30 60,60)\'></g></svg>")}'
       ]
     })
   )