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",
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
"log",
|
"log",
|
||||||
|
"memchr",
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"mio",
|
"mio",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ indexmap = "1"
|
||||||
itoa = "0.4"
|
itoa = "0.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
mimalloc = { version = "0.1", default-features = false }
|
mimalloc = { version = "0.1", default-features = false }
|
||||||
|
memchr = "2"
|
||||||
mio = { version = "0.7", features = ["tcp", "os-poll", "os-util"] }
|
mio = { version = "0.7", features = ["tcp", "os-poll", "os-util"] }
|
||||||
native-tls = "0.2"
|
native-tls = "0.2"
|
||||||
parking_lot = "0.10"
|
parking_lot = "0.10"
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,7 @@ impl Request {
|
||||||
.with_context(|| format!("no key in {}", part))?;
|
.with_context(|| format!("no key in {}", part))?;
|
||||||
let value = key_and_value.next()
|
let value = key_and_value.next()
|
||||||
.with_context(|| format!("no value in {}", part))?;
|
.with_context(|| format!("no value in {}", part))?;
|
||||||
let value = Self::urldecode(value)?
|
let value = Self::urldecode_memchr(value)?;
|
||||||
.to_string();
|
|
||||||
|
|
||||||
if key == "info_hash" {
|
if key == "info_hash" {
|
||||||
info_hashes.push(value);
|
info_hashes.push(value);
|
||||||
|
|
@ -170,4 +169,62 @@ impl Request {
|
||||||
|
|
||||||
Ok(processed)
|
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