mirror of https://github.com/rwf2/Rocket.git
Use the `RawStr` type for raw parameter strings.
This is a breaking change. The `&str` type no longer implements `FromParam`. The `&RawStr` type should be used in its place.
This commit is contained in:
parent
cff9901940
commit
f5ec470a7d
|
@ -13,7 +13,7 @@ struct User<'a> {
|
|||
}
|
||||
|
||||
#[post("/<name>?<query>", format = "application/json", data = "<user>", rank = 2)]
|
||||
fn get<'r>(name: &str,
|
||||
fn get<'r>(name: &RawStr,
|
||||
query: User<'r>,
|
||||
user: Form<'r, User<'r>>,
|
||||
cookies: Cookies)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
extern crate rocket;
|
||||
|
||||
#[get("/test/<one>/<two>/<three>")]
|
||||
fn get(one: &str, two: usize, three: isize) -> &'static str { "hi" }
|
||||
fn get(one: String, two: usize, three: isize) -> &'static str { "hi" }
|
||||
|
||||
fn main() {
|
||||
let _ = routes![get];
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
extern crate rocket;
|
||||
|
||||
#[get("/<todo>")]
|
||||
fn todo(todo: &str) -> &str {
|
||||
fn todo(todo: String) -> String {
|
||||
todo
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ impl<'a> FromParam<'a> for UUID {
|
|||
/// A value is successfully parsed if `param` is a properly formatted UUID.
|
||||
/// Otherwise, a `UuidParseError` is returned.
|
||||
#[inline(always)]
|
||||
fn from_param(param: &'a str) -> Result<UUID, Self::Error> {
|
||||
fn from_param(param: &'a RawStr) -> Result<UUID, Self::Error> {
|
||||
param.parse()
|
||||
}
|
||||
}
|
||||
|
@ -141,14 +141,14 @@ mod test {
|
|||
#[test]
|
||||
fn test_from_param() {
|
||||
let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2";
|
||||
let uuid_wrapper = UUID::from_param(uuid_str).unwrap();
|
||||
let uuid_wrapper = UUID::from_param(uuid_str.into()).unwrap();
|
||||
assert_eq!(uuid_str, uuid_wrapper.to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_inner() {
|
||||
let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2";
|
||||
let uuid_wrapper = UUID::from_param(uuid_str).unwrap();
|
||||
let uuid_wrapper = UUID::from_param(uuid_str.into()).unwrap();
|
||||
let real_uuid: uuid_ext::Uuid = uuid_str.parse().unwrap();
|
||||
let inner_uuid: uuid_ext::Uuid = uuid_wrapper.into_inner();
|
||||
assert_eq!(real_uuid, inner_uuid)
|
||||
|
@ -157,7 +157,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_partial_eq() {
|
||||
let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2";
|
||||
let uuid_wrapper = UUID::from_param(uuid_str).unwrap();
|
||||
let uuid_wrapper = UUID::from_param(uuid_str.into()).unwrap();
|
||||
let real_uuid: uuid_ext::Uuid = uuid_str.parse().unwrap();
|
||||
assert_eq!(uuid_wrapper, real_uuid)
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_from_param_invalid() {
|
||||
let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2p";
|
||||
let uuid_result = UUID::from_param(uuid_str);
|
||||
let uuid_result = UUID::from_param(uuid_str.into());
|
||||
assert_eq!(uuid_result, Err(UuidParseError::InvalidLength(37)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ extern crate rocket;
|
|||
use rocket::response::content;
|
||||
|
||||
#[get("/hello/<name>/<age>")]
|
||||
fn hello(name: &str, age: i8) -> String {
|
||||
fn hello(name: String, age: i8) -> String {
|
||||
format!("Hello, {} year old named {}!", age, name)
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ fn login<'a>(user_form: Form<'a, UserLogin<'a>>) -> Result<Redirect, String> {
|
|||
}
|
||||
|
||||
#[get("/user/<username>")]
|
||||
fn user_page(username: &str) -> String {
|
||||
fn user_page(username: &RawStr) -> String {
|
||||
format!("This is {}'s page.", username)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ extern crate rocket;
|
|||
#[cfg(test)] mod tests;
|
||||
|
||||
#[get("/hello/<name>/<age>")]
|
||||
fn hello(name: &str, age: u8) -> String {
|
||||
fn hello(name: String, age: u8) -> String {
|
||||
format!("Hello, {} year old named {}!", age, name)
|
||||
}
|
||||
|
||||
#[get("/hello/<name>")]
|
||||
fn hi<'r>(name: &'r str) -> &'r str {
|
||||
fn hi(name: String) -> String {
|
||||
name
|
||||
}
|
||||
|
||||
|
|
|
@ -3,15 +3,17 @@
|
|||
|
||||
extern crate rocket;
|
||||
|
||||
use rocket::http::RawStr;
|
||||
|
||||
#[cfg(test)] mod tests;
|
||||
|
||||
#[get("/hello/<name>/<age>")]
|
||||
fn hello(name: &str, age: i8) -> String {
|
||||
fn hello(name: String, age: i8) -> String {
|
||||
format!("Hello, {} year old named {}!", age, name)
|
||||
}
|
||||
|
||||
#[get("/hello/<name>/<age>", rank = 2)]
|
||||
fn hi(name: &str, age: &str) -> String {
|
||||
fn hi(name: String, age: &RawStr) -> String {
|
||||
format!("Hi {}! Your age ({}) is kind of funky.", name, age)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,7 @@ use std::io;
|
|||
use std::fs::File;
|
||||
|
||||
use rocket::{Request, Route, Data, Catcher, Error};
|
||||
use rocket::http::Status;
|
||||
use rocket::request::FromParam;
|
||||
use rocket::http::{Status, RawStr};
|
||||
use rocket::response::{self, Responder};
|
||||
use rocket::response::status::Custom;
|
||||
use rocket::handler::Outcome;
|
||||
|
@ -23,7 +22,8 @@ fn hi(_req: &Request, _: Data) -> Outcome<'static> {
|
|||
}
|
||||
|
||||
fn name<'a>(req: &'a Request, _: Data) -> Outcome<'a> {
|
||||
Outcome::of(req.get_param(0).unwrap_or("unnamed"))
|
||||
let param = req.get_param::<&'a RawStr>(0);
|
||||
Outcome::of(param.map(|r| r.as_str()).unwrap_or("unnamed"))
|
||||
}
|
||||
|
||||
fn echo_url(req: &Request, _: Data) -> Outcome<'static> {
|
||||
|
@ -31,7 +31,8 @@ fn echo_url(req: &Request, _: Data) -> Outcome<'static> {
|
|||
.as_str()
|
||||
.split_at(6)
|
||||
.1;
|
||||
Outcome::of(String::from_param(param).unwrap())
|
||||
|
||||
Outcome::of(RawStr::from_str(param).url_decode())
|
||||
}
|
||||
|
||||
fn upload<'r>(req: &'r Request, data: Data) -> Outcome<'r> {
|
||||
|
|
|
@ -6,6 +6,7 @@ extern crate rocket;
|
|||
mod tests;
|
||||
|
||||
use rocket::response::Redirect;
|
||||
use rocket::http::RawStr;
|
||||
|
||||
#[get("/")]
|
||||
fn root() -> Redirect {
|
||||
|
@ -13,8 +14,8 @@ fn root() -> Redirect {
|
|||
}
|
||||
|
||||
#[get("/users/<name>")]
|
||||
fn user(name: &str) -> Result<&'static str, Redirect> {
|
||||
match name {
|
||||
fn user(name: &RawStr) -> Result<&'static str, Redirect> {
|
||||
match name.as_str() {
|
||||
"Sergio" => Ok("Hello, Sergio!"),
|
||||
_ => Err(Redirect::to("/users/login")),
|
||||
}
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
|
||||
extern crate rocket;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
#[cfg(test)] mod tests;
|
||||
|
||||
use rocket::http::RawStr;
|
||||
|
||||
#[get("/users/<name>")]
|
||||
fn user(name: &str) -> Option<&'static str> {
|
||||
fn user(name: &RawStr) -> Option<&'static str> {
|
||||
if name == "Sergio" {
|
||||
Some("Hello, Sergio!")
|
||||
} else {
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::fmt;
|
|||
use std::borrow::Cow;
|
||||
|
||||
use rocket::request::FromParam;
|
||||
use rocket::http::RawStr;
|
||||
use rand::{self, Rng};
|
||||
|
||||
/// Table to retrieve base62 values from.
|
||||
|
@ -44,9 +45,9 @@ fn valid_id(id: &str) -> bool {
|
|||
/// Returns an instance of `PasteID` if the path segment is a valid ID.
|
||||
/// Otherwise returns the invalid ID as the `Err` value.
|
||||
impl<'a> FromParam<'a> for PasteID<'a> {
|
||||
type Error = &'a str;
|
||||
type Error = &'a RawStr;
|
||||
|
||||
fn from_param(param: &'a str) -> Result<PasteID<'a>, &'a str> {
|
||||
fn from_param(param: &'a RawStr) -> Result<PasteID<'a>, &'a RawStr> {
|
||||
match valid_id(param) {
|
||||
true => Ok(PasteID(Cow::Borrowed(param))),
|
||||
false => Err(param)
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::path::PathBuf;
|
|||
use std::fmt::Debug;
|
||||
|
||||
use http::uri::{URI, Segments, SegmentError};
|
||||
use http::RawStr;
|
||||
|
||||
/// Trait to convert a dynamic path segment string to a concrete value.
|
||||
///
|
||||
|
@ -51,15 +52,16 @@ use http::uri::{URI, Segments, SegmentError};
|
|||
///
|
||||
/// For instance, imagine you've asked for an `<id>` as a `usize`. To determine
|
||||
/// when the `<id>` was not a valid `usize` and retrieve the string that failed
|
||||
/// to parse, you can use a `Result<usize, &str>` type for the `<id>` parameter
|
||||
/// as follows:
|
||||
/// to parse, you can use a `Result<usize, &RawStr>` type for the `<id>`
|
||||
/// parameter as follows:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(plugin)]
|
||||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// # use rocket::http::RawStr;
|
||||
/// #[get("/<id>")]
|
||||
/// fn hello(id: Result<usize, &str>) -> String {
|
||||
/// fn hello(id: Result<usize, &RawStr>) -> String {
|
||||
/// match id {
|
||||
/// Ok(id_num) => format!("usize: {}", id_num),
|
||||
/// Err(string) => format!("Not a usize: {}", string)
|
||||
|
@ -80,7 +82,7 @@ use http::uri::{URI, Segments, SegmentError};
|
|||
/// type returns successfully. Otherwise, the raw path segment is returned
|
||||
/// in the `Err` value.
|
||||
///
|
||||
/// * **str**
|
||||
/// * **&RawStr**
|
||||
///
|
||||
/// _This implementation always returns successfully._
|
||||
///
|
||||
|
@ -107,14 +109,6 @@ use http::uri::{URI, Segments, SegmentError};
|
|||
/// The path segment is parsed by `T`'s `FromParam` implementation. The
|
||||
/// returned `Result` value is returned.
|
||||
///
|
||||
/// # `str` vs. `String`
|
||||
///
|
||||
/// Paths are URL encoded. As a result, the `str` `FromParam` implementation
|
||||
/// returns the raw, URL encoded version of the path segment string. On the
|
||||
/// other hand, `String` decodes the path parameter, but requires an allocation
|
||||
/// to do so. This tradeoff is similiar to that of form values, and you should
|
||||
/// use whichever makes sense for your application.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Say you want to parse a segment of the form:
|
||||
|
@ -138,13 +132,14 @@ use http::uri::{URI, Segments, SegmentError};
|
|||
///
|
||||
/// ```rust
|
||||
/// use rocket::request::FromParam;
|
||||
/// use rocket::http::RawStr;
|
||||
/// # #[allow(dead_code)]
|
||||
/// # struct MyParam<'r> { key: &'r str, value: usize }
|
||||
///
|
||||
/// impl<'r> FromParam<'r> for MyParam<'r> {
|
||||
/// type Error = &'r str;
|
||||
/// type Error = &'r RawStr;
|
||||
///
|
||||
/// fn from_param(param: &'r str) -> Result<MyParam<'r>, &'r str> {
|
||||
/// fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||
/// let (key, val_str) = match param.find(':') {
|
||||
/// Some(i) if i > 0 => (¶m[..i], ¶m[(i + 1)..]),
|
||||
/// _ => return Err(param)
|
||||
|
@ -172,11 +167,12 @@ use http::uri::{URI, Segments, SegmentError};
|
|||
/// # #![plugin(rocket_codegen)]
|
||||
/// # extern crate rocket;
|
||||
/// # use rocket::request::FromParam;
|
||||
/// # use rocket::http::RawStr;
|
||||
/// # #[allow(dead_code)]
|
||||
/// # struct MyParam<'r> { key: &'r str, value: usize }
|
||||
/// # impl<'r> FromParam<'r> for MyParam<'r> {
|
||||
/// # type Error = &'r str;
|
||||
/// # fn from_param(param: &'r str) -> Result<MyParam<'r>, &'r str> {
|
||||
/// # type Error = &'r RawStr;
|
||||
/// # fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||
/// # Err(param)
|
||||
/// # }
|
||||
/// # }
|
||||
|
@ -197,29 +193,35 @@ pub trait FromParam<'a>: Sized {
|
|||
|
||||
/// Parses an instance of `Self` from a dynamic path parameter string or
|
||||
/// returns an `Error` if one cannot be parsed.
|
||||
fn from_param(param: &'a str) -> Result<Self, Self::Error>;
|
||||
fn from_param(param: &'a RawStr) -> Result<Self, Self::Error>;
|
||||
}
|
||||
|
||||
impl<'a> FromParam<'a> for &'a str {
|
||||
impl<'a> FromParam<'a> for &'a RawStr {
|
||||
type Error = ();
|
||||
fn from_param(param: &'a str) -> Result<&'a str, Self::Error> {
|
||||
|
||||
#[inline(always)]
|
||||
fn from_param(param: &'a RawStr) -> Result<&'a RawStr, Self::Error> {
|
||||
Ok(param)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromParam<'a> for String {
|
||||
type Error = &'a str;
|
||||
fn from_param(p: &'a str) -> Result<String, Self::Error> {
|
||||
URI::percent_decode(p.as_bytes()).map_err(|_| p).map(|s| s.into_owned())
|
||||
type Error = &'a RawStr;
|
||||
|
||||
#[inline(always)]
|
||||
fn from_param(param: &'a RawStr) -> Result<String, Self::Error> {
|
||||
param.percent_decode().map(|cow| cow.into_owned()).map_err(|_| param)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_with_fromstr {
|
||||
($($T:ident),+) => ($(
|
||||
impl<'a> FromParam<'a> for $T {
|
||||
type Error = &'a str;
|
||||
fn from_param(param: &'a str) -> Result<Self, Self::Error> {
|
||||
$T::from_str(param).map_err(|_| param)
|
||||
type Error = &'a RawStr;
|
||||
|
||||
#[inline(always)]
|
||||
fn from_param(param: &'a RawStr) -> Result<Self, Self::Error> {
|
||||
$T::from_str(param.as_str()).map_err(|_| param)
|
||||
}
|
||||
}
|
||||
)+)
|
||||
|
@ -230,22 +232,26 @@ impl_with_fromstr!(f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64,
|
|||
SocketAddr);
|
||||
|
||||
impl<'a, T: FromParam<'a>> FromParam<'a> for Result<T, T::Error> {
|
||||
type Error = ();
|
||||
fn from_param(p: &'a str) -> Result<Self, Self::Error> {
|
||||
Ok(match T::from_param(p) {
|
||||
Ok(val) => Ok(val),
|
||||
Err(e) => Err(e),
|
||||
})
|
||||
type Error = !;
|
||||
|
||||
#[inline]
|
||||
fn from_param(param: &'a RawStr) -> Result<Self, Self::Error> {
|
||||
match T::from_param(param) {
|
||||
Ok(val) => Ok(Ok(val)),
|
||||
Err(e) => Ok(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromParam<'a>> FromParam<'a> for Option<T> {
|
||||
type Error = ();
|
||||
fn from_param(p: &'a str) -> Result<Self, Self::Error> {
|
||||
Ok(match T::from_param(p) {
|
||||
Ok(val) => Some(val),
|
||||
Err(_) => None
|
||||
})
|
||||
type Error = !;
|
||||
|
||||
#[inline]
|
||||
fn from_param(param: &'a RawStr) -> Result<Self, Self::Error> {
|
||||
match T::from_param(param) {
|
||||
Ok(val) => Ok(Some(val)),
|
||||
Err(_) => Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,9 +283,10 @@ pub trait FromSegments<'a>: Sized {
|
|||
}
|
||||
|
||||
impl<'a> FromSegments<'a> for Segments<'a> {
|
||||
type Error = ();
|
||||
type Error = !;
|
||||
|
||||
fn from_segments(segments: Segments<'a>) -> Result<Segments<'a>, ()> {
|
||||
#[inline(always)]
|
||||
fn from_segments(segments: Segments<'a>) -> Result<Segments<'a>, Self::Error> {
|
||||
Ok(segments)
|
||||
}
|
||||
}
|
||||
|
@ -335,21 +342,25 @@ impl<'a> FromSegments<'a> for PathBuf {
|
|||
}
|
||||
|
||||
impl<'a, T: FromSegments<'a>> FromSegments<'a> for Result<T, T::Error> {
|
||||
type Error = ();
|
||||
fn from_segments(segments: Segments<'a>) -> Result<Result<T, T::Error>, ()> {
|
||||
Ok(match T::from_segments(segments) {
|
||||
Ok(val) => Ok(val),
|
||||
Err(e) => Err(e),
|
||||
})
|
||||
type Error = !;
|
||||
|
||||
#[inline]
|
||||
fn from_segments(segments: Segments<'a>) -> Result<Result<T, T::Error>, !> {
|
||||
match T::from_segments(segments) {
|
||||
Ok(val) => Ok(Ok(val)),
|
||||
Err(e) => Ok(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromSegments<'a>> FromSegments<'a> for Option<T> {
|
||||
type Error = ();
|
||||
fn from_segments(segments: Segments<'a>) -> Result<Option<T>, ()> {
|
||||
Ok(match T::from_segments(segments) {
|
||||
Ok(val) => Some(val),
|
||||
Err(_) => None
|
||||
})
|
||||
type Error = !;
|
||||
|
||||
#[inline]
|
||||
fn from_segments(segments: Segments<'a>) -> Result<Option<T>, !> {
|
||||
match T::from_segments(segments) {
|
||||
Ok(val) => Ok(Some(val)),
|
||||
Err(_) => Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use super::{FromParam, FromSegments};
|
|||
use router::Route;
|
||||
use http::uri::{URI, Segments};
|
||||
use http::{Method, Header, HeaderMap, Cookies, Session, CookieJar, Key};
|
||||
use http::{ContentType, Accept, MediaType};
|
||||
use http::{RawStr, ContentType, Accept, MediaType};
|
||||
use http::parse::media_type;
|
||||
use http::hyper;
|
||||
|
||||
|
@ -362,7 +362,7 @@ impl<'r> Request<'r> {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Retrieve parameter `0`, which is expected to be an `&str`, in a manual
|
||||
/// Retrieve parameter `0`, which is expected to be a `String`, in a manual
|
||||
/// route:
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -371,7 +371,7 @@ impl<'r> Request<'r> {
|
|||
///
|
||||
/// # #[allow(dead_code)]
|
||||
/// fn name<'a>(req: &'a Request, _: Data) -> Outcome<'a> {
|
||||
/// Outcome::of(req.get_param(0).unwrap_or("unnamed"))
|
||||
/// Outcome::of(req.get_param::<String>(0).unwrap_or("unnamed".into()))
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_param<'a, T: FromParam<'a>>(&'a self, n: usize) -> Result<T, Error> {
|
||||
|
@ -391,7 +391,7 @@ impl<'r> Request<'r> {
|
|||
/// Get the `n`th path parameter as a string, if it exists. This is used by
|
||||
/// codegen.
|
||||
#[doc(hidden)]
|
||||
pub fn get_param_str(&self, n: usize) -> Option<&str> {
|
||||
pub fn get_param_str(&self, n: usize) -> Option<&RawStr> {
|
||||
let params = self.extra.params.borrow();
|
||||
if n >= params.len() {
|
||||
debug!("{} is >= param count {}", n, params.len());
|
||||
|
@ -405,7 +405,7 @@ impl<'r> Request<'r> {
|
|||
return None;
|
||||
}
|
||||
|
||||
Some(&path[i..j])
|
||||
Some(path[i..j].into())
|
||||
}
|
||||
|
||||
/// Retrieves and parses into `T` all of the path segments in the request
|
||||
|
|
|
@ -53,9 +53,10 @@ const FLASH_COOKIE_NAME: &'static str = "_flash";
|
|||
/// #
|
||||
/// use rocket::response::{Flash, Redirect};
|
||||
/// use rocket::request::FlashMessage;
|
||||
/// use rocket::http::RawStr;
|
||||
///
|
||||
/// #[post("/login/<name>")]
|
||||
/// fn login(name: &str) -> Result<&'static str, Flash<Redirect>> {
|
||||
/// fn login(name: &RawStr) -> Result<&'static str, Flash<Redirect>> {
|
||||
/// if name == "special_user" {
|
||||
/// Ok("Hello, special user!")
|
||||
/// } else {
|
||||
|
|
Loading…
Reference in New Issue