From 090debd9b4e9c865ea64a3085d8a0933970e3954 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Mon, 16 Apr 2018 21:51:28 -0500 Subject: [PATCH 1/5] move processing --- lib/marked.js | 81 ++++++++++----------------------------------------- 1 file changed, 16 insertions(+), 65 deletions(-) diff --git a/lib/marked.js b/lib/marked.js index 1ecfc3ee8d..7128ebddf2 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -554,68 +554,9 @@ inline.normal = merge({}, inline); inline.pedantic = merge({}, inline.normal, { strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/, - /* Original link re: /^!?\[(label)\]\(\s*?(?:\s+(['"][\s\S]*?['"]))?\s*\)/ - * This captures the spec reasonably well but is vulnerable to REDOS. - * Instead we use a custom parser that follows the RegExp.exec semantics. */ - link: { - exec: function (s) { - // [TEXT](DESTINATION) - var generalLinkRe = edit(/^!?\[(label)\]\((.*?)\)/) - .replace('label', inline._label) - .getRegex(); - - // destination: DESTINATION from generalLinkRe - // returns [destination, title]: no angle-brackets on destination, no quotes on title - function splitIntoDestinationAndTitle (destination) { - function unwrapAngleBrackets (str) { - if (str.match(/^<.*>$/)) { - str = str.slice(1, -1); - } - return str; - } - - // Valid DESTINATIONs, in decreasing specificity. - var destinationAndTitleRe = /^([^'"(]*[^\s])\s+(['"(].*['")])/; - var destinationRe = /^(?)/; - var parsingRegexes = [destinationAndTitleRe, destinationRe]; - - var match = false; - for (var i = 0; i < parsingRegexes.length; i++) { - match = parsingRegexes[i].exec(destination); - if (match) { - break; - } - } - - if (!match) { - return null; - } - - var dest = match[1]; - var title = match[2] || ''; // Not all parsingRegexes have 2 groups. - - // Format dest. - dest = dest.trim(); - dest = unwrapAngleBrackets(dest); - - return [dest, title]; - } - - var fullMatch = generalLinkRe.exec(s); - if (!fullMatch) { - return null; - } - - var text = fullMatch[1]; - var destination = fullMatch[2]; - - var destinationAndTitle = splitIntoDestinationAndTitle(destination); - if (!destinationAndTitle) { - return null; - } - return [fullMatch[0], text, destinationAndTitle[0], destinationAndTitle[1]]; - } - }, + link: edit(/^!?\[(label)\]\((.*?)\)/) + .replace('label', inline._label) + .getRegex(), reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/) .replace('label', inline._label) .getRegex() @@ -761,9 +702,19 @@ InlineLexer.prototype.output = function(src) { if (cap = this.rules.link.exec(src)) { src = src.substring(cap[0].length); this.inLink = true; - href = cap[2]; - href = href[0] === '<' ? href.substring(1, href.length - 1) : href; - title = cap[3] ? cap[3].substring(1, cap[3].length - 1) : cap[3]; + href = cap[2].trim(); + if (this.options.pedantic) { + link = /^([^'"(]*[^\s])\s+(['"(].*['")])/.exec(href); + + if (link) { + href = link[1]; + title = link[2].trim().slice(1, -1); + } + href = href.trim(); + } else { + title = cap[3] ? cap[3].slice(1, -1) : cap[3]; + } + href = href[0] === '<' ? href.slice(1, -1) : href; out += this.outputLink(cap, { href: InlineLexer.escapes(href), title: InlineLexer.escapes(title) From 4b7cfbe8f2126f1724ce87371adddfd944da8157 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Mon, 16 Apr 2018 22:05:02 -0500 Subject: [PATCH 2/5] remove unnecessary trim --- lib/marked.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/marked.js b/lib/marked.js index 7128ebddf2..de2cf88e72 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -702,7 +702,7 @@ InlineLexer.prototype.output = function(src) { if (cap = this.rules.link.exec(src)) { src = src.substring(cap[0].length); this.inLink = true; - href = cap[2].trim(); + href = cap[2]; if (this.options.pedantic) { link = /^([^'"(]*[^\s])\s+(['"(].*['")])/.exec(href); From 5bc83ea8a6dcebd2e35ee7971f81800a03039322 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Mon, 16 Apr 2018 22:16:36 -0500 Subject: [PATCH 3/5] fix href `<` --- lib/marked.js | 2 +- test/new/link_lt.html | 1 + test/new/link_lt.md | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 test/new/link_lt.html create mode 100644 test/new/link_lt.md diff --git a/lib/marked.js b/lib/marked.js index de2cf88e72..7845b6b140 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -714,7 +714,7 @@ InlineLexer.prototype.output = function(src) { } else { title = cap[3] ? cap[3].slice(1, -1) : cap[3]; } - href = href[0] === '<' ? href.slice(1, -1) : href; + href = href.replace(/^<([\s\S]*)>$/, '$1'); out += this.outputLink(cap, { href: InlineLexer.escapes(href), title: InlineLexer.escapes(title) diff --git a/test/new/link_lt.html b/test/new/link_lt.html new file mode 100644 index 0000000000..ea48caa950 --- /dev/null +++ b/test/new/link_lt.html @@ -0,0 +1 @@ +

URL

diff --git a/test/new/link_lt.md b/test/new/link_lt.md new file mode 100644 index 0000000000..f4f9adddc9 --- /dev/null +++ b/test/new/link_lt.md @@ -0,0 +1 @@ +[URL]( Date: Tue, 17 Apr 2018 09:43:47 -0500 Subject: [PATCH 4/5] remove () around pedantic title --- lib/marked.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/marked.js b/lib/marked.js index 7845b6b140..eb8faefc8f 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -704,11 +704,11 @@ InlineLexer.prototype.output = function(src) { this.inLink = true; href = cap[2]; if (this.options.pedantic) { - link = /^([^'"(]*[^\s])\s+(['"(].*['")])/.exec(href); + link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); if (link) { href = link[1]; - title = link[2].trim().slice(1, -1); + title = link[3]; } href = href.trim(); } else { From 686999863864679ac25016574a9b064a4498fb1f Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 17 Apr 2018 13:27:18 -0500 Subject: [PATCH 5/5] set title to empty string --- lib/marked.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/marked.js b/lib/marked.js index eb8faefc8f..1fe8ba45ac 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -709,12 +709,13 @@ InlineLexer.prototype.output = function(src) { if (link) { href = link[1]; title = link[3]; + } else { + title = ''; } - href = href.trim(); } else { - title = cap[3] ? cap[3].slice(1, -1) : cap[3]; + title = cap[3] ? cap[3].slice(1, -1) : ''; } - href = href.replace(/^<([\s\S]*)>$/, '$1'); + href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); out += this.outputLink(cap, { href: InlineLexer.escapes(href), title: InlineLexer.escapes(title)