Rocket/core/http/src/cookies.rs

597 lines
19 KiB
Rust
Raw Normal View History

Remove Session in favor of private cookies. New testing API. Sessions -------- This commit removes the `Session` type in favor of methods on the `Cookies` types that allow for adding, removing, and getting private (signed and encrypted) cookies. These methods provide a superset of the functionality of `Session` while also being a minimal addition to the existing API. They can be used to implement the previous `Session` type as well as other forms of session storage. The new methods are: * Cookie::add_private(&mut self, Cookie) * Cookie::remove_private(&mut self, Cookie) * Cookie::get_private(&self, &str) Resolves #20 Testing ------- This commit removes the `rocket::testing` module. It adds the `rocket::local` module which provides a `Client` type for local dispatching of requests against a `Rocket` instance. This `local` package subsumes the previous `testing` package. Rocket Examples --------------- The `forms`, `optional_result`, and `hello_alt_methods` examples have been removed. The following example have been renamed: * extended_validation -> form_validation * hello_ranks -> ranking * from_request -> request_guard * hello_tls -> tls Other Changes ------------- This commit also includes the following smaller changes: * Config::{development, staging, production} constructors have been added for easier creation of default `Config` structures. * The `Config` type is exported from the root. * `Request` implements `Clone` and `Debug`. * `Request::new` is no longer exported. * A `Response::body_bytes` method was added to easily retrieve a response's body as a `Vec<u8>`.
2017-06-06 20:41:04 +00:00
use std::fmt;
use parking_lot::Mutex;
2019-06-13 01:33:40 +00:00
use crate::Header;
pub use cookie::{Cookie, SameSite, Iter};
#[doc(hidden)] pub use self::key::*;
/// Types and methods to manage a `Key` when private cookies are enabled.
#[cfg(feature = "private-cookies")]
mod key {
pub use cookie::Key;
}
/// Types and methods to manage a `Key` when private cookies are disabled.
#[cfg(not(feature = "private-cookies"))]
mod key {
#[derive(Copy, Clone)]
pub struct Key;
impl Key {
Revamp configuration. This commit completely overhauls Rocket's configuration systems, basing it on the new Figment library. It includes many breaking changes pertaining to configuration. They are: * "Environments" are replaced by "profiles". * 'ROCKET_PROFILE' takes the place of 'ROCKET_ENV'. * Profile names are now arbitrary, but 'debug' and 'release' are given special treatment as default profiles for the debug and release compilation profiles. * A 'default' profile now sits along-side the meta 'global' profile. * The concept of "extras" is no longer present; users can extract any values they want from the configured 'Figment'. * The 'Poolable' trait takes an '&Config'. * The 'secrets' feature is disabled by default. * It is a hard error if 'secrets' is enabled under the 'release' profile and no 'secret_key' is configured. * 'ConfigBuilder' no longer exists: all fields of 'Config' are public with public constructors for each type. * 'keep_alive' is disabled with '0', not 'false' or 'off'. * Inlined error variants into the 'Error' structure. * 'LoggingLevel' is now 'LogLevel'. * Limits can now be specified in SI units: "1 MiB". The summary of other changes are: * The default config file can be configured with 'ROCKET_CONFIG'. * HTTP/1 and HTTP/2 keep-alive configuration is restored. * 'ctrlc' is now a recognized config option. * 'serde' is now a core dependency. * TLS misconfiguration errors are improved. * Several example use '_' as the return type of '#[launch]' fns. * 'AdHoc::config()' was added for simple config extraction. * Added more documentation for using 'Limits'. * Launch information is no longer treated specially. * The configuration guide was rewritten. Resolves #852. Resolves #209. Closes #1404. Closes #652.
2020-09-03 05:41:31 +00:00
pub fn from(_: &[u8]) -> Self { Key }
pub fn derive_from(_: &[u8]) -> Self { Key }
pub fn generate() -> Self { Key }
2020-06-07 11:02:18 +00:00
pub fn try_generate() -> Option<Self> { Some(Key) }
Revamp configuration. This commit completely overhauls Rocket's configuration systems, basing it on the new Figment library. It includes many breaking changes pertaining to configuration. They are: * "Environments" are replaced by "profiles". * 'ROCKET_PROFILE' takes the place of 'ROCKET_ENV'. * Profile names are now arbitrary, but 'debug' and 'release' are given special treatment as default profiles for the debug and release compilation profiles. * A 'default' profile now sits along-side the meta 'global' profile. * The concept of "extras" is no longer present; users can extract any values they want from the configured 'Figment'. * The 'Poolable' trait takes an '&Config'. * The 'secrets' feature is disabled by default. * It is a hard error if 'secrets' is enabled under the 'release' profile and no 'secret_key' is configured. * 'ConfigBuilder' no longer exists: all fields of 'Config' are public with public constructors for each type. * 'keep_alive' is disabled with '0', not 'false' or 'off'. * Inlined error variants into the 'Error' structure. * 'LoggingLevel' is now 'LogLevel'. * Limits can now be specified in SI units: "1 MiB". The summary of other changes are: * The default config file can be configured with 'ROCKET_CONFIG'. * HTTP/1 and HTTP/2 keep-alive configuration is restored. * 'ctrlc' is now a recognized config option. * 'serde' is now a core dependency. * TLS misconfiguration errors are improved. * Several example use '_' as the return type of '#[launch]' fns. * 'AdHoc::config()' was added for simple config extraction. * Added more documentation for using 'Limits'. * Launch information is no longer treated specially. * The configuration guide was rewritten. Resolves #852. Resolves #209. Closes #1404. Closes #652.
2020-09-03 05:41:31 +00:00
}
impl PartialEq for Key {
fn eq(&self, _: &Self) -> bool {
true
}
}
}
/// Collection of one or more HTTP cookies.
///
/// `CookieJar` allows for retrieval of cookies from an incoming request. It
/// also tracks modifications (additions and removals) and marks them as
/// pending.
///
/// # Pending
///
/// Changes to a `CookieJar` are _not_ visible via the normal [`get()`] and
/// [`get_private()`] methods. This is typically the desired effect as a
/// `CookieJar` always reflects the cookies in an incoming request. In cases
/// where this is not desired, the [`get_pending()`] and
/// [`get_private_pending()`] methods are available, which always return the
/// latest changes.
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{CookieJar, Cookie};
///
/// #[get("/message")]
/// fn message(jar: &CookieJar<'_>) {
/// jar.add(Cookie::new("message", "hello!"));
/// jar.add(Cookie::new("other", "bye!"));
///
/// // `get()` does not reflect changes.
/// assert!(jar.get("other").is_none());
/// # assert_eq!(jar.get("message").map(|c| c.value()), Some("hi"));
///
/// // `get_pending()` does.
/// let other_pending = jar.get_pending("other");
/// let message_pending = jar.get_pending("message");
/// assert_eq!(other_pending.as_ref().map(|c| c.value()), Some("bye!"));
/// assert_eq!(message_pending.as_ref().map(|c| c.value()), Some("hello!"));
/// # jar.remove(Cookie::named("message"));
/// # assert_eq!(jar.get("message").map(|c| c.value()), Some("hi"));
/// # assert!(jar.get_pending("message").is_none());
/// }
/// # fn main() {
/// # use rocket::local::blocking::Client;
/// # let rocket = rocket::ignite().mount("/", routes![message]);
/// # let client = Client::tracked(rocket).unwrap();
/// # let response = client.get("/message")
/// # .cookie(Cookie::new("message", "hi"))
/// # .dispatch();
/// #
/// # assert!(response.status().class().is_success());
/// # }
/// ```
///
/// # Usage
///
/// A type of `&CookieJar` can be retrieved via its `FromRequest` implementation
/// as a request guard or via the [`Request::cookies()`] method. Individual
/// cookies can be retrieved via the [`get()`] and [`get_private()`] methods.
/// Pending changes can be observed via the [`get_pending()`] and
/// [`get_private_pending()`] methods. Cookies can be added or removed via the
/// [`add()`], [`add_private()`], [`remove()`], and [`remove_private()`]
/// methods.
///
2019-06-13 01:33:40 +00:00
/// [`Request::cookies()`]: rocket::Request::cookies()
/// [`get()`]: #method.get
/// [`get_private()`]: #method.get_private
/// [`get_pending()`]: #method.get_pending
/// [`get_private_pending()`]: #method.get_private_pending
/// [`add()`]: #method.add
/// [`add_private()`]: #method.add_private
/// [`remove()`]: #method.remove
/// [`remove_private()`]: #method.remove_private
///
/// ## Examples
///
/// The following example shows `&CookieJar` being used as a request guard in a
/// handler to retrieve the value of a "message" cookie.
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::CookieJar;
///
/// #[get("/message")]
/// fn message<'a>(jar: &'a CookieJar<'_>) -> Option<&'a str> {
/// jar.get("message").map(|cookie| cookie.value())
/// }
/// # fn main() { }
/// ```
///
/// The following snippet shows `&CookieJar` being retrieved from a `Request` in
/// a custom request guard implementation for `User`. A [private cookie]
/// containing a user's ID is retrieved. If the cookie exists and the ID parses
/// as an integer, a `User` structure is validated. Otherwise, the guard
/// forwards.
///
/// [private cookie]: #method.add_private
///
/// ```rust
/// # #[macro_use] extern crate rocket;
Revamp configuration. This commit completely overhauls Rocket's configuration systems, basing it on the new Figment library. It includes many breaking changes pertaining to configuration. They are: * "Environments" are replaced by "profiles". * 'ROCKET_PROFILE' takes the place of 'ROCKET_ENV'. * Profile names are now arbitrary, but 'debug' and 'release' are given special treatment as default profiles for the debug and release compilation profiles. * A 'default' profile now sits along-side the meta 'global' profile. * The concept of "extras" is no longer present; users can extract any values they want from the configured 'Figment'. * The 'Poolable' trait takes an '&Config'. * The 'secrets' feature is disabled by default. * It is a hard error if 'secrets' is enabled under the 'release' profile and no 'secret_key' is configured. * 'ConfigBuilder' no longer exists: all fields of 'Config' are public with public constructors for each type. * 'keep_alive' is disabled with '0', not 'false' or 'off'. * Inlined error variants into the 'Error' structure. * 'LoggingLevel' is now 'LogLevel'. * Limits can now be specified in SI units: "1 MiB". The summary of other changes are: * The default config file can be configured with 'ROCKET_CONFIG'. * HTTP/1 and HTTP/2 keep-alive configuration is restored. * 'ctrlc' is now a recognized config option. * 'serde' is now a core dependency. * TLS misconfiguration errors are improved. * Several example use '_' as the return type of '#[launch]' fns. * 'AdHoc::config()' was added for simple config extraction. * Added more documentation for using 'Limits'. * Launch information is no longer treated specially. * The configuration guide was rewritten. Resolves #852. Resolves #209. Closes #1404. Closes #652.
2020-09-03 05:41:31 +00:00
/// # #[cfg(feature = "private-cookies")] {
/// use rocket::http::Status;
/// use rocket::outcome::IntoOutcome;
/// use rocket::request::{self, Request, FromRequest};
///
/// // In practice, we'd probably fetch the user from the database.
/// struct User(usize);
///
/// #[rocket::async_trait]
/// impl<'a, 'r> FromRequest<'a, 'r> for User {
/// type Error = std::convert::Infallible;
///
/// async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
/// request.cookies()
/// .get_private("user_id")
/// .and_then(|c| c.value().parse().ok())
/// .map(|id| User(id))
/// .or_forward(())
/// }
/// }
Revamp configuration. This commit completely overhauls Rocket's configuration systems, basing it on the new Figment library. It includes many breaking changes pertaining to configuration. They are: * "Environments" are replaced by "profiles". * 'ROCKET_PROFILE' takes the place of 'ROCKET_ENV'. * Profile names are now arbitrary, but 'debug' and 'release' are given special treatment as default profiles for the debug and release compilation profiles. * A 'default' profile now sits along-side the meta 'global' profile. * The concept of "extras" is no longer present; users can extract any values they want from the configured 'Figment'. * The 'Poolable' trait takes an '&Config'. * The 'secrets' feature is disabled by default. * It is a hard error if 'secrets' is enabled under the 'release' profile and no 'secret_key' is configured. * 'ConfigBuilder' no longer exists: all fields of 'Config' are public with public constructors for each type. * 'keep_alive' is disabled with '0', not 'false' or 'off'. * Inlined error variants into the 'Error' structure. * 'LoggingLevel' is now 'LogLevel'. * Limits can now be specified in SI units: "1 MiB". The summary of other changes are: * The default config file can be configured with 'ROCKET_CONFIG'. * HTTP/1 and HTTP/2 keep-alive configuration is restored. * 'ctrlc' is now a recognized config option. * 'serde' is now a core dependency. * TLS misconfiguration errors are improved. * Several example use '_' as the return type of '#[launch]' fns. * 'AdHoc::config()' was added for simple config extraction. * Added more documentation for using 'Limits'. * Launch information is no longer treated specially. * The configuration guide was rewritten. Resolves #852. Resolves #209. Closes #1404. Closes #652.
2020-09-03 05:41:31 +00:00
/// # }
/// # fn main() { }
/// ```
///
/// # Private Cookies
///
/// _Private_ cookies are just like regular cookies except that they are
/// encrypted using authenticated encryption, a form of encryption which
/// simultaneously provides confidentiality, integrity, and authenticity. This
/// means that private cookies cannot be inspected, tampered with, or
/// manufactured by clients. If you prefer, you can think of private cookies as
/// being signed and encrypted.
///
/// Private cookies can be retrieved, added, and removed from a `CookieJar`
/// collection via the [`get_private()`], [`add_private()`], and
/// [`remove_private()`] methods.
///
/// ## Encryption Key
///
/// To encrypt private cookies, Rocket uses the 256-bit key specified in the
/// `secret_key` configuration parameter. If one is not specified, Rocket will
/// automatically generate a fresh key. Note, however, that a private cookie can
/// only be decrypted with the same key with which it was encrypted. As such, it
/// is important to set a `secret_key` configuration parameter when using
/// private cookies so that cookies decrypt properly after an application
/// restart. Rocket will emit a warning if an application is run in production
/// mode without a configured `secret_key`.
///
/// Generating a string suitable for use as a `secret_key` configuration value
/// is usually done through tools like `openssl`. Using `openssl`, for instance,
/// a 256-bit base64 key can be generated with the command `openssl rand -base64
/// 32`.
pub struct CookieJar<'a> {
jar: cookie::CookieJar,
key: &'a Key,
ops: Mutex<Vec<Op>>,
}
impl<'a> Clone for CookieJar<'a> {
fn clone(&self) -> Self {
CookieJar {
jar: self.jar.clone(),
key: self.key,
ops: Mutex::new(self.ops.lock().clone()),
}
}
}
#[derive(Clone)]
enum Op {
Add(Cookie<'static>, bool),
Remove(Cookie<'static>, bool),
}
impl Op {
fn cookie(&self) -> &Cookie<'static> {
match self {
Op::Add(c, _) | Op::Remove(c, _) => c
}
}
}
impl<'a> CookieJar<'a> {
/// Returns a reference to the _original_ `Cookie` inside this container
/// with the name `name`. If no such cookie exists, returns `None`.
///
/// **Note:** This method _does not_ obverse changes made via additions and
/// removals to the cookie jar. To observe those changes, use
/// [`CookieJar::get_pending()`].
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// let cookie = jar.get("name");
/// }
/// ```
pub fn get(&self, name: &str) -> Option<&Cookie<'static>> {
self.jar.get(name)
}
/// Retrives the _original_ `Cookie` inside this collection with the name
/// `name` and authenticates and decrypts the cookie's value. If the cookie
/// cannot be found, or the cookie fails to authenticate or decrypt, `None`
/// is returned.
///
/// **Note:** This method _does not_ obverse changes made via additions and
/// removals to the cookie jar. To observe those changes, use
/// [`CookieJar::get_private_pending()`].
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// let cookie = jar.get_private("name");
/// }
/// ```
#[cfg(feature = "private-cookies")]
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
pub fn get_private(&self, name: &str) -> Option<Cookie<'static>> {
self.jar.private(&*self.key).get(name)
Remove Session in favor of private cookies. New testing API. Sessions -------- This commit removes the `Session` type in favor of methods on the `Cookies` types that allow for adding, removing, and getting private (signed and encrypted) cookies. These methods provide a superset of the functionality of `Session` while also being a minimal addition to the existing API. They can be used to implement the previous `Session` type as well as other forms of session storage. The new methods are: * Cookie::add_private(&mut self, Cookie) * Cookie::remove_private(&mut self, Cookie) * Cookie::get_private(&self, &str) Resolves #20 Testing ------- This commit removes the `rocket::testing` module. It adds the `rocket::local` module which provides a `Client` type for local dispatching of requests against a `Rocket` instance. This `local` package subsumes the previous `testing` package. Rocket Examples --------------- The `forms`, `optional_result`, and `hello_alt_methods` examples have been removed. The following example have been renamed: * extended_validation -> form_validation * hello_ranks -> ranking * from_request -> request_guard * hello_tls -> tls Other Changes ------------- This commit also includes the following smaller changes: * Config::{development, staging, production} constructors have been added for easier creation of default `Config` structures. * The `Config` type is exported from the root. * `Request` implements `Clone` and `Debug`. * `Request::new` is no longer exported. * A `Response::body_bytes` method was added to easily retrieve a response's body as a `Vec<u8>`.
2017-06-06 20:41:04 +00:00
}
/// Returns a reference to the _original or pending_ `Cookie` inside this
/// container with the name `name`. If no such cookie exists, returns
/// `None`.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// let pending_cookie = jar.get_pending("name");
/// }
/// ```
pub fn get_pending(&self, name: &str) -> Option<Cookie<'static>> {
let ops = self.ops.lock();
for op in ops.iter().rev().filter(|op| op.cookie().name() == name) {
match op {
Op::Add(c, _) => return Some(c.clone()),
Op::Remove(_, _) => return None,
}
}
drop(ops);
self.get(name).map(|c| c.clone())
}
/// Retrives the _original or pending_ `Cookie` inside this collection with
/// the name `name` and authenticates and decrypts the cookie's value. If
/// the cookie cannot be found, or the cookie fails to authenticate or
/// decrypt, `None` is returned.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// let pending_cookie = jar.get_private_pending("name");
/// }
/// ```
#[cfg(feature = "private-cookies")]
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
pub fn get_private_pending(&self, name: &str) -> Option<Cookie<'static>> {
let cookie = self.get_pending(name)?;
self.jar.private(&*self.key).decrypt(cookie)
}
/// Adds `cookie` to this collection.
///
/// Unless a value is set for the given property, the following defaults are
/// set on `cookie` before being added to `self`:
///
/// * `path`: `"/"`
/// * `SameSite`: `Strict`
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, SameSite, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// jar.add(Cookie::new("first", "value"));
///
/// let cookie = Cookie::build("other", "value_two")
/// .path("/")
/// .secure(true)
/// .same_site(SameSite::Lax);
///
/// jar.add(cookie.finish());
/// }
/// ```
pub fn add(&self, mut cookie: Cookie<'static>) {
Self::set_defaults(&mut cookie);
self.ops.lock().push(Op::Add(cookie, false));
}
/// Adds `cookie` to the collection. The cookie's value is encrypted with
/// authenticated encryption assuring confidentiality, integrity, and
/// authenticity. The cookie can later be retrieved using
/// [`get_private`](#method.get_private) and removed using
/// [`remove_private`](#method.remove_private).
///
/// Unless a value is set for the given property, the following defaults are
/// set on `cookie` before being added to `self`:
///
/// * `path`: `"/"`
/// * `SameSite`: `Strict`
/// * `HttpOnly`: `true`
/// * `Expires`: 1 week from now
///
/// These defaults ensure maximum usability and security. For additional
/// security, you may wish to set the `secure` flag.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// jar.add_private(Cookie::new("name", "value"));
/// }
/// ```
#[cfg(feature = "private-cookies")]
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
pub fn add_private(&self, mut cookie: Cookie<'static>) {
Self::set_private_defaults(&mut cookie);
self.ops.lock().push(Op::Add(cookie, true));
}
/// Removes `cookie` from this collection and generates a "removal" cookies
/// to send to the client on response. For correctness, `cookie` must
/// contain the same `path` and `domain` as the cookie that was initially
/// set. Failure to provide the initial `path` and `domain` will result in
/// cookies that are not properly removed. For convenience, if a path is not
/// set on `cookie`, the `"/"` path will automatically be set.
///
/// A "removal" cookie is a cookie that has the same name as the original
/// cookie but has an empty value, a max-age of 0, and an expiration date
/// far in the past.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// jar.remove(Cookie::named("name"));
/// }
/// ```
pub fn remove(&self, mut cookie: Cookie<'static>) {
if cookie.path().is_none() {
cookie.set_path("/");
}
self.ops.lock().push(Op::Remove(cookie, false));
}
/// Removes the private `cookie` from the collection.
///
/// For correct removal, the passed in `cookie` must contain the same `path`
/// and `domain` as the cookie that was initially set. If a path is not set
/// on `cookie`, the `"/"` path will automatically be set.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// jar.remove_private(Cookie::named("name"));
/// }
/// ```
#[cfg(feature = "private-cookies")]
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
pub fn remove_private(&self, mut cookie: Cookie<'static>) {
if cookie.path().is_none() {
cookie.set_path("/");
}
self.ops.lock().push(Op::Remove(cookie, true));
}
/// Returns an iterator over all of the _original_ cookies present in this
/// collection.
///
/// **Note:** This method _does not_ obverse changes made via additions and
/// removals to the cookie jar.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::http::{Cookie, CookieJar};
///
/// #[get("/")]
/// fn handler(jar: &CookieJar<'_>) {
/// for c in jar.iter() {
/// println!("Name: {:?}, Value: {:?}", c.name(), c.value());
/// }
/// }
/// ```
pub fn iter(&self) -> impl Iterator<Item=&Cookie<'static>> {
self.jar.iter()
}
}
/// WARNING: These are unstable! Do not use outside of Rocket!
#[doc(hidden)]
impl<'a> CookieJar<'a> {
#[inline(always)]
pub fn new(key: &'a Key) -> Self {
CookieJar {
jar: cookie::CookieJar::new(),
key, ops: Mutex::new(Vec::new()),
}
}
#[inline(always)]
pub fn from(jar: cookie::CookieJar, key: &'a Key) -> CookieJar<'a> {
CookieJar { jar, key, ops: Mutex::new(Vec::new()) }
}
/// Removes all delta cookies.
#[inline(always)]
pub fn reset_delta(&self) {
self.ops.lock().clear();
}
/// TODO: This could be faster by just returning the cookies directly via
/// an ordered hash-set of sorts.
#[inline(always)]
pub fn take_delta_jar(&self) -> cookie::CookieJar {
let ops = std::mem::replace(&mut *self.ops.lock(), Vec::new());
let mut jar = cookie::CookieJar::new();
for op in ops {
match op {
Op::Add(c, false) => jar.add(c),
#[cfg(feature = "private-cookies")]
Op::Add(c, true) => jar.private_mut(self.key).add(c),
Op::Remove(mut c, _) => {
if self.jar.get(c.name()).is_some() {
c.make_removal();
jar.add(c);
} else {
jar.remove(c);
}
}
#[allow(unreachable_patterns)]
_ => unreachable!()
}
}
jar
}
/// Adds an original `cookie` to this collection.
#[inline(always)]
pub fn add_original(&mut self, cookie: Cookie<'static>) {
self.jar.add_original(cookie)
}
/// Adds an original, private `cookie` to the collection.
#[inline(always)]
#[cfg(feature = "private-cookies")]
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
pub fn add_original_private(&mut self, cookie: Cookie<'static>) {
self.jar.private_mut(&*self.key).add_original(cookie);
}
/// For each property mentioned below, this method checks if there is a
/// provided value and if there is none, sets a default value. Default
/// values are:
///
/// * `path`: `"/"`
/// * `SameSite`: `Strict`
///
fn set_defaults(cookie: &mut Cookie<'static>) {
if cookie.path().is_none() {
cookie.set_path("/");
}
Remove Session in favor of private cookies. New testing API. Sessions -------- This commit removes the `Session` type in favor of methods on the `Cookies` types that allow for adding, removing, and getting private (signed and encrypted) cookies. These methods provide a superset of the functionality of `Session` while also being a minimal addition to the existing API. They can be used to implement the previous `Session` type as well as other forms of session storage. The new methods are: * Cookie::add_private(&mut self, Cookie) * Cookie::remove_private(&mut self, Cookie) * Cookie::get_private(&self, &str) Resolves #20 Testing ------- This commit removes the `rocket::testing` module. It adds the `rocket::local` module which provides a `Client` type for local dispatching of requests against a `Rocket` instance. This `local` package subsumes the previous `testing` package. Rocket Examples --------------- The `forms`, `optional_result`, and `hello_alt_methods` examples have been removed. The following example have been renamed: * extended_validation -> form_validation * hello_ranks -> ranking * from_request -> request_guard * hello_tls -> tls Other Changes ------------- This commit also includes the following smaller changes: * Config::{development, staging, production} constructors have been added for easier creation of default `Config` structures. * The `Config` type is exported from the root. * `Request` implements `Clone` and `Debug`. * `Request::new` is no longer exported. * A `Response::body_bytes` method was added to easily retrieve a response's body as a `Vec<u8>`.
2017-06-06 20:41:04 +00:00
if cookie.same_site().is_none() {
cookie.set_same_site(SameSite::Strict);
}
}
/// For each property mentioned below, this method checks if there is a
/// provided value and if there is none, sets a default value. Default
/// values are:
///
/// * `path`: `"/"`
/// * `SameSite`: `Strict`
/// * `HttpOnly`: `true`
/// * `Expires`: 1 week from now
///
#[cfg(feature = "private-cookies")]
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
fn set_private_defaults(cookie: &mut Cookie<'static>) {
if cookie.path().is_none() {
cookie.set_path("/");
}
if cookie.same_site().is_none() {
cookie.set_same_site(SameSite::Strict);
}
if cookie.http_only().is_none() {
cookie.set_http_only(true);
}
Remove Session in favor of private cookies. New testing API. Sessions -------- This commit removes the `Session` type in favor of methods on the `Cookies` types that allow for adding, removing, and getting private (signed and encrypted) cookies. These methods provide a superset of the functionality of `Session` while also being a minimal addition to the existing API. They can be used to implement the previous `Session` type as well as other forms of session storage. The new methods are: * Cookie::add_private(&mut self, Cookie) * Cookie::remove_private(&mut self, Cookie) * Cookie::get_private(&self, &str) Resolves #20 Testing ------- This commit removes the `rocket::testing` module. It adds the `rocket::local` module which provides a `Client` type for local dispatching of requests against a `Rocket` instance. This `local` package subsumes the previous `testing` package. Rocket Examples --------------- The `forms`, `optional_result`, and `hello_alt_methods` examples have been removed. The following example have been renamed: * extended_validation -> form_validation * hello_ranks -> ranking * from_request -> request_guard * hello_tls -> tls Other Changes ------------- This commit also includes the following smaller changes: * Config::{development, staging, production} constructors have been added for easier creation of default `Config` structures. * The `Config` type is exported from the root. * `Request` implements `Clone` and `Debug`. * `Request::new` is no longer exported. * A `Response::body_bytes` method was added to easily retrieve a response's body as a `Vec<u8>`.
2017-06-06 20:41:04 +00:00
if cookie.expires().is_none() {
cookie.set_expires(time::OffsetDateTime::now_utc() + time::Duration::weeks(1));
}
}
}
Remove Session in favor of private cookies. New testing API. Sessions -------- This commit removes the `Session` type in favor of methods on the `Cookies` types that allow for adding, removing, and getting private (signed and encrypted) cookies. These methods provide a superset of the functionality of `Session` while also being a minimal addition to the existing API. They can be used to implement the previous `Session` type as well as other forms of session storage. The new methods are: * Cookie::add_private(&mut self, Cookie) * Cookie::remove_private(&mut self, Cookie) * Cookie::get_private(&self, &str) Resolves #20 Testing ------- This commit removes the `rocket::testing` module. It adds the `rocket::local` module which provides a `Client` type for local dispatching of requests against a `Rocket` instance. This `local` package subsumes the previous `testing` package. Rocket Examples --------------- The `forms`, `optional_result`, and `hello_alt_methods` examples have been removed. The following example have been renamed: * extended_validation -> form_validation * hello_ranks -> ranking * from_request -> request_guard * hello_tls -> tls Other Changes ------------- This commit also includes the following smaller changes: * Config::{development, staging, production} constructors have been added for easier creation of default `Config` structures. * The `Config` type is exported from the root. * `Request` implements `Clone` and `Debug`. * `Request::new` is no longer exported. * A `Response::body_bytes` method was added to easily retrieve a response's body as a `Vec<u8>`.
2017-06-06 20:41:04 +00:00
impl fmt::Debug for CookieJar<'_> {
2019-06-13 01:33:40 +00:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let pending: Vec<_> = self.ops.lock()
.iter()
.map(|c| c.cookie())
.cloned()
.collect();
f.debug_struct("CookieJar")
.field("original", &self.jar)
.field("pending", &pending)
.finish()
Remove Session in favor of private cookies. New testing API. Sessions -------- This commit removes the `Session` type in favor of methods on the `Cookies` types that allow for adding, removing, and getting private (signed and encrypted) cookies. These methods provide a superset of the functionality of `Session` while also being a minimal addition to the existing API. They can be used to implement the previous `Session` type as well as other forms of session storage. The new methods are: * Cookie::add_private(&mut self, Cookie) * Cookie::remove_private(&mut self, Cookie) * Cookie::get_private(&self, &str) Resolves #20 Testing ------- This commit removes the `rocket::testing` module. It adds the `rocket::local` module which provides a `Client` type for local dispatching of requests against a `Rocket` instance. This `local` package subsumes the previous `testing` package. Rocket Examples --------------- The `forms`, `optional_result`, and `hello_alt_methods` examples have been removed. The following example have been renamed: * extended_validation -> form_validation * hello_ranks -> ranking * from_request -> request_guard * hello_tls -> tls Other Changes ------------- This commit also includes the following smaller changes: * Config::{development, staging, production} constructors have been added for easier creation of default `Config` structures. * The `Config` type is exported from the root. * `Request` implements `Clone` and `Debug`. * `Request::new` is no longer exported. * A `Response::body_bytes` method was added to easily retrieve a response's body as a `Vec<u8>`.
2017-06-06 20:41:04 +00:00
}
}
2019-06-13 01:33:40 +00:00
impl From<Cookie<'_>> for Header<'static> {
fn from(cookie: Cookie<'_>) -> Header<'static> {
Header::new("Set-Cookie", cookie.encoded().to_string())
}
}
2019-06-13 01:33:40 +00:00
impl From<&Cookie<'_>> for Header<'static> {
fn from(cookie: &Cookie<'_>) -> Header<'static> {
Remove Session in favor of private cookies. New testing API. Sessions -------- This commit removes the `Session` type in favor of methods on the `Cookies` types that allow for adding, removing, and getting private (signed and encrypted) cookies. These methods provide a superset of the functionality of `Session` while also being a minimal addition to the existing API. They can be used to implement the previous `Session` type as well as other forms of session storage. The new methods are: * Cookie::add_private(&mut self, Cookie) * Cookie::remove_private(&mut self, Cookie) * Cookie::get_private(&self, &str) Resolves #20 Testing ------- This commit removes the `rocket::testing` module. It adds the `rocket::local` module which provides a `Client` type for local dispatching of requests against a `Rocket` instance. This `local` package subsumes the previous `testing` package. Rocket Examples --------------- The `forms`, `optional_result`, and `hello_alt_methods` examples have been removed. The following example have been renamed: * extended_validation -> form_validation * hello_ranks -> ranking * from_request -> request_guard * hello_tls -> tls Other Changes ------------- This commit also includes the following smaller changes: * Config::{development, staging, production} constructors have been added for easier creation of default `Config` structures. * The `Config` type is exported from the root. * `Request` implements `Clone` and `Debug`. * `Request::new` is no longer exported. * A `Response::body_bytes` method was added to easily retrieve a response's body as a `Vec<u8>`.
2017-06-06 20:41:04 +00:00
Header::new("Set-Cookie", cookie.encoded().to_string())
}
}