1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-11-25 11:01:14 +00:00

Quoter::requote returns Vec<u8> (#2613)

This commit is contained in:
Ali MJ Al-Nasrawy 2022-02-01 00:26:34 +03:00 committed by GitHub
parent cd511affd5
commit fd412a8223
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 16 deletions

View file

@ -1,6 +1,9 @@
# Changes # Changes
## Unreleased - 2021-xx-xx ## Unreleased - 2021-xx-xx
- `Quoter::requote` now returns `Option<Vec<u8>>`. [#2613]
[#2613]: https://github.com/actix/actix-web/pull/2613
## 0.5.0-rc.2 - 2022-01-21 ## 0.5.0-rc.2 - 2022-01-21

View file

@ -52,7 +52,7 @@ macro_rules! parse_value {
V: Visitor<'de>, V: Visitor<'de>,
{ {
let decoded = FULL_QUOTER let decoded = FULL_QUOTER
.with(|q| q.requote(self.value.as_bytes())) .with(|q| q.requote_str_lossy(self.value))
.map(Cow::Owned) .map(Cow::Owned)
.unwrap_or(Cow::Borrowed(self.value)); .unwrap_or(Cow::Borrowed(self.value));
@ -332,7 +332,7 @@ impl<'de> Deserializer<'de> for Value<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match FULL_QUOTER.with(|q| q.requote(self.value.as_bytes())) { match FULL_QUOTER.with(|q| q.requote_str_lossy(self.value)) {
Some(s) => visitor.visit_string(s), Some(s) => visitor.visit_string(s),
None => visitor.visit_borrowed_str(self.value), None => visitor.visit_borrowed_str(self.value),
} }
@ -342,7 +342,7 @@ impl<'de> Deserializer<'de> for Value<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match FULL_QUOTER.with(|q| q.requote(self.value.as_bytes())) { match FULL_QUOTER.with(|q| q.requote_str_lossy(self.value)) {
Some(s) => visitor.visit_byte_buf(s.into()), Some(s) => visitor.visit_byte_buf(s.into()),
None => visitor.visit_borrowed_bytes(self.value.as_bytes()), None => visitor.visit_borrowed_bytes(self.value.as_bytes()),
} }

View file

@ -66,8 +66,13 @@ impl Quoter {
/// Re-quotes... ? /// Re-quotes... ?
/// ///
/// Returns `None` when no modification to the original string was required. /// Returns `None` when no modification to the original byte string was required.
pub fn requote(&self, val: &[u8]) -> Option<String> { ///
/// Non-ASCII bytes are accepted as valid input.
///
/// Behavior for invalid/incomplete percent-encoding sequences is unspecified and may include removing
/// the invalid sequence from the output or passing it as it is.
pub fn requote(&self, val: &[u8]) -> Option<Vec<u8>> {
let mut has_pct = 0; let mut has_pct = 0;
let mut pct = [b'%', 0, 0]; let mut pct = [b'%', 0, 0];
let mut idx = 0; let mut idx = 0;
@ -121,7 +126,12 @@ impl Quoter {
idx += 1; idx += 1;
} }
cloned.map(|data| String::from_utf8_lossy(&data).into_owned()) cloned
}
pub(crate) fn requote_str_lossy(&self, val: &str) -> Option<String> {
self.requote(val.as_bytes())
.map(|data| String::from_utf8_lossy(&data).into_owned())
} }
} }
@ -201,14 +211,29 @@ mod tests {
#[test] #[test]
fn custom_quoter() { fn custom_quoter() {
let q = Quoter::new(b"", b"+"); let q = Quoter::new(b"", b"+");
assert_eq!(q.requote(b"/a%25c").unwrap(), "/a%c"); assert_eq!(q.requote(b"/a%25c").unwrap(), b"/a%c");
assert_eq!(q.requote(b"/a%2Bc").unwrap(), "/a%2Bc"); assert_eq!(q.requote(b"/a%2Bc").unwrap(), b"/a%2Bc");
let q = Quoter::new(b"%+", b"/"); let q = Quoter::new(b"%+", b"/");
assert_eq!(q.requote(b"/a%25b%2Bc").unwrap(), "/a%b+c"); assert_eq!(q.requote(b"/a%25b%2Bc").unwrap(), b"/a%b+c");
assert_eq!(q.requote(b"/a%2fb").unwrap(), "/a%2fb"); assert_eq!(q.requote(b"/a%2fb").unwrap(), b"/a%2fb");
assert_eq!(q.requote(b"/a%2Fb").unwrap(), "/a%2Fb"); assert_eq!(q.requote(b"/a%2Fb").unwrap(), b"/a%2Fb");
assert_eq!(q.requote(b"/a%0Ab").unwrap(), "/a\nb"); assert_eq!(q.requote(b"/a%0Ab").unwrap(), b"/a\nb");
assert_eq!(q.requote(b"/a%FE\xffb").unwrap(), b"/a\xfe\xffb");
assert_eq!(q.requote(b"/a\xfe\xffb"), None);
}
#[test]
fn non_ascii() {
let q = Quoter::new(b"%+", b"/");
assert_eq!(q.requote(b"/a%FE\xffb").unwrap(), b"/a\xfe\xffb");
assert_eq!(q.requote(b"/a\xfe\xffb"), None);
}
#[test]
fn invalid_sequences() {
let q = Quoter::new(b"%+", b"/");
assert_eq!(q.requote(b"/a%2x%2X%%").unwrap(), b"/a%2x%2X");
} }
#[test] #[test]

View file

@ -15,14 +15,14 @@ pub struct Url {
impl Url { impl Url {
#[inline] #[inline]
pub fn new(uri: http::Uri) -> Url { pub fn new(uri: http::Uri) -> Url {
let path = DEFAULT_QUOTER.with(|q| q.requote(uri.path().as_bytes())); let path = DEFAULT_QUOTER.with(|q| q.requote_str_lossy(uri.path()));
Url { uri, path } Url { uri, path }
} }
#[inline] #[inline]
pub fn new_with_quoter(uri: http::Uri, quoter: &Quoter) -> Url { pub fn new_with_quoter(uri: http::Uri, quoter: &Quoter) -> Url {
Url { Url {
path: quoter.requote(uri.path().as_bytes()), path: quoter.requote_str_lossy(uri.path()),
uri, uri,
} }
} }
@ -45,13 +45,13 @@ impl Url {
#[inline] #[inline]
pub fn update(&mut self, uri: &http::Uri) { pub fn update(&mut self, uri: &http::Uri) {
self.uri = uri.clone(); self.uri = uri.clone();
self.path = DEFAULT_QUOTER.with(|q| q.requote(uri.path().as_bytes())); self.path = DEFAULT_QUOTER.with(|q| q.requote_str_lossy(uri.path()));
} }
#[inline] #[inline]
pub fn update_with_quoter(&mut self, uri: &http::Uri, quoter: &Quoter) { pub fn update_with_quoter(&mut self, uri: &http::Uri, quoter: &Quoter) {
self.uri = uri.clone(); self.uri = uri.clone();
self.path = quoter.requote(uri.path().as_bytes()); self.path = quoter.requote_str_lossy(uri.path());
} }
} }