Skip to content

Commit

Permalink
Basic cookie extractor (#114)
Browse files Browse the repository at this point in the history
* Basic cookie extractor

* Update futures-preview and pin-utils

* Clean up as discussed in the PR

* minimal docs added

* change as per new extract trait

* fix cookie extractor example
  • Loading branch information
mmrath authored and yoshuawuyts committed Jan 24, 2019
1 parent bf1e3d8 commit fd57592
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ dist/
npm-debug.log*
Cargo.lock
.DS_Store
.idea
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
18 changes: 18 additions & 0 deletions examples/cookie_extractor.rs
Original file line number Diff line number Diff line change
@@ -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();
}
55 changes: 55 additions & 0 deletions src/cookies.rs
Original file line number Diff line number Diff line change
@@ -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<S: 'static> Extract<S> for Cookies {
type Fut = future::Ready<Result<Self, Response>>;

fn extract(
data: &mut S,
req: &mut Request,
params: &Option<RouteMatch<'_>>,
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<CookieJar, ParseError> {
let mut jar = CookieJar::new();

s.split(';').try_for_each(|s| -> Result<_, ParseError> {
jar.add(Cookie::parse(s.trim().to_owned())?);

Ok(())
})?;

Ok(jar)
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
mod app;
pub mod body;
pub mod configuration;
mod cookies;
mod endpoint;
mod extract;
pub mod head;
Expand All @@ -25,6 +26,7 @@ mod router;
pub use crate::{
app::{App, AppData},
configuration::ExtractConfiguration,
cookies::Cookies,
endpoint::Endpoint,
extract::Extract,
middleware::Middleware,
Expand Down

0 comments on commit fd57592

Please sign in to comment.