diff options
author | Alex Grinman <alex@krypt.co> | 2019-02-15 13:07:25 -0500 |
---|---|---|
committer | Alex Grinman <alex@krypt.co> | 2019-02-15 13:11:11 -0500 |
commit | 00862926b8cb7db48f60654d984dd11001ad3c95 (patch) | |
tree | 6eab35891b67644b16e344bab5e5dc23faf61394 /src | |
parent | 65c7f89ad4a4281aea4ea0115c27dbd54d339b15 (diff) |
fix: replace pluses before percent decoding
Diffstat (limited to 'src')
-rw-r--r-- | src/de/parse.rs | 41 |
1 files changed, 26 insertions, 15 deletions
diff --git a/src/de/parse.rs b/src/de/parse.rs index 5d84512..3718c57 100644 --- a/src/de/parse.rs +++ b/src/de/parse.rs @@ -193,22 +193,20 @@ impl<'a> Parser<'a> { /// Replace b'+' with b' ' /// Copied from [`form_urlencoded`](https://github.com/servo/rust-url/blob/380be29859adb859e861c2d765897c22ec878e01/src/form_urlencoded.rs#L125). -fn replace_plus(input: Cow<str>) -> Cow<str> { - match input.as_bytes().iter().position(|&b| b == b'+') { - None => input, +fn replace_plus(input: &[u8]) -> Cow<[u8]> { + match input.iter().position(|&b| b == b'+') { + None => Cow::Borrowed(input), Some(first_position) => { - let mut replaced = input.as_bytes().to_owned(); + let mut replaced = input.to_owned(); replaced[first_position] = b' '; for byte in &mut replaced[first_position + 1..] { if *byte == b'+' { *byte = b' '; } } - Cow::Owned( - String::from_utf8(replaced) - .expect("replacing '+' with ' ' cannot panic"), - ) - }, + + Cow::Owned(replaced) + } } } @@ -236,13 +234,26 @@ impl<'a> Parser<'a> { /// Avoids allocations when neither percent encoded, nor `'+'` values are /// present. fn collect_str(&mut self) -> Result<Cow<'a, str>> { - let res: Cow<'a, str> = percent_encoding::percent_decode( - &self.inner[self.acc.0..self.acc.1 - 1], - ) - .decode_utf8()?; - let res: Result<Cow<'a, str>> = Ok(replace_plus(res)); + let replaced = replace_plus(&self.inner[self.acc.0..self.acc.1 - 1]); + let ret:Result<Cow<'a, str>> = match percent_encoding::percent_decode(&replaced).decode_utf8()? { + Cow::Borrowed(_) => { + match replaced { + Cow::Borrowed(_) => { + let res = str::from_utf8(&self.inner[self.acc.0..self.acc.1 - 1])?; + Ok(Cow::Borrowed(res)) + }, + Cow::Owned(owned) => { + let res = String::from_utf8(owned)?; + Ok(Cow::Owned(res)) + } + } + }, + Cow::Owned(owned) => { + Ok(Cow::Owned(owned)) + } + }; self.clear_acc(); - res.map_err(Error::from) + ret.map_err(Error::from) } /// In some ways the main way to use a `Parser`, this runs the parsing step |