Skip to content

Commit

Permalink
fix(url parsing): fix url edge case parsing in images and links
Browse files Browse the repository at this point in the history
Allow some edge cases to parse correctly. Example:
`![img](.images/cat(1).png)`,
`![img](<.image(1)/cat(1).png>)`,
`[link](<>)`
  • Loading branch information
tivie committed May 30, 2017
1 parent 230f443 commit 30aa18c
Show file tree
Hide file tree
Showing 18 changed files with 147 additions and 46 deletions.
49 changes: 28 additions & 21 deletions dist/showdown.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/showdown.js.map

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/showdown.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/showdown.min.js.map

Large diffs are not rendered by default.

35 changes: 17 additions & 18 deletions src/subParsers/anchors.js
Expand Up @@ -6,17 +6,16 @@ showdown.subParser('anchors', function (text, options, globals) {

text = globals.converter._dispatch('anchors.before', text, options, globals);

var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
if (showdown.helper.isUndefined(m7)) {
m7 = '';
var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) {
if (showdown.helper.isUndefined(title)) {
title = '';
}
wholeMatch = m1;
var linkText = m2,
linkId = m3.toLowerCase(),
url = m4,
title = m7;
linkId = linkId.toLowerCase();

if (!url) {
// Special case for explicit empty url
if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
url = '';
} else if (!url) {
if (!linkId) {
// lower-case and turn embedded newlines into spaces
linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
Expand All @@ -29,12 +28,7 @@ showdown.subParser('anchors', function (text, options, globals) {
title = globals.gTitles[linkId];
}
} else {
if (wholeMatch.search(/\(\s*\)$/m) > -1) {
// Special case for explicit empty url
url = '';
} else {
return wholeMatch;
}
return wholeMatch;
}
}

Expand All @@ -61,16 +55,21 @@ showdown.subParser('anchors', function (text, options, globals) {
};

// First, handle reference-style links: [link text] [id]
text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);
text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g, writeAnchorTag);

// Next, inline-style links: [link text](url "optional title")
text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
// cases with crazy urls like ./image/cat1).png
text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
writeAnchorTag);

// normal cases
text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
writeAnchorTag);

// handle reference-style shortcuts: [link text]
// These must come last in case you've also got [link test][1]
// or [link test](/foo)
text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);
text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag);

