Add 'LocalRequest::private_cookie()'.

Resolves #368.
This commit is contained in:
Stanislav Ivanov 2017-11-30 19:30:31 +02:00 committed by Sergio Benitez
parent dd07c367d5
commit 70413b155f
4 changed files with 103 additions and 17 deletions

View File

@ -38,7 +38,7 @@ isatty = "0.1"
[dependencies.cookie] [dependencies.cookie]
git = "https://github.com/alexcrichton/cookie-rs" git = "https://github.com/alexcrichton/cookie-rs"
rev = "b8298e" rev = "f4e6930"
features = ["percent-encode", "secure"] features = ["percent-encode", "secure"]
[dev-dependencies] [dev-dependencies]

View File

@ -231,26 +231,46 @@ impl<'a> Cookies<'a> {
/// ``` /// ```
pub fn add_private(&mut self, mut cookie: Cookie<'static>) { pub fn add_private(&mut self, mut cookie: Cookie<'static>) {
if let Cookies::Jarred(ref mut jar, key) = *self { if let Cookies::Jarred(ref mut jar, key) = *self {
if cookie.path().is_none() { Cookies::set_private_defaults(&mut cookie);
cookie.set_path("/");
}
if cookie.http_only().is_none() {
cookie.set_http_only(true);
}
if cookie.expires().is_none() {
cookie.set_expires(::time::now() + ::time::Duration::weeks(1));
}
if cookie.same_site().is_none() {
cookie.set_same_site(SameSite::Strict);
}
jar.private(key).add(cookie) jar.private(key).add(cookie)
} }
} }
/// Adds an original, private `cookie` to the collection.
pub(crate) fn add_original_private(&mut self, mut cookie: Cookie<'static>) {
if let Cookies::Jarred(ref mut jar, key) = *self {
Cookies::set_private_defaults(&mut cookie);
jar.private(key).add_original(cookie)
}
}
/// For each property mentioned below, this method checks
/// if there is provided value and if there is none, set default value.
/// Default values are:
///
/// * `path`: `"/"`
/// * `SameSite`: `Strict`
/// * `HttpOnly`: `true`
/// * `Expires`: 1 week from now
///
fn set_private_defaults(cookie: &mut Cookie<'static>) {
if cookie.path().is_none() {
cookie.set_path("/");
}
if cookie.http_only().is_none() {
cookie.set_http_only(true);
}
if cookie.expires().is_none() {
cookie.set_expires(::time::now() + ::time::Duration::weeks(1));
}
if cookie.same_site().is_none() {
cookie.set_same_site(SameSite::Strict);
}
}
/// Removes `cookie` from this collection and generates a "removal" cookies /// Removes `cookie` from this collection and generates a "removal" cookies
/// to send to the client on response. For correctness, `cookie` must /// to send to the client on response. For correctness, `cookie` must
/// contain the same `path` and `domain` as the cookie that was initially /// contain the same `path` and `domain` as the cookie that was initially

View File

@ -189,6 +189,28 @@ impl<'c> LocalRequest<'c> {
self self
} }
/// Add a [private cookie] to this request.
///
/// [private cookie]: /rocket/http/enum.Cookies.html#private-cookies
///
/// # Examples
///
/// Add `user_id` as a private cookie:
///
/// ```rust
/// use rocket::local::Client;
/// use rocket::http::Cookie;
///
/// let client = Client::new(rocket::ignite()).unwrap();
/// # #[allow(unused_variables)]
/// let req = client.get("/").private_cookie(Cookie::new("user_id", "sb"));
/// ```
#[inline]
pub fn private_cookie(self, cookie: Cookie<'static>) -> Self {
self.request.cookies().add_original_private(cookie);
self
}
// TODO: For CGI, we want to be able to set the body to be stdin without // TODO: For CGI, we want to be able to set the body to be stdin without
// actually reading everything into a vector. Can we allow that here while // actually reading everything into a vector. Can we allow that here while
// keeping the simplicity? Looks like it would require us to reintroduce a // keeping the simplicity? Looks like it would require us to reintroduce a

View File

@ -0,0 +1,44 @@
#![feature(plugin, decl_macro)]
#![plugin(rocket_codegen)]
extern crate rocket;
use rocket::http::Cookies;
#[get("/")]
fn return_private_cookie(mut cookies: Cookies) -> Option<String> {
match cookies.get_private("cookie_name") {
Some(cookie) => Some(cookie.value().into()),
None => None,
}
}
mod tests {
use super::*;
use rocket::local::Client;
use rocket::http::Cookie;
use rocket::http::Status;
#[test]
fn private_cookie_is_returned() {
let rocket = rocket::ignite().mount("/", routes![return_private_cookie]);
let client = Client::new(rocket).unwrap();
let req = client.get("/").private_cookie(Cookie::new("cookie_name", "cookie_value"));
let mut response = req.dispatch();
assert_eq!(response.body_string(), Some("cookie_value".into()));
assert_eq!(response.headers().get_one("Set-Cookie"), None);
}
#[test]
fn regular_cookie_is_not_returned() {
let rocket = rocket::ignite().mount("/", routes![return_private_cookie]);
let client = Client::new(rocket).unwrap();
let req = client.get("/").cookie(Cookie::new("cookie_name", "cookie_value"));
let response = req.dispatch();
assert_eq!(response.status(), Status::NotFound);
}
}