mirror of
https://github.com/YGGverse/aquatic.git
synced 2026-03-31 17:55:36 +00:00
aquatic_http: add memchr version of urldecode, which might be faster
This commit is contained in:
parent
f94c52da77
commit
056cd41732
3 changed files with 61 additions and 2 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -83,6 +83,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"itoa",
|
||||
"log",
|
||||
"memchr",
|
||||
"mimalloc",
|
||||
"mio",
|
||||
"native-tls",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ indexmap = "1"
|
|||
itoa = "0.4"
|
||||
log = "0.4"
|
||||
mimalloc = { version = "0.1", default-features = false }
|
||||
memchr = "2"
|
||||
mio = { version = "0.7", features = ["tcp", "os-poll", "os-util"] }
|
||||
native-tls = "0.2"
|
||||
parking_lot = "0.10"
|
||||
|
|
|
|||
|
|
@ -60,8 +60,7 @@ impl Request {
|
|||
.with_context(|| format!("no key in {}", part))?;
|
||||
let value = key_and_value.next()
|
||||
.with_context(|| format!("no value in {}", part))?;
|
||||
let value = Self::urldecode(value)?
|
||||
.to_string();
|
||||
let value = Self::urldecode_memchr(value)?;
|
||||
|
||||
if key == "info_hash" {
|
||||
info_hashes.push(value);
|
||||
|
|
@ -170,4 +169,62 @@ impl Request {
|
|||
|
||||
Ok(processed)
|
||||
}
|
||||
|
||||
fn urldecode_memchr(value: &str) -> anyhow::Result<String> {
|
||||
let mut processed = String::with_capacity(value.len());
|
||||
|
||||
let bytes = value.as_bytes();
|
||||
let iter = ::memchr::memchr_iter(b'%', bytes);
|
||||
|
||||
let mut str_index_after_hex = 0usize;
|
||||
|
||||
for i in iter {
|
||||
match (bytes.get(i), bytes.get(i + 1), bytes.get(i + 2)){
|
||||
(Some(0..=127), Some(0..=127), Some(0..=127)) => {
|
||||
if i > 0 {
|
||||
processed.push_str(&value[str_index_after_hex..i]);
|
||||
}
|
||||
|
||||
str_index_after_hex = i + 3;
|
||||
|
||||
let hex = &value[i + 1..i + 3];
|
||||
let byte = u8::from_str_radix(&hex, 16)?;
|
||||
|
||||
processed.push(byte as char);
|
||||
},
|
||||
_ => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"invalid urlencoded segment at byte {} in {}", i, value
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(rest_of_str) = value.get(str_index_after_hex..){
|
||||
processed.push_str(rest_of_str);
|
||||
}
|
||||
|
||||
processed.shrink_to_fit();
|
||||
|
||||
Ok(processed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_urldecode(){
|
||||
let f = Request::urldecode_memchr;
|
||||
|
||||
assert_eq!(f("").unwrap(), "".to_string());
|
||||
assert_eq!(f("abc").unwrap(), "abc".to_string());
|
||||
assert_eq!(f("%21").unwrap(), "!".to_string());
|
||||
assert_eq!(f("%21%3D").unwrap(), "!=".to_string());
|
||||
assert_eq!(f("abc%21def%3Dghi").unwrap(), "abc!def=ghi".to_string());
|
||||
assert!(f("%").is_err());
|
||||
assert!(f("%å7").is_err());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue