Repository: raphlinus/pulldown-cmark (rust)

Issue:
[fuzz test] link labels should be trimmed
```markdown
[
a]: https://example.com

[a]
```

The link label should match the link, but doesn't in pulldown-cmark.

Pull request description:
Trim spaces off start and end of link reference
Fixes #793

This is specifically called out by [the spec]:

> One label matches another just in case their normalized forms are equal. To normalize a label, strip off the opening and closing brackets, perform the Unicode case fold, **strip leading and trailing spaces, tabs, and line endings**, and collapse consecutive internal spaces, tabs, and line endings to a single space. If there are multiple matching reference link definitions, the one that comes first in the document is used. (It is desirable in such cases to emit a warning.)

[the spec]: https://spec.commonmark.org/0.30/#matches

Patch:
diff --git a/specs/regression.txt b/specs/regression.txt
index 81664e6..9b67e58 100644
--- a/specs/regression.txt
+++ b/specs/regression.txt
@@ -2006,4 +2006,19 @@ ISSUE 791
 <a href="https://example.com" title="[foo]">foo</a>
 </li>
 </ul>
-````````````````````````````````
\ No newline at end of file
+````````````````````````````````
+
+
+ISSUE 793
+
+```````````````````````````````` example
+[
+a]: https://example.com
+
+[b
+]: https://example.com
+
+[a] [b]
+.
+<p><a href="https://example.com">a</a> <a href="https://example.com">b</a></p>
+````````````````````````````````
diff --git a/src/linklabel.rs b/src/linklabel.rs
index 83f0ecc..655bdc7 100644
--- a/src/linklabel.rs
+++ b/src/linklabel.rs
@@ -108,9 +108,16 @@ pub(crate) fn scan_link_label_rest<'t>(
         None
     } else {
         let cow = if mark == 0 {
-            text[..ix].into()
+            let asciiws = &[' ', '\r', '\n', '\t'][..];
+            text[..ix].trim_matches(asciiws).into()
         } else {
             label.push_str(&text[mark..ix]);
+            while matches!(label.as_bytes().last(), Some(&b' ' | &b'\r' | &b'\n' | &b'\t')) {
+                label.pop();
+            }
+            while matches!(label.as_bytes().first(), Some(&b' ' | &b'\r' | &b'\n' | &b'\t')) {
+                label.remove(0);
+            }
             label.into()
         };
         Some((ix + 1, cow))


Test patch:
diff --git a/tests/suite/regression.rs b/tests/suite/regression.rs
index 6db31bb..66fb308 100644
--- a/tests/suite/regression.rs
+++ b/tests/suite/regression.rs
@@ -2369,5 +2369,21 @@ fn regression_test_147() {
 </li>
 </ul>
 "##;
+    test_markdown_html(original, expected, false, false, false);
+}
+
+#[test]
+fn regression_test_148() {
+      let original = r##"[
+a]: https://example.com
+
+[b
+]: https://example.com
+
+[a] [b]
+"##;
+    let expected = r##"<p><a href="https://example.com">a</a> <a href="https://example.com">b</a></p>
+"##;
+
     test_markdown_html(original, expected, false, false, false);
 }
\ No newline at end of file