Skip to content

Commit 04b4e34

Browse files
committed
Fix regex for css property url extraction
When there are parentheses in the pattern it would match incorrectly. Cherry-picked from PR#204
1 parent 2b1bfbb commit 04b4e34

4 files changed

Lines changed: 46 additions & 14 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ DOLCIMASCOLO (packaging), Zee (ZM) @zm-cttae (many major updates), Joshua Walsh
404404
(useCredentialsFilters), Aravind @codesculpture (fix overridden props), Shi Wenyu @cWenyu
405405
(shadow slot fix), David Burns @davidburns573 and Yujia Cheng @YujiaCheng1996 (font copy
406406
optional), Julien Dorra @juliendorra (documentation), Sean Zhang @SeanZhang-eaton (regex
407-
fixes)
407+
fixes), Ludovic Bouges @ludovic (style property filter), Roland Ma @RolandMa1986 (URL
408+
regex)"
408409

409410
## License
410411

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@
7070
"David Burns @davidburns573",
7171
"Yujia Cheng @YujiaCheng1996",
7272
"Julien Dorra @juliendorra",
73-
"Sean Zhang @SeanZhang-eaton"
73+
"Sean Zhang @SeanZhang-eaton",
74+
"Ludovic Bouges @ludovic",
75+
"Roland Ma @RolandMa1986"
7476
],
7577
"license": "MIT",
7678
"bugs": {

spec/dom-to-image-more.spec.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,9 +761,14 @@
761761
describe('inliner', function () {
762762
const NO_BASE_URL = null;
763763

764+
it('should process urls', function () {
765+
const should = domtoimage.impl.inliner.shouldProcess;
766+
assert.deepEqual(should('url("http://acme.com/file")'), true);
767+
assert.deepEqual(should('nope("http://acme.com/file")'), false);
768+
});
769+
764770
it('should parse urls', function () {
765771
const parse = domtoimage.impl.inliner.impl.readUrls;
766-
767772
assert.deepEqual(parse('url("http://acme.com/file")'), [
768773
'http://acme.com/file',
769774
]);
@@ -776,10 +781,35 @@
776781

777782
it('should ignore data urls', function () {
778783
const parse = domtoimage.impl.inliner.impl.readUrls;
779-
780784
assert.deepEqual(parse('url(foo.com), url(data:AAA)'), ['foo.com']);
781785
});
782786

787+
it('should build a decent escaped regex urls', function () {
788+
const regexer = domtoimage.impl.inliner.impl.urlAsRegex;
789+
790+
one('http://foo.com', 'url("http://foo.com")', '"');
791+
one('http://foo.com', "url('http://foo.com')", "'");
792+
one('http://foo.com', 'url(http://foo.com)', '');
793+
one(
794+
'http://foo.com',
795+
'url("http://bar.org") and url(\'http://foo.com\')',
796+
"'"
797+
);
798+
one('https://example.org', 'url(ping.png)', null);
799+
800+
function one(input, css, expectation) {
801+
const pattern = regexer(input);
802+
const findings = pattern.exec(css);
803+
//console.log({ pattern: pattern.toString(), input, css, findings, expectation});
804+
805+
if (findings) {
806+
assert.deepEqual(findings.slice(1, 3), [expectation, input]);
807+
} else {
808+
assert.isNull(expectation);
809+
}
810+
}
811+
});
812+
783813
it('should inline url', function (done) {
784814
const inline = domtoimage.impl.inliner.impl.inline;
785815

src/dom-to-image-more.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,14 +1035,15 @@
10351035
}
10361036

10371037
function newInliner() {
1038-
const URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/g;
1038+
const URL_REGEX = /url\((["']?)((?:\\?.)*?)\1\)/gm;
10391039

10401040
return {
10411041
inlineAll: inlineAll,
10421042
shouldProcess: shouldProcess,
10431043
impl: {
10441044
readUrls: readUrls,
10451045
inline: inline,
1046+
urlAsRegex: urlAsRegex,
10461047
},
10471048
};
10481049

@@ -1054,29 +1055,27 @@
10541055
const result = [];
10551056
let match;
10561057
while ((match = URL_REGEX.exec(string)) !== null) {
1057-
result.push(match[1]);
1058+
result.push(match[2]);
10581059
}
10591060
return result.filter(function (url) {
10601061
return !util.isDataUrl(url);
10611062
});
10621063
}
10631064

1065+
function urlAsRegex(urlValue) {
1066+
return new RegExp(`url\\((["']?)(${util.escape(urlValue)})\\1\\)`, 'gm');
1067+
}
1068+
10641069
function inline(string, url, baseUrl, get) {
10651070
return Promise.resolve(url)
10661071
.then(function (urlValue) {
10671072
return baseUrl ? util.resolveUrl(urlValue, baseUrl) : urlValue;
10681073
})
10691074
.then(get || util.getAndEncode)
10701075
.then(function (dataUrl) {
1071-
return string.replace(urlAsRegex(url), `$1${dataUrl}$3`);
1076+
const pattern = urlAsRegex(url);
1077+
return string.replace(pattern, `url($1${dataUrl}$1)`);
10721078
});
1073-
1074-
function urlAsRegex(urlValue) {
1075-
return new RegExp(
1076-
`(url\\(['"]?)(${util.escape(urlValue)})(['"]?\\))`,
1077-
'g'
1078-
);
1079-
}
10801079
}
10811080

10821081
function inlineAll(string, baseUrl, get) {

0 commit comments

Comments
 (0)