aboutsummaryrefslogtreecommitdiffstats
path: root/src/util/sanitize_uri.rs
diff options
context:
space:
mode:
authorLibravatar Titus Wormer <tituswormer@gmail.com>2022-07-20 17:19:17 +0200
committerLibravatar Titus Wormer <tituswormer@gmail.com>2022-07-20 17:19:17 +0200
commita820d849c3e20a1d72137072d70a7c8e00306f98 (patch)
treec2916ab31d6d481e0b53a06aa9b95dfcddd4163f /src/util/sanitize_uri.rs
parent7894ec75a7070591c3499fce1f409563c4edc7d7 (diff)
downloadmarkdown-rs-a820d849c3e20a1d72137072d70a7c8e00306f98.tar.gz
markdown-rs-a820d849c3e20a1d72137072d70a7c8e00306f98.tar.bz2
markdown-rs-a820d849c3e20a1d72137072d70a7c8e00306f98.zip
Refactor to improve allocation around strings
Diffstat (limited to 'src/util/sanitize_uri.rs')
-rw-r--r--src/util/sanitize_uri.rs49
1 files changed, 21 insertions, 28 deletions
diff --git a/src/util/sanitize_uri.rs b/src/util/sanitize_uri.rs
index 55b15e4..81450ae 100644
--- a/src/util/sanitize_uri.rs
+++ b/src/util/sanitize_uri.rs
@@ -32,32 +32,25 @@ use crate::util::encode::encode;
///
/// * [`micromark-util-sanitize-uri` in `micromark`](https://github.com/micromark/micromark/tree/main/packages/micromark-util-sanitize-uri)
pub fn sanitize_uri(value: &str, protocols: &Option<Vec<&str>>) -> String {
- let value = encode(&normalize_uri(value));
+ let value = encode(normalize_uri(value));
if let Some(protocols) = protocols {
- let chars: Vec<char> = value.chars().collect();
- let mut index = 0;
- let mut colon: Option<usize> = None;
-
- while index < chars.len() {
- let char = chars[index];
-
- match char {
- ':' => {
- colon = Some(index);
- break;
+ let end = value.find(|c| matches!(c, '?' | '#' | '/'));
+ let mut colon = value.find(|c| matches!(c, ':'));
+
+ // If the first colon is after `?`, `#`, or `/`, it’s not a protocol.
+ if let Some(end) = end {
+ if let Some(index) = colon {
+ if index > end {
+ colon = None;
}
- '?' | '#' | '/' => break,
- _ => {}
}
-
- index += 1;
}
- // If there is no protocol, or the first colon is after `?`, `#`, or `/`, it’s relative.
- // It is a protocol, it should be allowed.
+ // If there is no protocol, it’s relative, and fine.
if let Some(colon) = colon {
- let protocol = chars[0..colon].iter().collect::<String>().to_lowercase();
+ // If it is a protocol, it should be allowed.
+ let protocol = value[0..colon].to_lowercase();
if !protocols.contains(&protocol.as_str()) {
return "".to_string();
}
@@ -85,8 +78,9 @@ pub fn sanitize_uri(value: &str, protocols: &Option<Vec<&str>>) -> String {
///
/// * [`micromark-util-sanitize-uri` in `micromark`](https://github.com/micromark/micromark/tree/main/packages/micromark-util-sanitize-uri)
fn normalize_uri(value: &str) -> String {
- let chars: Vec<char> = value.chars().collect();
- let mut result: Vec<String> = vec![];
+ let chars = value.chars().collect::<Vec<_>>();
+ // Note: it’ll grow bigger for each non-ascii or non-safe character.
+ let mut result = String::with_capacity(value.len());
let mut index = 0;
let mut start = 0;
let mut buff = [0; 4];
@@ -104,16 +98,15 @@ fn normalize_uri(value: &str) -> String {
continue;
}
- // Note: Rust already takes care of lone astral surrogates.
+ // Note: Rust already takes care of lone surrogates.
// Non-ascii or not allowed ascii.
if char >= '\u{0080}'
|| !matches!(char, '!' | '#' | '$' | '&'..=';' | '=' | '?'..='Z' | '_' | 'a'..='z' | '~')
{
- result.push(chars[start..index].iter().collect::<String>());
-
+ result.push_str(&chars[start..index].iter().collect::<String>());
char.encode_utf8(&mut buff);
- result.push(
- buff[0..char.len_utf8()]
+ result.push_str(
+ &buff[0..char.len_utf8()]
.iter()
.map(|&byte| format!("%{:>02X}", byte))
.collect::<String>(),
@@ -125,7 +118,7 @@ fn normalize_uri(value: &str) -> String {
index += 1;
}
- result.push(chars[start..].iter().collect::<String>());
+ result.push_str(&chars[start..].iter().collect::<String>());
- result.join("")
+ result
}