Fixes #633 - handling data URI with brackets.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 5 Aug 2015 06:45:51 +0000 (07:45 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Thu, 6 Aug 2015 08:39:37 +0000 (09:39 +0100)
We need to identify cases when data URI are escaped (and brackets
are not) so we can get the whole URI.

History.md
lib/urls/reduce.js
test/integration-test.js

index 99fd231..bfaac34 100644 (file)
@@ -8,6 +8,7 @@
 ==================
 
 * Fixed issue [#630](https://github.com/jakubpawlowicz/clean-css/issues/630) - vendor prefixed flex optimizations.
+* Fixed issue [#633](https://github.com/jakubpawlowicz/clean-css/issues/633) - handling data URI with brackets.
 
 [3.3.7 / 2015-07-29](https://github.com/jakubpawlowicz/clean-css/compare/v3.3.6...v3.3.7)
 ==================
index 4a5fa54..1f7d7fd 100644 (file)
@@ -9,6 +9,7 @@ function byUrl(data, context, callback) {
   var nextStart = 0;
   var nextStartUpperCase = 0;
   var nextEnd = 0;
+  var nextEndAhead = 0;
   var cursor = 0;
   var tempData = [];
   var hasUppercaseUrl = data.indexOf(UPPERCASE_URL_PREFIX) > -1;
@@ -22,13 +23,26 @@ function byUrl(data, context, callback) {
     if (nextStart == -1 && nextStartUpperCase > -1)
       nextStart = nextStartUpperCase;
 
-    if (data[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] == '\'')
+    } else if (data[nextStart + URL_PREFIX.length] == '\'') {
       nextEnd = data.indexOf('\'', nextStart + URL_PREFIX.length + 1);
-    else
+    } else {
       nextEnd = data.indexOf(URL_SUFFIX, nextStart);
 
+      while (true) {
+        nextEndAhead = data.indexOf(URL_SUFFIX, nextEnd + 1);
+        // if it has whitespace 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;
+      }
+    }
+
+
     // Following lines are a safety mechanism to ensure
     // incorrectly terminated urls are processed correctly.
     if (nextEnd == -1) {
index 997ffc9..59a3b27 100644 (file)
@@ -1346,6 +1346,14 @@ vows.describe('integration tests')
       'keep quoting if whitespace inside @font-face': [
         '@font-face{src:url("/Helvetica Neue.eot")}',
         '@font-face{src:url(\'/Helvetica Neue.eot\')}'
+      ],
+      'keep SVG data URI unchanged for background-uri': [
+        'div{background-image:url(data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2018%2018%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%2214%22%20height%3D%2214%22%20transform%3D%22translate(2%202)%22%2F%3E%3C%2Fsvg%3E)}',
+        'div{background-image:url(data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2018%2018%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%2214%22%20height%3D%2214%22%20transform%3D%22translate(2%202)%22%2F%3E%3C%2Fsvg%3E)}'
+      ],
+      'keep SVG data URI unchanged1 for background': [
+        'div{background:url(data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2018%2018%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%2214%22%20height%3D%2214%22%20transform%3D%22translate(2%202)%22%2F%3E%3C%2Fsvg%3E) bottom left}',
+        'div{background:url(data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2018%2018%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%2214%22%20height%3D%2214%22%20transform%3D%22translate(2%202)%22%2F%3E%3C%2Fsvg%3E) bottom left}'
       ]
     }, { root: process.cwd(), relativeTo: process.cwd() })
   )