Skip to content
Snippets Groups Projects
Commit e43effce authored by codecraft's avatar codecraft :crocodile:
Browse files

Add Display for cookie. Implement Encode trait for T: AsRef<[u8]>

parent 74b8a2fc
No related branches found
No related tags found
1 merge request!1Initial feature merge
use std::time::Duration;
use std::{error::Error, str::FromStr, time::Duration};
use crate::handling::response::CookieBuilder;
/// Structure representing a Cookie
/// # Creating a Cookie:
......@@ -21,16 +23,16 @@ pub struct Cookie {
/// The cookie's path domain, if any.
pub(crate) path: Option<String>,
/// Whether this cookie was marked Secure.
pub(crate) secure: Option<bool>,
pub(crate) secure: bool,
/// Whether this cookie was marked HttpOnly.
pub(crate) http_only: Option<bool>,
pub(crate) http_only: bool,
/// The draft `SameSite` attribute.
pub(crate) same_site: Option<SameSite>,
pub(crate) expires: Option<String>,
pub(crate) partitioned: Option<bool>,
pub(crate) partitioned: bool,
}
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
/// SameSite Paremeters
pub enum SameSite {
/// Requires Secure
......@@ -42,7 +44,7 @@ pub enum SameSite {
impl std::fmt::Display for SameSite {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::None => write!(f, "SameSite=None; Secure"),
Self::None => write!(f, "SameSite=None"),
Self::Lax => write!(f, "SameSite=Lax"),
Self::Strict => write!(f, "SameSite=Strict"),
}
......@@ -51,6 +53,95 @@ impl std::fmt::Display for SameSite {
impl std::fmt::Display for Cookie {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut appendix = String::from("");
if self.secure {
appendix += "; Secure";
}
if self.http_only {
appendix += "; HttpOnly";
}
if self.partitioned {
appendix += "; Partitioned";
}
if let Some(max_age) = &self.max_age {
appendix += &format!("; Max-Age={}", max_age.as_secs());
}
if let Some(domain) = &self.domain {
appendix += &format!("; Domain={}", domain);
}
if let Some(path) = &self.path {
appendix += &format!("; Path={}", path);
}
if let Some(same_site) = &self.same_site {
appendix += &format!("; {}", same_site);
if !self.secure && *same_site == SameSite::None {
appendix += &format!("; Secure");
}
}
if let Some(expires) = &self.expires {
appendix += &format!("; Expires={}", expires)
}
write!(f, "Set-Cookie: {}={}{}", self.name, self.value, appendix)
}
}
impl Error for ParseCookieError {}
#[derive(Debug)]
pub struct ParseCookieError {
inner: CookieError,
}
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
pub enum CookieError {
MissingEqual,
}
impl std::fmt::Display for ParseCookieError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ParseCookieError {{ error: {:?} }}", self.inner)
}
}
impl FromStr for Cookie {
type Err = ParseCookieError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
todo!()
}
}
#[cfg(test)]
mod test {
use std::time::Duration;
use crate::handling::response::CookieBuilder;
use super::SameSite;
#[test]
fn test_cookie_to_string() {
let test_cookie1 = CookieBuilder::build("a", "cookie").finish().to_string();
let test_cookie1_res = "Set-Cookie: a=cookie";
let test_cookie2 = CookieBuilder::build("a", "secure_cookie")
.secure(true)
.finish()
.to_string();
let test_cookie2_res = "Set-Cookie: a=secure_cookie; Secure";
let test_cookie3 = CookieBuilder::build("ab", "ss")
.max_age(Duration::from_secs(24))
.domain("codecraft.com")
.path("/")
.same_site(SameSite::None)
.http_only(true)
.partitioned(true)
.expires("Monday")
.finish()
.to_string();
let test_cookie3_res = "Set-Cookie: ab=ss; HttpOnly; Partitioned; \
Max-Age=24; Domain=codecraft.com; Path=/; SameSite=None; Secure; Expires=Monday";
assert_eq!(test_cookie1_res, test_cookie1);
assert_eq!(test_cookie2_res, test_cookie2);
assert_eq!(test_cookie3_res, test_cookie3);
}
}
use std::time::Duration;
use crate::utils::urlencoded::EnCodable;
use super::{Cookie, SameSite};
/// Builder wrapper for a Cookie
......@@ -22,16 +24,16 @@ impl CookieBuilder {
CookieBuilder {
inner: Cookie {
cookie_string: None,
name: name.to_owned(),
value: value.to_owned(),
name: name.encode(),
value: value.encode(),
max_age: None,
domain: None,
path: None,
secure: None,
http_only: None,
secure: false,
http_only: false,
same_site: None,
expires: None,
partitioned: None,
partitioned: false,
},
}
}
......@@ -43,19 +45,19 @@ impl CookieBuilder {
self
}
pub fn domain(mut self, domain: &str) -> Self {
self.inner.domain = Some(domain.to_owned());
self.inner.domain = Some(domain.encode());
self
}
pub fn path(mut self, path: &str) -> Self {
self.inner.path = Some(path.to_owned());
self.inner.path = Some(path.encode());
self
}
pub fn secure(mut self, secure: bool) -> Self {
self.inner.secure = Some(secure);
self.inner.secure = secure;
self
}
pub fn http_only(mut self, http_only: bool) -> Self {
self.inner.http_only = Some(http_only);
self.inner.http_only = http_only;
self
}
pub fn same_site(mut self, same_site: SameSite) -> Self {
......@@ -63,19 +65,19 @@ impl CookieBuilder {
self
}
pub fn expires(mut self, expire: &str) -> Self {
self.inner.expires = Some(expire.to_owned());
self.inner.expires = Some(expire.encode());
self
}
pub fn partitioned(mut self, partitioned: bool) -> Self {
self.inner.partitioned = Some(partitioned);
self.inner.partitioned = partitioned;
self
}
pub fn name(mut self, name: &str) -> Self {
self.inner.name = name.to_owned();
self.inner.name = name.encode();
self
}
pub fn value(mut self, value: &str) -> Self {
self.inner.value = value.to_owned();
self.inner.value = value.encode();
self
}
}
......@@ -18,6 +18,12 @@ pub trait DeCodable {
fn decode(&self) -> Result<Vec<u8>, ()>;
}
impl<T: AsRef<[u8]>> EnCodable for T {
fn encode(&self) -> String {
self.as_ref().encode()
}
}
impl EnCodable for [u8] {
fn encode(self: &[u8]) -> String {
let mut result = String::with_capacity(self.len());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment