aboutsummaryrefslogtreecommitdiff
path: root/src/response.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/response.rs')
-rw-r--r--src/response.rs82
1 files changed, 71 insertions, 11 deletions
diff --git a/src/response.rs b/src/response.rs
index cb87a80..c9d83a7 100644
--- a/src/response.rs
+++ b/src/response.rs
@@ -1,9 +1,6 @@
//! Provides convenience traits and functions to build HTTP responses.
-use std::convert::TryInto;
-
-use cookie::Cookie;
-use time::{Duration, OffsetDateTime};
+use std::{convert::TryInto, fmt::Display, time::{Duration, SystemTime}};
use crate::http::{self, HeaderMap, StatusCode, header, response::Builder};
@@ -16,6 +13,67 @@ pub trait SputnikBuilder {
fn set_cookie(self, cookie: Cookie) -> Builder;
}
+#[derive(Default, Debug)]
+pub struct Cookie {
+ pub name: String,
+ pub value: String,
+ pub expires: Option<SystemTime>,
+ pub max_age: Option<Duration>,
+ pub domain: Option<String>,
+ pub path: Option<String>,
+ pub secure: Option<bool>,
+ pub http_only: Option<bool>,
+ pub same_site: Option<SameSite>,
+}
+
+impl Display for Cookie {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}={}", self.name, self.value)?;
+ if let Some(true) = self.http_only {
+ write!(f, "; HttpOnly")?;
+ }
+ if let Some(same_site) = &self.same_site {
+ write!(f, "; SameSite={}", same_site)?;
+
+ if same_site == &SameSite::None && self.secure.is_none() {
+ write!(f, "; Secure")?;
+ }
+ }
+ if let Some(true) = self.secure {
+ write!(f, "; Secure")?;
+ }
+ if let Some(path) = &self.path {
+ write!(f, "; Path={}", path)?;
+ }
+ if let Some(domain) = &self.domain {
+ write!(f, "; Domain={}", domain)?;
+ }
+ if let Some(max_age) = &self.max_age {
+ write!(f, "; Max-Age={}", max_age.as_secs())?;
+ }
+ if let Some(time) = self.expires {
+ write!(f, "; Expires={}", httpdate::fmt_http_date(time))?;
+ }
+
+ Ok(())
+ }
+}
+
+#[derive(Debug, PartialEq)]
+pub enum SameSite {
+ Strict, Lax, None
+}
+
+impl Display for SameSite {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ SameSite::Strict => write!(f, "Strict"),
+ SameSite::Lax => write!(f, "Lax"),
+ SameSite::None => write!(f, "None"),
+ }
+ }
+}
+
/// Creates a new builder with a given Location header and status code.
pub fn redirect(location: &str, code: StatusCode) -> Builder {
Builder::new().status(code).header(header::LOCATION, location)
@@ -35,10 +93,12 @@ impl SputnikBuilder for Builder {
/// Constructs an expired cookie to delete a cookie.
pub fn delete_cookie(name: &str) -> Cookie {
- let mut cookie = Cookie::new(name, "");
- cookie.set_max_age(Duration::seconds(0));
- cookie.set_expires(OffsetDateTime::now_utc() - Duration::days(365));
- cookie
+ Cookie{
+ name: name.into(),
+ max_age: Some(Duration::from_secs(0)),
+ expires: Some(SystemTime::now() - Duration::from_secs(60*60*24)),
+ ..Default::default()
+ }
}
/// Adds convenience methods to [`HeaderMap`].
@@ -56,7 +116,7 @@ impl SputnikHeaders for HeaderMap {
}
fn set_cookie(&mut self, cookie: Cookie) {
- self.append(header::SET_COOKIE, cookie.encoded().to_string().try_into().unwrap());
+ self.append(header::SET_COOKIE, cookie.to_string().try_into().unwrap());
}
}
@@ -73,8 +133,8 @@ mod tests {
#[test]
fn test_set_cookie() {
let mut map = HeaderMap::new();
- map.set_cookie(Cookie::new("some", "cookie"));
- map.set_cookie(Cookie::new("some", "cookie"));
+ map.set_cookie(Cookie{name: "some".into(), value: "cookie".into(), ..Default::default()});
+ map.set_cookie(Cookie{name: "some".into(), value: "cookie".into(), ..Default::default()});
assert_eq!(map.len(), 2);
}