// Lastly handle GithubMentions if option is enabled
if (options.ghMentions) {
Expand Down
12 changes: 10 additions & 2 deletions src/subParsers/images.js
Expand Up @@ -6,7 +6,8 @@ showdown.subParser('images', function (text, options, globals) {

text = globals.converter._dispatch('images.before', text, options, globals);

var inlineRegExp = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,
var inlineRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,
crazyRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,
referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g,
refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g;

Expand All @@ -21,8 +22,11 @@ showdown.subParser('images', function (text, options, globals) {
if (!title) {
title = '';
}
// Special case for explicit empty url
if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
url = '';

if (url === '' || url === null) {
} else if (url === '' || url === null) {
if (linkId === '' || linkId === null) {
// lower-case and turn embedded newlines into spaces
linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
Expand Down Expand Up @@ -76,6 +80,10 @@ showdown.subParser('images', function (text, options, globals) {
text = text.replace(referenceRegExp, writeImageTag);

// Next, handle inline images: ![alt text](url =<width>x<height> "optional title")
// cases with crazy urls like ./image/cat1).png
text = text.replace(crazyRegExp, writeImageTag);

// normal cases
text = text.replace(inlineRegExp, writeImageTag);

// handle reference-style shortcuts: |[img text]
Expand Down
4 changes: 4 additions & 0 deletions test/cases/anchors-followed-by-brakets.html
@@ -0,0 +1,4 @@
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile">link</a> (some other text)</p>
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup">link</a> (some other text)</p>
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)">link</a> (some other text)</p>
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)/foo">link</a> (some other text)</p>
7 changes: 7 additions & 0 deletions test/cases/anchors-followed-by-brakets.md
@@ -0,0 +1,7 @@
This is a [link](https://en.wikipedia.org/wiki/Textile) (some other text)

This is a [link](https://en.wikipedia.org/wiki/Textile_(markup) (some other text)

This is a [link](https://en.wikipedia.org/wiki/Textile_(markup_language)) (some other text)

This is a [link](https://en.wikipedia.org/wiki/Textile_(markup_language)/foo) (some other text)
2 changes: 2 additions & 0 deletions test/cases/images-followed-by-brackets.html
@@ -0,0 +1,2 @@
<p><img src="./image/cat1.png" alt="image link" />(some text between brackets)</p>
<p><img src="./image/cat(1).png" alt="image link" />(some text between brackets)</p>
3 changes: 3 additions & 0 deletions test/cases/images-followed-by-brackets.md
@@ -0,0 +1,3 @@
![image link](<./image/cat1.png>)(some text between brackets)

![image link](<./image/cat(1).png>)(some text between brackets)
4 changes: 4 additions & 0 deletions test/issues/#390.brackets-in-URL-break-images.html
@@ -0,0 +1,4 @@
<p>This is an <img src="./image/cat(1).png" alt="image" /></p>
<p>This is another <img src="./image/cat(1).png" alt="image" /></p>
<p><a href="http://example.com"><img src="./image/cat(1).png" alt="image link" /></a></p>
<p><a href="http://example.com"><img src="./image/cat1).png" alt="image link" /></a></p>
9 changes: 9 additions & 0 deletions test/issues/#390.brackets-in-URL-break-images.md
@@ -0,0 +1,9 @@
This is an ![image][]

[image]: ./image/cat(1).png

This is another ![image](./image/cat(1).png)

[![image link](./image/cat(1).png)](http://example.com)

[![image link](<./image/cat1).png>)](http://example.com)
1 change: 1 addition & 0 deletions test/issues/#390.brackets-in-URL-break-links.html
@@ -1,2 +1,3 @@
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)" title="Textile">link</a>.</p>
<p>This is another <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)" title="Textile">link</a>.</p>
<p><a href="./image/cat1).png" title="title">link</a></p>
2 changes: 2 additions & 0 deletions test/issues/#390.brackets-in-URL-break-links.md
Expand Up @@ -3,3 +3,5 @@ This is a [link][].
[link]: https://en.wikipedia.org/wiki/Textile_(markup_language) "Textile"

This is another [link](https://en.wikipedia.org/wiki/Textile_(markup_language) "Textile").

[link](<./image/cat1).png> "title")
5 changes: 5 additions & 0 deletions test/issues/URLs-with-multiple-parenthesis.html
@@ -0,0 +1,5 @@
<p><a href="./images(1)/cat(1).png">link</a></p>
<p><a href="./images(1)/cat(1).png" title="title">link</a></p>
<p><img src="./images(1)/cat(1).png" alt="image" /></p>
<p><img src="./images(1)/cat(1).png" alt="image" title="title" /></p>
<p><img src="./images(1)/cat(1).png" alt="image" title="title" width="800" height="600" /></p>
9 changes: 9 additions & 0 deletions test/issues/URLs-with-multiple-parenthesis.md
@@ -0,0 +1,9 @@
[link](<./images(1)/cat(1).png>)

[link](<./images(1)/cat(1).png> "title")

![image](<./images(1)/cat(1).png>)

![image](<./images(1)/cat(1).png> "title")

![image](<./images(1)/cat(1).png> =800x600 "title")
14 changes: 14 additions & 0 deletions test/issues/crazy-urls.html
@@ -0,0 +1,14 @@
<p><img src="images(1)/cat(1).png" alt="my cat" /></p>
<p><a href="images(1)/cat(1).png">my cat</a></p>
<p><img src="some.com/crazy url with spaces" alt="foo" /></p>
<p><img src="some.com/crazy url with spaces" alt="foo" title="title" /></p>
<p><a href="some.com/crazy url with spaces">foo</a></p>
<p><a href="some.com/crazy url with spaces" title="title">foo</a></p>
<p><img src="" alt="empty" /></p>
<p><a href="">empty</a></p>
<p><img src="" alt="empty" title="title" /></p>
<p><a href="" title="title">empty</a></p>
<p><img src="" alt="empty" /></p>
<p><a href="">empty</a></p>
<p><img src="" alt="empty" title="title" /></p>
<p><a href="" title="title">empty</a></p>
27 changes: 27 additions & 0 deletions test/issues/crazy-urls.md
@@ -0,0 +1,27 @@
![my cat](<images(1)/cat(1).png>)

[my cat](<images(1)/cat(1).png>)

![foo](<some.com/crazy url with spaces>)

![foo](<some.com/crazy url with spaces> "title")

[foo](<some.com/crazy url with spaces>)

[foo](<some.com/crazy url with spaces> "title")

![empty](<>)

[empty](<>)

![empty](<> "title")

[empty](<> "title")

![empty](< >)

[empty](< >)

![empty](< > "title")

[empty](< > "title")

0 comments on commit 30aa18c

Please sign in to comment.