diff --git a/.gitignore b/.gitignore index ac0d3c74e..00541512b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ dist/ npm-debug.log* Cargo.lock .DS_Store +.idea \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 8b7043af7..5b6d91e33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ serde_qs = "0.4.1" slog = "2.4.1" slog-term = "2.4.0" slog-async = "2.3.0" +cookie="0.11" path-table = "1.0.0" [dependencies.multipart] diff --git a/examples/cookie_extractor.rs b/examples/cookie_extractor.rs new file mode 100644 index 000000000..f081f72b5 --- /dev/null +++ b/examples/cookie_extractor.rs @@ -0,0 +1,18 @@ +#![feature(async_await, futures_api)] + +use tide::Cookies; + +/// Tide will use the the `Cookies`'s `Extract` implementation to build this parameter. +/// +async fn hello_cookies(cookies: Cookies) -> String { + format!("hello cookies: {:?}", cookies) +} + +fn main() { + let mut app = tide::App::new(()); + app.at("/").get(hello_cookies); + + let address = "127.0.0.1:8000".to_owned(); + println!("Server is listening on http://{}", address); + app.serve(); +} diff --git a/src/cookies.rs b/src/cookies.rs new file mode 100644 index 000000000..7d3cca79c --- /dev/null +++ b/src/cookies.rs @@ -0,0 +1,55 @@ +use cookie::{Cookie, CookieJar, ParseError}; +use futures::future; + +use crate::{configuration::Store, response::IntoResponse, Extract, Request, Response, RouteMatch}; + +/// A representation of cookies which wraps `CookieJar` from `cookie` crate +/// +/// Currently this only exposes getting cookie by name but future enhancements might allow more +/// operation. `Cookies` implements`Extract` so that handler methods can have a `Cookies` parameter. +/// +#[derive(Clone, Debug)] +pub struct Cookies { + content: CookieJar, +} + +impl Cookies { + /// returns a `Cookie` by name of the cookie + #[inline] + pub fn get(&self, name: &str) -> Option<&Cookie<'static>> { + self.content.get(name) + } +} + +impl Extract for Cookies { + type Fut = future::Ready>; + + fn extract( + data: &mut S, + req: &mut Request, + params: &Option>, + store: &Store, + ) -> Self::Fut { + let cookie_jar = match req.headers().get("Cookie") { + Some(raw_cookies) => parse_from_header(raw_cookies.to_str().unwrap()), + _ => Ok(CookieJar::new()), + }; + let resp = cookie_jar + .map(|c| Cookies { content: c }) + .map_err(|_e| http::status::StatusCode::BAD_REQUEST.into_response()); + + future::ready(resp) + } +} + +fn parse_from_header(s: &str) -> Result { + let mut jar = CookieJar::new(); + + s.split(';').try_for_each(|s| -> Result<_, ParseError> { + jar.add(Cookie::parse(s.trim().to_owned())?); + + Ok(()) + })?; + + Ok(jar) +} diff --git a/src/lib.rs b/src/lib.rs index 454a75c11..3aa9d997e 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ mod app; pub mod body; pub mod configuration; +mod cookies; mod endpoint; mod extract; pub mod head; @@ -25,6 +26,7 @@ mod router; pub use crate::{ app::{App, AppData}, configuration::ExtractConfiguration, + cookies::Cookies, endpoint::Endpoint, extract::Extract, middleware::Middleware,