Rocket

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 5762208bbacf873d2512e64603e66492bd3adb63
parent 4dbd87a36fcd735a007c81ec2bd15a1551a58529
Author: Sergio Benitez <sb@sergio.bz>
Date:   Fri,  2 Nov 2018 00:10:01 -0700

Percent-encode characters: '[', ']', '\', '^', '|'.

Fixes #808.

Diffstat:
Mcore/http/src/lib.rs | 4++--
Mcore/http/src/uri/uri.rs | 21++++++++++++++++++---
Mcore/http/src/uri/uri_display.rs | 17+++++------------
Acore/lib/tests/uri-percent-encoding-issue-808.rs | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 84 insertions(+), 17 deletions(-)

diff --git a/core/http/src/lib.rs b/core/http/src/lib.rs @@ -15,8 +15,8 @@ #[macro_use] extern crate pear; extern crate smallvec; -#[macro_use] -extern crate percent_encoding; +#[doc(hidden)] #[macro_use] +pub extern crate percent_encoding; extern crate cookie; extern crate time; extern crate indexmap; diff --git a/core/http/src/uri/uri.rs b/core/http/src/uri/uri.rs @@ -59,6 +59,22 @@ pub enum Uri<'a> { Asterisk, } +/// This encode set is used for strings where '/' characters are known to be +/// safe; all other special path segment characters are encoded. +define_encode_set! { + #[doc(hidden)] + pub UNSAFE_PATH_ENCODE_SET = [::percent_encoding::DEFAULT_ENCODE_SET] | { + '%', '[', '\\', ']', '^', '|' + } +} + +/// This encode set should be used for path segments (components) of a +/// `/`-separated path. It encodes as much as possible. +define_encode_set! { + #[doc(hidden)] + pub DEFAULT_ENCODE_SET = [UNSAFE_PATH_ENCODE_SET] | { '/' } +} + impl<'a> Uri<'a> { #[inline] crate unsafe fn raw_absolute( @@ -161,7 +177,7 @@ impl<'a> Uri<'a> { /// Returns a URL-encoded version of the string. Any characters outside of /// visible ASCII-range are encoded as well as ' ', '"', '#', '<', '>', '`', - /// '?', '{', '}', '%', and '/'. + /// '?', '{', '}', '%', '/', '[', '\\', ']', '^', and '|'. /// /// # Examples /// @@ -173,8 +189,7 @@ impl<'a> Uri<'a> { /// assert_eq!(encoded, "hello%3Fa=%3Cb%3Ehi%3C%2Fb%3E"); /// ``` pub fn percent_encode(string: &str) -> Cow<str> { - let set = ::percent_encoding::PATH_SEGMENT_ENCODE_SET; - ::percent_encoding::utf8_percent_encode(string, set).into() + ::percent_encoding::utf8_percent_encode(string, DEFAULT_ENCODE_SET).into() } /// Returns a URL-decoded version of the string. If the percent encoded diff --git a/core/http/src/uri/uri_display.rs b/core/http/src/uri/uri_display.rs @@ -2,17 +2,10 @@ use std::fmt; use std::path::{Path, PathBuf}; use std::borrow::Cow; -use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; +use percent_encoding::utf8_percent_encode; -use {RawStr, uri::{Uri, Formatter}, ext::Normalize}; - -mod priv_encode_set { - /// This encode set is used for strings where '/' characters are known to be - /// safe; all other special path segment characters are encoded. - define_encode_set! { pub PATH_ENCODE_SET = [super::DEFAULT_ENCODE_SET] | {'%'} } -} - -use self::priv_encode_set::PATH_ENCODE_SET; +use uri::{Uri, Formatter, UNSAFE_PATH_ENCODE_SET}; +use {RawStr, ext::Normalize}; /// Trait implemented by types that can be displayed as part of a URI in `uri!`. /// @@ -241,7 +234,7 @@ impl UriDisplay for PathBuf { #[inline] fn fmt(&self, f: &mut Formatter) -> fmt::Result { let string = self.normalized_str(); - let enc: Cow<str> = utf8_percent_encode(&string, PATH_ENCODE_SET).into(); + let enc: Cow<str> = utf8_percent_encode(&string, UNSAFE_PATH_ENCODE_SET).into(); f.write_raw(&enc) } } @@ -251,7 +244,7 @@ impl UriDisplay for Path { #[inline] fn fmt(&self, f: &mut Formatter) -> fmt::Result { let string = self.normalized_str(); - let enc: Cow<str> = utf8_percent_encode(&string, PATH_ENCODE_SET).into(); + let enc: Cow<str> = utf8_percent_encode(&string, UNSAFE_PATH_ENCODE_SET).into(); f.write_raw(&enc) } } diff --git a/core/lib/tests/uri-percent-encoding-issue-808.rs b/core/lib/tests/uri-percent-encoding-issue-808.rs @@ -0,0 +1,59 @@ +#![feature(proc_macro_hygiene, decl_macro)] + +#[macro_use] extern crate rocket; + +use rocket::response::Redirect; +use rocket::http::uri::Uri; + +const NAME: &str = "John[]|\\%@^"; + +#[get("/hello/<name>")] +fn hello(name: String) -> String { + format!("Hello, {}!", name) +} + +#[get("/raw")] +fn raw_redirect() -> Redirect { + Redirect::to(format!("/hello/{}", Uri::percent_encode(NAME))) +} + +#[get("/uri")] +fn uri_redirect() -> Redirect { + Redirect::to(uri!(hello: NAME)) +} + +fn rocket() -> rocket::Rocket { + rocket::ignite().mount("/", routes![hello, uri_redirect, raw_redirect]) +} + + +mod tests { + use super::*; + use rocket::local::Client; + use rocket::http::{Status, uri::Uri}; + + #[test] + fn uri_percent_encoding_redirect() { + let expected_location = vec!["/hello/John%5B%5D%7C%5C%25@%5E"]; + let client = Client::new(rocket()).unwrap(); + + let response = client.get("/raw").dispatch(); + let location: Vec<_> = response.headers().get("location").collect(); + assert_eq!(response.status(), Status::SeeOther); + assert_eq!(&location, &expected_location); + + let response = client.get("/uri").dispatch(); + let location: Vec<_> = response.headers().get("location").collect(); + assert_eq!(response.status(), Status::SeeOther); + assert_eq!(&location, &expected_location); + } + + #[test] + fn uri_percent_encoding_get() { + let client = Client::new(rocket()).unwrap(); + let name = Uri::percent_encode(NAME); + let mut response = client.get(format!("/hello/{}", name)).dispatch(); + assert_eq!(response.status(), Status::Ok); + assert_eq!(response.body_string().unwrap(), format!("Hello, {}!", NAME)); + } +}