#![cfg(feature = "cookies")] use std::convert::TryInto; use std::sync::Arc; use async_trait::async_trait; use mendes::application::IntoResponse; use mendes::cookies::{cookie, AppWithAeadKey, AppWithCookies, Key}; use mendes::http::header::{COOKIE, SET_COOKIE}; use mendes::http::request::Parts; use mendes::http::{Request, Response, StatusCode}; use mendes::{handler, route, Application, Context}; use serde::{Deserialize, Serialize}; #[tokio::test] async fn cookie() { let app = Arc::new(App { key: mendes::cookies::Key::new(&[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ]), }); let rsp = App::handle(Context::new(app.clone(), path_request("/store"))).await; assert_eq!(rsp.status(), StatusCode::OK); let set = rsp.headers().get(SET_COOKIE).unwrap(); let value = set.to_str().unwrap().split(';').next().unwrap(); let mut req = path_request("/extract"); req.headers_mut().insert(COOKIE, value.try_into().unwrap()); let rsp = App::handle(Context::new(app, req)).await; assert_eq!(rsp.status(), StatusCode::OK); assert_eq!(rsp.into_body(), "user = 37"); } fn path_request(path: &str) -> Request<()> { Request::builder() .uri(format!("https://example.com{path}")) .body(()) .unwrap() } struct App { key: mendes::cookies::Key, } impl AppWithAeadKey for App { fn key(&self) -> &Key { &self.key } } #[async_trait] impl Application for App { type RequestBody = (); type ResponseBody = String; type Error = Error; async fn handle(mut cx: Context) -> Response { route!(match cx.path() { Some("store") => store, Some("extract") => extract, }) } } #[handler(GET)] async fn extract(app: &App, req: &http::request::Parts) -> Result, Error> { let session = app.cookie::(&req.headers).unwrap(); Ok(Response::builder() .status(StatusCode::OK) .body(format!("user = {}", session.user)) .unwrap()) } #[handler(GET)] async fn store(app: &App) -> Result, Error> { let session = Session { user: 37 }; Ok(Response::builder() .status(StatusCode::OK) .header(SET_COOKIE, app.set_cookie_header(Some(session)).unwrap()) .body("Hello, world".into()) .unwrap()) } #[cookie] #[derive(Deserialize, Serialize)] struct Session { user: i32, } #[derive(Debug)] enum Error { Mendes(mendes::Error), } impl From for Error { fn from(e: mendes::Error) -> Self { Error::Mendes(e) } } impl From<&Error> for StatusCode { fn from(e: &Error) -> StatusCode { let Error::Mendes(e) = e; StatusCode::from(e) } } impl IntoResponse for Error { fn into_response(self, _: &App, _: &Parts) -> Response { let Error::Mendes(err) = self; Response::builder() .status(StatusCode::from(&err)) .body(err.to_string()) .unwrap() } }