diff --git a/README.md b/README.md index 14777d1f..9a38ce09 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,8 @@ Options: Enable relaxing which character is allowed in a tasklists --relaxed-autolinks - Enable relaxing of autolink parsing, allowing links to be recognized when in brackets + Enable relaxing of autolink parsing, allow links to be recognized when in brackets + and allow all url schemes --default-info-string Default value for fenced code block's info strings if none is given diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 5e73097d..c941efaa 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -135,6 +135,7 @@ dependencies = [ "derive_builder", "emojis", "entities", + "in-place", "memchr", "once_cell", "regex", @@ -302,6 +303,15 @@ dependencies = [ "regex", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "flate2" version = "1.0.25" @@ -353,6 +363,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "in-place" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cdb69f3adfd5f493210cece799f4620417bf9965bc1536c22ae0e29ba27a8c0" +dependencies = [ + "tempfile", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -363,6 +382,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "io-lifetimes" version = "1.0.9" @@ -382,7 +410,7 @@ checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" dependencies = [ "hermit-abi", "io-lifetimes", - "rustix", + "rustix 0.36.16", "windows-sys 0.45.0", ] @@ -445,6 +473,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "memchr" version = "2.5.0" @@ -562,6 +596,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -569,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] @@ -600,7 +643,21 @@ dependencies = [ "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.37.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", "windows-sys 0.45.0", ] @@ -726,6 +783,19 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix 0.37.7", + "windows-sys 0.45.0", +] + [[package]] name = "termcolor" version = "1.2.0" @@ -741,7 +811,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" dependencies = [ - "rustix", + "rustix 0.36.16", "windows-sys 0.45.0", ] diff --git a/src/main.rs b/src/main.rs index 24c2e136..d2cbd3e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,7 +66,8 @@ struct Cli { #[arg(long)] relaxed_tasklist_character: bool, - /// Enable relaxing of autolink parsing, allowing links to be recognized when in brackets + /// Enable relaxing of autolink parsing, allow links to be recognized when in brackets + /// and allow all url schemes #[arg(long)] relaxed_autolinks: bool, diff --git a/src/parser/autolink.rs b/src/parser/autolink.rs index ff78f54a..a66c321f 100644 --- a/src/parser/autolink.rs +++ b/src/parser/autolink.rs @@ -41,7 +41,7 @@ pub(crate) fn process_autolinks<'a>( match contents[i] { b':' => { - post_org = url_match(arena, contents, i); + post_org = url_match(arena, contents, i, relaxed_autolinks); if post_org.is_some() { break; } @@ -235,6 +235,7 @@ fn url_match<'a>( arena: &'a Arena>, contents: &[u8], i: usize, + relaxed_autolinks: bool, ) -> Option<(&'a AstNode<'a>, usize, usize)> { const SCHEMES: [&[u8]; 3] = [b"http", b"https", b"ftp"]; @@ -249,9 +250,11 @@ fn url_match<'a>( rewind += 1; } - let cond = |s: &&[u8]| size - i + rewind >= s.len() && &&contents[i - rewind..i] == s; - if !SCHEMES.iter().any(cond) { - return None; + if !relaxed_autolinks { + let cond = |s: &&[u8]| size - i + rewind >= s.len() && &&contents[i - rewind..i] == s; + if !SCHEMES.iter().any(cond) { + return None; + } } let mut link_end = match check_domain(&contents[i + 3..], true) { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 3aa16a48..9c9de85e 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -462,7 +462,8 @@ pub struct ParseOptions { /// Whether or not a simple `x` or `X` is used for tasklist or any other symbol is allowed. pub relaxed_tasklist_matching: bool, - /// Relax parsing of autolinks, allowing links to be detected inside brackets. + /// Relax parsing of autolinks, allow links to be detected inside brackets + /// and allow all url schemes /// /// ``` /// # use comrak::{markdown_to_html, Options}; diff --git a/src/tests/autolink.rs b/src/tests/autolink.rs index f176fbbd..a8b4f2c1 100644 --- a/src/tests/autolink.rs +++ b/src/tests/autolink.rs @@ -22,10 +22,10 @@ fn autolink_email() { fn autolink_scheme() { html_opts!( [extension.autolink], - concat!("https://google.com/search\n"), + concat!("https://google.com/search\n", "rdar://localhost.com/blah"), concat!( - "

https://google.\ - com/search

\n" + "

https://google.com/search\n", + "rdar://localhost.com/blah

\n" ), ); } @@ -102,6 +102,36 @@ fn autolink_relaxed_links_in_brackets() { } } +#[test] +fn autolink_relaxed_links_schemes() { + let examples = [ + [ + "https://foo.com", + "

https://foo.com

\n", + ], + [ + "smb:///Volumes/shared/foo.pdf", + "

smb:///Volumes/shared/foo.pdf

\n", + ], + [ + "irc://irc.freenode.net/git", + "

irc://irc.freenode.net/git

\n", + ], + [ + "rdar://localhost.com/blah", + "

rdar://localhost.com/blah

\n", + ], + ]; + + for example in examples { + html_opts!( + [extension.autolink, parse.relaxed_autolinks], + example[0], + example[1] + ); + } +} + #[test] fn sourcepos_correctly_restores_context() { // There's unsoundness in trying to maintain and adjust sourcepos