use percent_encoding::AsciiSet;
use percent_encoding::NON_ALPHANUMERIC;
use percent_encoding::percent_decode_str;
use percent_encoding::utf8_percent_encode;
use crate::*;
pub fn new_http_uri_invalid_error(err: http::uri::InvalidUri) -> Error {
Error::new(ErrorKind::Unexpected, "parse http uri").set_source(err)
}
static PATH_ENCODE_SET: AsciiSet = NON_ALPHANUMERIC
.remove(b'/')
.remove(b'-')
.remove(b'_')
.remove(b'.')
.remove(b'!')
.remove(b'~')
.remove(b'*')
.remove(b'\'')
.remove(b'(')
.remove(b')');
pub fn percent_encode_path(path: &str) -> String {
utf8_percent_encode(path, &PATH_ENCODE_SET).to_string()
}
pub fn percent_decode_path(path: &str) -> String {
match percent_decode_str(path).decode_utf8() {
Ok(v) => v.to_string(),
Err(_) => path.to_string(),
}
}
pub struct QueryPairsWriter {
base: String,
has_query: bool,
}
impl QueryPairsWriter {
pub fn new(s: &str) -> Self {
let mut base = String::with_capacity(256);
base.push_str(s);
Self {
base,
has_query: false,
}
}
pub fn push(mut self, key: &str, value: &str) -> Self {
if self.has_query {
self.base.push('&');
} else {
self.base.push('?');
self.has_query = true;
}
self.base.push_str(key);
if !value.is_empty() {
self.base.push('=');
self.base.push_str(value);
}
self
}
pub fn finish(self) -> String {
self.base
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_percent_encode_path() {
let cases = vec![
(
"Reserved Characters",
";,/?:@&=+$",
"%3B%2C/%3F%3A%40%26%3D%2B%24",
),
("Unescaped Characters", "-_.!~*'()", "-_.!~*'()"),
("Number Sign", "#", "%23"),
(
"Alphanumeric Characters + Space",
"ABC abc 123",
"ABC%20abc%20123",
),
(
"Unicode",
"你好,世界!❤",
"%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C%EF%BC%81%E2%9D%A4",
),
];
for (name, input, expected) in cases {
let actual = percent_encode_path(input);
assert_eq!(actual, expected, "{name}");
}
}
#[test]
fn test_percent_decode_path() {
let cases = vec![
(
"Reserved Characters",
"%3B%2C/%3F%3A%40%26%3D%2B%24",
";,/?:@&=+$",
),
("Unescaped Characters", "-_.!~*'()", "-_.!~*'()"),
("Number Sign", "%23", "#"),
(
"Alphanumeric Characters + Space",
"ABC%20abc%20123",
"ABC abc 123",
),
(
"Unicode Characters",
"%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C%EF%BC%81%E2%9D%A4",
"你好,世界!❤",
),
(
"Double Encoded Characters",
"Double%2520Encoded",
"Double%20Encoded",
),
(
"Not Percent Encoded Characters",
"/not percent encoded/path;,/?:@&=+$-",
"/not percent encoded/path;,/?:@&=+$-",
),
];
for (name, input, expected) in cases {
let actual = percent_decode_path(input);
assert_eq!(actual, expected, "{name}");
}
}
}