From: Jakub Pawlowicz Date: Thu, 2 Jun 2016 06:57:57 +0000 (+0200) Subject: Fixes #782 - regression in processing data URIs. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=c9c571f312a5011fb7cf8f5433d58f53c26eb8b5;p=clean-css.git Fixes #782 - regression in processing data URIs. Instead of trying to fuzzy match an end of data URI let's use split to navigate through bracket levels and determine an end of an URI. --- diff --git a/History.md b/History.md index 93f88085..00d0b11c 100644 --- a/History.md +++ b/History.md @@ -7,6 +7,7 @@ ================== * Fixed issue [#781](https://github.com/jakubpawlowicz/clean-css/issues/781) - regression in override compacting. +* Fixed issue [#782](https://github.com/jakubpawlowicz/clean-css/issues/782) - regression in processing data URIs. [3.4.15 / 2016-06-01](https://github.com/jakubpawlowicz/clean-css/compare/v3.4.14...v3.4.15) ================== diff --git a/lib/urls/reduce.js b/lib/urls/reduce.js index 8dcbab68..783277e0 100644 --- a/lib/urls/reduce.js +++ b/lib/urls/reduce.js @@ -1,9 +1,11 @@ +var split = require('../utils/split'); + var URL_PREFIX = 'url('; var UPPERCASE_URL_PREFIX = 'URL('; var URL_SUFFIX = ')'; var DATA_URI_PREFIX_PATTERN = /^\s*['"]?\s*data:/; -var DATA_URI_END_FUZZY_PATTERN = /^\)[\s\{\};]/; +var DATA_URI_TRAILER_PATTERN = /[\s\};,\/]/; var IMPORT_URL_PREFIX = '@import'; var UPPERCASE_IMPORT_URL_PREFIX = '@IMPORT'; @@ -14,7 +16,7 @@ function byUrl(data, context, callback) { var nextStart = 0; var nextStartUpperCase = 0; var nextEnd = 0; - var nextEndAhead = 0; + var firstMatch; var isDataURI = false; var cursor = 0; var tempData = []; @@ -32,18 +34,12 @@ function byUrl(data, context, callback) { isDataURI = DATA_URI_PREFIX_PATTERN.test(data.substring(nextStart + URL_PREFIX.length)); if (isDataURI) { - nextEnd = data.indexOf(URL_SUFFIX, nextStart); - - // 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; + firstMatch = split(data.substring(nextStart), DATA_URI_TRAILER_PATTERN, false, '(', ')', true).pop(); + + if (firstMatch && firstMatch[firstMatch.length - 1] == URL_SUFFIX) { + nextEnd = nextStart + firstMatch.length - URL_SUFFIX.length; + } else { + nextEnd = -1; } } else { if (data[nextStart + URL_PREFIX.length] == '"') { diff --git a/lib/utils/split.js b/lib/utils/split.js index 178c7393..899ce299 100644 --- a/lib/utils/split.js +++ b/lib/utils/split.js @@ -1,4 +1,4 @@ -function split(value, separator, includeSeparator, openLevel, closeLevel) { +function split(value, separator, includeSeparator, openLevel, closeLevel, firstOnly) { var withRegex = typeof separator != 'string'; var hasSeparator = withRegex ? separator.test(value) : @@ -10,7 +10,7 @@ function split(value, separator, includeSeparator, openLevel, closeLevel) { openLevel = openLevel || '('; closeLevel = closeLevel || ')'; - if (value.indexOf(openLevel) == -1 && !includeSeparator) + if (value.indexOf(openLevel) == -1 && !includeSeparator && !firstOnly) return value.split(separator); var level = 0; @@ -29,6 +29,10 @@ function split(value, separator, includeSeparator, openLevel, closeLevel) { if (level === 0 && cursor > 0 && cursor + 1 < len && (withRegex ? separator.test(value[cursor]) : value[cursor] == separator)) { tokens.push(value.substring(lastStart, cursor + (includeSeparator ? 1 : 0))); lastStart = cursor + 1; + + if (firstOnly && tokens.length == 1) { + break; + } } cursor++; diff --git a/test/text/urls-processor-test.js b/test/text/urls-processor-test.js index 04974ed7..54111dfb 100644 --- a/test/text/urls-processor-test.js +++ b/test/text/urls-processor-test.js @@ -86,15 +86,20 @@ vows.describe(UrlsProcessor) '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': [ + 'data URI wrapped in single quotes': [ 'a{background-image:url(\'data:image/svg+xml;charset=utf-8,\')}', 'a{background-image:__ESCAPED_URL_CLEAN_CSS0__}', 'a{background-image:url(\'data:image/svg+xml;charset=utf-8,\')}' ], - 'data URI with double brackets': [ + 'data URI wrapped in double quotes': [ 'a{background-image:url("data:image/svg+xml;charset=utf-8,")}', 'a{background-image:__ESCAPED_URL_CLEAN_CSS0__}', 'a{background-image:url("data:image/svg+xml;charset=utf-8,")}' + ], + 'two quoted data URIs with closing brackets': [ + '.a{cursor:url("data:application/octet-stream;base64,A...rotate(30 60,60)...="),move!important}.b{cursor:url("data:application/octet-stream;base64,A...rotate(30 60,60)...=")}', + '.a{cursor:__ESCAPED_URL_CLEAN_CSS0__,move!important}.b{cursor:__ESCAPED_URL_CLEAN_CSS0__}', + '.a{cursor:url("data:application/octet-stream;base64,A...rotate(30 60,60)...="),move!important}.b{cursor:url("data:application/octet-stream;base64,A...rotate(30 60,60)...=")}', ] }) ) diff --git a/test/utils/split-test.js b/test/utils/split-test.js index 93570914..ab0835e9 100644 --- a/test/utils/split-test.js +++ b/test/utils/split-test.js @@ -129,4 +129,24 @@ vows.describe(split) } } }) + .addBatch({ + 'just first one': { + topic: 'linear-gradient(0, #fff, rgba(0, 0, 0)) red', + split: function (input) { + assert.deepEqual(split(input, ' ', false, '(', ')', true), ['linear-gradient(0, #fff, rgba(0, 0, 0))']); + } + }, + 'just first one when no opening token': { + topic: 'red blue', + split: function (input) { + assert.deepEqual(split(input, ' ', false, '(', ')', true), ['red']); + } + }, + 'just first one when no closing token in last token': { + topic: 'red linear-gradient(0 0', + split: function (input) { + assert.deepEqual(split(input, ' ', false, '(', ')', true), ['red']); + } + } + }) .export(module);