From edf1fcecc5c55657bb4c302696513fec4f9f9c6e Mon Sep 17 00:00:00 2001 From: Wai Pai Lee Date: Fri, 1 May 2020 17:57:59 +0800 Subject: [PATCH] feat: revamp cookies parser flow Revamp the flow to fit current routing handler. Cookie flow and convertion are improved in this commit too. --- Cargo.toml | 4 ++++ examples/cookies.rs | 35 +++++++++++++++++++++++++++++++++ examples/main.rs | 8 ++++---- src/app.rs | 26 ++++++++++++++++++++++-- src/context.rs | 18 ++++++++++++----- src/middleware/cookie_parser.rs | 14 ++++++------- src/router/responder.rs | 8 ++++---- src/router/response.rs | 20 +++++++++++-------- 8 files changed, 102 insertions(+), 31 deletions(-) create mode 100644 examples/cookies.rs diff --git a/Cargo.toml b/Cargo.toml index af23c77..516ed4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,10 @@ path = 'examples/json.rs' name = 'app_state' path = 'examples/app_state.rs' +[[example]] +name = 'cookies' +path = 'examples/cookies.rs' + [package] name = 'obsidian' version = '0.2.2' diff --git a/examples/cookies.rs b/examples/cookies.rs new file mode 100644 index 0000000..4b00f5c --- /dev/null +++ b/examples/cookies.rs @@ -0,0 +1,35 @@ +use obsidian::{context::Context, App}; +use obsidian::middleware::cookie_parser::CookieParser; +use cookie::Cookie; + +#[tokio::main] +async fn main() { + let mut app: App = App::new(); + let addr = ([127, 0, 0, 1], 3000).into(); + + app.get("/", |ctx: Context| async { + if let Some(cookies) = ctx.cookie("cookie_name") { + let cookies2 = ctx.cookie("cookie_name2").expect("cookie_name2 should be set"); + let response = format!("{}={}; {}={};", cookies.name(), cookies.value(), cookies2.name(), cookies2.value()); + + ctx + .build(response) + .ok() + } + else { + ctx + .build("Set cookies!") + .with_cookie(Cookie::new("cookie_name", "cookie_value")) + .with_cookie(Cookie::new("cookie_name2", "cookie_value2")) + .ok() + } + }); + + let cookie_parser = CookieParser::new(); + app.use_service(cookie_parser); + + app.listen(&addr, || { + println!("server is listening to {}", &addr); + }) + .await; +} diff --git a/examples/main.rs b/examples/main.rs index 8ae9160..140bb9e 100644 --- a/examples/main.rs +++ b/examples/main.rs @@ -110,8 +110,8 @@ ctx.build(Response::ok().html(" Option<&Cookie> { if let Some(cookie_data) = self.get::() { - if let Some(ref cookie) = cookie_data.cookie_jar().get(name) { - return Some(*cookie); - } + return cookie_data.cookie_jar().get(name); } None @@ -371,16 +369,26 @@ impl ResponseBuilder { self } - pub fn with_headers(mut self, headers: Vec<(HeaderName, &'static str)>) -> Self { + pub fn with_headers(mut self, headers: &[(HeaderName, &'static str)]) -> Self { self.response = self.response.set_headers(headers); self } - pub fn with_headers_str(mut self, headers: Vec<(&'static str, &'static str)>) -> Self { + pub fn with_headers_str(mut self, headers: &[(&'static str, &'static str)]) -> Self { self.response = self.response.set_headers_str(headers); self } + pub fn with_cookie(mut self, cookie: Cookie<'static>) -> Self { + self.response = self.response.set_cookie(cookie); + self + } + + pub fn with_cookies(mut self, cookies: &[Cookie<'static>]) -> Self { + self.response = self.response.set_cookies(cookies); + self + } + pub fn ok(mut self) -> ContextResult { *self.ctx.response_mut() = Some(self.response); Ok(self.ctx) diff --git a/src/middleware/cookie_parser.rs b/src/middleware/cookie_parser.rs index 575d449..77560d9 100644 --- a/src/middleware/cookie_parser.rs +++ b/src/middleware/cookie_parser.rs @@ -5,7 +5,7 @@ use hyper::header; use crate::app::EndpointExecutor; use crate::context::Context; use crate::middleware::Middleware; -use crate::{Body, Response}; +use crate::router::ContextResult; #[derive(Default)] pub struct CookieParserData { @@ -43,19 +43,17 @@ impl Middleware for CookieParser { &'a self, mut context: Context, ep_executor: EndpointExecutor<'a>, - ) -> Response { + ) -> ContextResult { if let Some(cookie_header) = context.headers().get(header::COOKIE) { if let Ok(cookie_str) = cookie_header.to_str() { let mut cookie_data = CookieParserData::new(); cookie_str .split("; ") - .map(|x| x.trim().splitn(2, '=').collect::>()) - .for_each(|x| { - if let (2, Some(k), Some(v)) = (x.len(), x.first(), x.last()) { - cookie_data - .cookie_jar_mut() - .add_original(Cookie::new((*k).to_string(), (*v).to_string())); + .map(|cookie_str_part| Cookie::parse(cookie_str_part.to_owned())) + .for_each(|cookie_result| { + if let Ok(cookie) = cookie_result { + cookie_data.cookie_jar_mut().add_original(cookie); } }); diff --git a/src/router/responder.rs b/src/router/responder.rs index d0690cb..05ab0bb 100644 --- a/src/router/responder.rs +++ b/src/router/responder.rs @@ -1,7 +1,7 @@ use super::Response; use super::ResponseBody; -use hyper::{header, StatusCode}; use cookie::Cookie; +use hyper::{header, StatusCode}; pub trait Responder { fn respond_to(self) -> Response; @@ -19,14 +19,14 @@ pub trait Responder { Response::new(self).set_header(key, value) } - fn with_headers(self, headers: Vec<(header::HeaderName, &'static str)>) -> Response + fn with_headers(self, headers: &[(header::HeaderName, &'static str)]) -> Response where Self: Responder + ResponseBody + Sized, { Response::new(self).set_headers(headers) } - fn with_headers_str(self, headers: Vec<(&'static str, &'static str)>) -> Response + fn with_headers_str(self, headers: &[(&'static str, &'static str)]) -> Response where Self: Responder + ResponseBody + Sized, { @@ -40,7 +40,7 @@ pub trait Responder { Response::new(self).set_cookie(cookie) } - fn with_cookies(self, cookies: Vec>) -> Response + fn with_cookies(self, cookies: &[Cookie<'static>]) -> Response where Self: Responder + ResponseBody + Sized, { diff --git a/src/router/response.rs b/src/router/response.rs index 67ce0c3..0afdd1d 100644 --- a/src/router/response.rs +++ b/src/router/response.rs @@ -44,6 +44,10 @@ impl Response { &self.cookies } + pub fn cookies_mut(&mut self) -> &mut Option>> { + &mut self.cookies + } + pub fn headers_mut(&mut self) -> &mut Option> { &mut self.headers } @@ -95,7 +99,7 @@ impl Response { self.set_cookie(cookie) } - pub fn with_cookies(self, cookies: Vec>) -> Self { + pub fn with_cookies(self, cookies: &[Cookie<'static>]) -> Self { self.set_cookies(cookies) } @@ -111,15 +115,15 @@ impl Response { self } - pub fn set_cookies(mut self, mut cookies: Vec>) -> Self { + pub fn set_cookies(mut self, mut cookies: &[Cookie<'static>]) -> Self { match self.cookies { - Some(ref mut x) => x.append(&mut cookies), - None => self.cookies = Some(cookies), + Some(ref mut x) => x.extend_from_slice(&mut cookies), + None => self.cookies = Some(cookies.to_vec()), } self } - pub fn set_headers(mut self, headers: Vec<(header::HeaderName, &str)>) -> Self { + pub fn set_headers(mut self, headers: &[(header::HeaderName, &str)]) -> Self { let headers: Vec<(header::HeaderName, String)> = headers .iter() .map(|(k, v)| (header::HeaderName::from(k), (*v).to_string())) @@ -133,11 +137,11 @@ impl Response { } // Alias set_headers method - pub fn with_headers(self, headers: Vec<(header::HeaderName, &'static str)>) -> Self { + pub fn with_headers(self, headers: &[(header::HeaderName, &'static str)]) -> Self { self.set_headers(headers) } - pub fn set_headers_str(mut self, headers: Vec<(&'static str, &'static str)>) -> Self { + pub fn set_headers_str(mut self, headers: &[(&'static str, &'static str)]) -> Self { let values: Vec<(header::HeaderName, String)> = headers .iter() .map(|(k, v)| { @@ -156,7 +160,7 @@ impl Response { } // Alias set_headers_str method - pub fn with_headers_str(self, headers: Vec<(&'static str, &'static str)>) -> Self { + pub fn with_headers_str(self, headers: &[(&'static str, &'static str)]) -> Self { self.set_headers_str(headers) }