summaryrefslogtreecommitdiffstats
path: root/third_party/rust/urlencoding
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/urlencoding')
-rw-r--r--third_party/rust/urlencoding/.cargo-checksum.json1
-rw-r--r--third_party/rust/urlencoding/Cargo.toml10
-rw-r--r--third_party/rust/urlencoding/LICENSE19
-rw-r--r--third_party/rust/urlencoding/README.md50
-rw-r--r--third_party/rust/urlencoding/src/lib.rs170
5 files changed, 250 insertions, 0 deletions
diff --git a/third_party/rust/urlencoding/.cargo-checksum.json b/third_party/rust/urlencoding/.cargo-checksum.json
new file mode 100644
index 0000000000..e5c1ef9e42
--- /dev/null
+++ b/third_party/rust/urlencoding/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"81153f958c5a2f4b4aabf0b69cff507c0755f40af1c17860583e0528c48bebe2","LICENSE":"5fe71cd9f72a6009711249fff7cb5d4d075cf9288a5eb52e125d5f8ad9ed8ce7","README.md":"f96070e07fc534f4b591919399304d7464f20892ec2ba0704c8e4a714595d561","src/lib.rs":"08de888c4e799701b755cb865d6da8faf3a1268755264170ac8ac7b4480682a5"},"package":"3df3561629a8bb4c57e5a2e4c43348d9e29c7c29d9b1c4c1f47166deca8f37ed"} \ No newline at end of file
diff --git a/third_party/rust/urlencoding/Cargo.toml b/third_party/rust/urlencoding/Cargo.toml
new file mode 100644
index 0000000000..a1ca1995fc
--- /dev/null
+++ b/third_party/rust/urlencoding/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "urlencoding"
+version = "1.0.0"
+authors = ["Bertram Truong <b@bertramtruong.com>"]
+license = "MIT"
+description = "A Rust library for doing URL percentage encoding."
+repository = "https://github.com/bt/rust_urlencoding"
+keywords = ["url", "encoding", "urlencoding"]
+
+[dependencies]
diff --git a/third_party/rust/urlencoding/LICENSE b/third_party/rust/urlencoding/LICENSE
new file mode 100644
index 0000000000..fb9900014e
--- /dev/null
+++ b/third_party/rust/urlencoding/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2016 Bertram Truong
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/third_party/rust/urlencoding/README.md b/third_party/rust/urlencoding/README.md
new file mode 100644
index 0000000000..5088cf1298
--- /dev/null
+++ b/third_party/rust/urlencoding/README.md
@@ -0,0 +1,50 @@
+# urlencoding
+
+[![Latest Version](https://img.shields.io/crates/v/urlencoding.svg)](https://crates.io/crates/urlencoding)
+
+A Rust library for doing URL percentage encoding.
+
+Installation
+============
+
+This crate can be downloaded through Cargo. To do so, add the following line to your `Cargo.toml` file, under `dependencies`:
+
+```toml
+urlencoding = "1.0.0"
+```
+
+Usage
+=====
+
+To encode a string, do the following:
+
+```rust
+extern crate urlencoding;
+
+use urlencoding::encode;
+
+fn main() {
+ let encoded = encode("This string will be URL encoded.");
+ println!("{}", encoded);
+ // This%20string%20will%20be%20URL%20encoded.
+}
+```
+
+To decode a string, it's only slightly different:
+
+```rust
+extern crate urlencoding;
+
+use urlencoding::decode;
+
+fn main() {
+ let decoded = decode("%F0%9F%91%BE%20Exterminate%21");
+ println!("{}", decoded.unwrap());
+ // 👾 Exterminate!
+}
+```
+
+License
+=======
+
+This project is licensed under the MIT license, Copyright (c) 2017 Bertram Truong. For more information see the `LICENSE` file.
diff --git a/third_party/rust/urlencoding/src/lib.rs b/third_party/rust/urlencoding/src/lib.rs
new file mode 100644
index 0000000000..6808a395b1
--- /dev/null
+++ b/third_party/rust/urlencoding/src/lib.rs
@@ -0,0 +1,170 @@
+use std::str;
+use std::string::FromUtf8Error;
+
+pub fn encode(data: &str) -> String {
+ let mut escaped = String::new();
+ for b in data.as_bytes().iter() {
+ match *b as char {
+ // Accepted characters
+ 'A'...'Z' | 'a'...'z' | '0'...'9' | '-' | '_' | '.' | '~' => escaped.push(*b as char),
+
+ // Everything else is percent-encoded
+ b => escaped.push_str(format!("%{:02X}", b as u32).as_str()),
+ };
+ }
+ return escaped;
+}
+
+pub fn decode(data: &str) -> Result<String, FromUrlEncodingError> {
+ validate_urlencoded_str(data)?;
+ let mut unescaped_bytes: Vec<u8> = Vec::new();
+ let mut bytes = data.bytes();
+ // If validate_urlencoded_str returned Ok, then we know
+ // every '%' is followed by 2 hex characters
+ while let Some(b) = bytes.next() {
+ match b as char {
+ '%' => {
+ let bytes_to_decode = &[bytes.next().unwrap(), bytes.next().unwrap()];
+ let hex_str = str::from_utf8(bytes_to_decode).unwrap();
+ unescaped_bytes.push(u8::from_str_radix(hex_str, 16).unwrap());
+ },
+ _ => {
+ // Assume whoever did the encoding intended what we got
+ unescaped_bytes.push(b);
+ }
+ }
+ }
+ String::from_utf8(unescaped_bytes).or_else(|e| Err(FromUrlEncodingError::Utf8CharacterError {
+ error: e,
+ }))
+}
+
+// Validates every '%' character is followed by exactly 2 hex
+// digits.
+fn validate_urlencoded_str(data: &str) -> Result<(), FromUrlEncodingError> {
+ let mut iter = data.char_indices();
+ while let Some((idx, chr)) = iter.next() {
+ match chr {
+ '%' => {
+ validate_percent_encoding(&mut iter, idx)?;
+ },
+ _ => continue,
+ }
+ }
+ Ok(())
+}
+
+// Validates the next two characters returned by the provided iterator are
+// hexadecimal digits.
+fn validate_percent_encoding(iter: &mut str::CharIndices, current_idx: usize) -> Result<(), FromUrlEncodingError> {
+ for _ in 0..2 {
+ match iter.next() {
+ // Only hex digits are valid
+ Some((_, c)) if c.is_digit(16) => {
+ continue
+ },
+ Some((i, c)) => return Err(FromUrlEncodingError::UriCharacterError {
+ character: c,
+ index: i,
+ }),
+ // We got a '%' without 2 characters after it, so mark the '%' as bad
+ None => return Err(FromUrlEncodingError::UriCharacterError {
+ character: '%',
+ index: current_idx,
+ }),
+ }
+ }
+ Ok(())
+}
+
+#[derive(Debug)]
+pub enum FromUrlEncodingError {
+ UriCharacterError { character: char, index: usize },
+ Utf8CharacterError { error: FromUtf8Error },
+}
+
+#[cfg(test)]
+mod tests {
+ use super::encode;
+ use super::decode;
+ use super::FromUrlEncodingError;
+
+ #[test]
+ fn it_encodes_successfully() {
+ let expected = "this%20that";
+ assert_eq!(expected, encode("this that"));
+ }
+
+ #[test]
+ fn it_encodes_successfully_emoji() {
+ let emoji_string = "👾 Exterminate!";
+ let expected = "%F0%9F%91%BE%20Exterminate%21";
+ assert_eq!(expected, encode(emoji_string));
+ }
+
+ #[test]
+ fn it_decodes_successfully() {
+ let expected = String::from("this that");
+ let encoded = "this%20that";
+ assert_eq!(expected, decode(encoded).unwrap());
+ }
+
+ #[test]
+ fn it_decodes_successfully_emoji() {
+ let expected = String::from("👾 Exterminate!");
+ let encoded = "%F0%9F%91%BE%20Exterminate%21";
+ assert_eq!(expected, decode(encoded).unwrap());
+ }
+
+ #[test]
+ fn it_decodes_unsuccessfully_emoji() {
+ let bad_encoded_string = "👾 Exterminate!";
+
+ assert_eq!(bad_encoded_string, decode(bad_encoded_string).unwrap());
+ }
+
+ #[test]
+ fn it_decodes_unsuccessfuly_bad_percent_01() {
+ let bad_encoded_string = "this%2that";
+ let expected_idx = 6;
+ let expected_char = 't';
+
+ match decode(bad_encoded_string).unwrap_err() {
+ FromUrlEncodingError::UriCharacterError { index: i, character: c } => {
+ assert_eq!(expected_idx, i);
+ assert_eq!(expected_char, c)
+ },
+ _ => panic!()
+ }
+ }
+
+ #[test]
+ fn it_decodes_unsuccessfuly_bad_percent_02() {
+ let bad_encoded_string = "this%20that%";
+ let expected_idx = 11;
+ let expected_char = '%';
+
+ match decode(bad_encoded_string).unwrap_err() {
+ FromUrlEncodingError::UriCharacterError { index: i, character: c } => {
+ assert_eq!(expected_idx, i);
+ assert_eq!(expected_char, c)
+ },
+ _ => panic!()
+ }
+ }
+
+ #[test]
+ fn it_decodes_unsuccessfuly_bad_percent_03() {
+ let bad_encoded_string = "this%20that%2";
+ let expected_idx = 11;
+ let expected_char = '%';
+
+ match decode(bad_encoded_string).unwrap_err() {
+ FromUrlEncodingError::UriCharacterError { index: i, character: c } => {
+ assert_eq!(expected_idx, i);
+ assert_eq!(expected_char, c)
+ },
+ _ => panic!()
+ }
+ }
+}