diff --git a/Cargo.toml b/Cargo.toml index 1af2836f..6c6face7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ members = [ "actix-cors", "actix-files", "actix-framed", - #"actix-session", + "actix-session", "actix-identity", #"actix-multipart", "actix-web-actors", diff --git a/actix-session/Cargo.toml b/actix-session/Cargo.toml index d2fd5ae5..3ce2a8b4 100644 --- a/actix-session/Cargo.toml +++ b/actix-session/Cargo.toml @@ -24,15 +24,15 @@ default = ["cookie-session"] cookie-session = ["actix-web/secure-cookies"] [dependencies] -actix-web = "1.0.9" -actix-service = "0.4.2" +actix-web = "2.0.0-alpha.1" +actix-service = "1.0.0-alpha.1" bytes = "0.4" derive_more = "0.15.0" -futures = "0.1.24" +futures = "0.3.1" hashbrown = "0.6.3" serde = "1.0" serde_json = "1.0" time = "0.1.42" [dev-dependencies] -actix-rt = "0.2.2" +actix-rt = "1.0.0-alpha.1" diff --git a/actix-session/src/cookie.rs b/actix-session/src/cookie.rs index 19273778..9a486cce 100644 --- a/actix-session/src/cookie.rs +++ b/actix-session/src/cookie.rs @@ -17,6 +17,7 @@ use std::collections::HashMap; use std::rc::Rc; +use std::task::{Context, Poll}; use actix_service::{Service, Transform}; use actix_web::cookie::{Cookie, CookieJar, Key, SameSite}; @@ -24,8 +25,7 @@ use actix_web::dev::{ServiceRequest, ServiceResponse}; use actix_web::http::{header::SET_COOKIE, HeaderValue}; use actix_web::{Error, HttpMessage, ResponseError}; use derive_more::{Display, From}; -use futures::future::{ok, Future, FutureResult}; -use futures::Poll; +use futures::future::{ok, FutureExt, LocalBoxFuture, Ready}; use serde_json::error::Error as JsonError; use crate::{Session, SessionStatus}; @@ -284,7 +284,7 @@ where type Error = S::Error; type InitError = (); type Transform = CookieSessionMiddleware; - type Future = FutureResult; + type Future = Ready>; fn new_transform(&self, service: S) -> Self::Future { ok(CookieSessionMiddleware { @@ -309,10 +309,10 @@ where type Request = ServiceRequest; type Response = ServiceResponse; type Error = S::Error; - type Future = Box>; + type Future = LocalBoxFuture<'static, Result>; - fn poll_ready(&mut self) -> Poll<(), Self::Error> { - self.service.poll_ready() + fn poll_ready(&mut self, cx: &mut Context) -> Poll> { + self.service.poll_ready(cx) } /// On first request, a new session cookie is returned in response, regardless @@ -325,29 +325,36 @@ where let (is_new, state) = self.inner.load(&req); Session::set_session(state.into_iter(), &mut req); - Box::new(self.service.call(req).map(move |mut res| { - match Session::get_changes(&mut res) { - (SessionStatus::Changed, Some(state)) - | (SessionStatus::Renewed, Some(state)) => { - res.checked_expr(|res| inner.set_cookie(res, state)) - } - (SessionStatus::Unchanged, _) => - // set a new session cookie upon first request (new client) - { - if is_new { - let state: HashMap = HashMap::new(); - res.checked_expr(|res| inner.set_cookie(res, state.into_iter())) - } else { + let fut = self.service.call(req); + + async move { + fut.await.map(|mut res| { + match Session::get_changes(&mut res) { + (SessionStatus::Changed, Some(state)) + | (SessionStatus::Renewed, Some(state)) => { + res.checked_expr(|res| inner.set_cookie(res, state)) + } + (SessionStatus::Unchanged, _) => + // set a new session cookie upon first request (new client) + { + if is_new { + let state: HashMap = HashMap::new(); + res.checked_expr(|res| { + inner.set_cookie(res, state.into_iter()) + }) + } else { + res + } + } + (SessionStatus::Purged, _) => { + let _ = inner.remove_cookie(&mut res); res } + _ => res, } - (SessionStatus::Purged, _) => { - let _ = inner.remove_cookie(&mut res); - res - } - _ => res, - } - })) + }) + } + .boxed_local() } } @@ -359,101 +366,113 @@ mod tests { #[test] fn cookie_session() { - let mut app = test::init_service( - App::new() - .wrap(CookieSession::signed(&[0; 32]).secure(false)) - .service(web::resource("/").to(|ses: Session| { - let _ = ses.set("counter", 100); - "test" - })), - ); + test::block_on(async { + let mut app = test::init_service( + App::new() + .wrap(CookieSession::signed(&[0; 32]).secure(false)) + .service(web::resource("/").to(|ses: Session| { + let _ = ses.set("counter", 100); + "test" + })), + ) + .await; - let request = test::TestRequest::get().to_request(); - let response = test::block_on(app.call(request)).unwrap(); - assert!(response - .response() - .cookies() - .find(|c| c.name() == "actix-session") - .is_some()); + let request = test::TestRequest::get().to_request(); + let response = app.call(request).await.unwrap(); + assert!(response + .response() + .cookies() + .find(|c| c.name() == "actix-session") + .is_some()); + }) } #[test] fn private_cookie() { - let mut app = test::init_service( - App::new() - .wrap(CookieSession::private(&[0; 32]).secure(false)) - .service(web::resource("/").to(|ses: Session| { - let _ = ses.set("counter", 100); - "test" - })), - ); + test::block_on(async { + let mut app = test::init_service( + App::new() + .wrap(CookieSession::private(&[0; 32]).secure(false)) + .service(web::resource("/").to(|ses: Session| { + let _ = ses.set("counter", 100); + "test" + })), + ) + .await; - let request = test::TestRequest::get().to_request(); - let response = test::block_on(app.call(request)).unwrap(); - assert!(response - .response() - .cookies() - .find(|c| c.name() == "actix-session") - .is_some()); + let request = test::TestRequest::get().to_request(); + let response = app.call(request).await.unwrap(); + assert!(response + .response() + .cookies() + .find(|c| c.name() == "actix-session") + .is_some()); + }) } #[test] fn cookie_session_extractor() { - let mut app = test::init_service( - App::new() - .wrap(CookieSession::signed(&[0; 32]).secure(false)) - .service(web::resource("/").to(|ses: Session| { - let _ = ses.set("counter", 100); - "test" - })), - ); + test::block_on(async { + let mut app = test::init_service( + App::new() + .wrap(CookieSession::signed(&[0; 32]).secure(false)) + .service(web::resource("/").to(|ses: Session| { + let _ = ses.set("counter", 100); + "test" + })), + ) + .await; - let request = test::TestRequest::get().to_request(); - let response = test::block_on(app.call(request)).unwrap(); - assert!(response - .response() - .cookies() - .find(|c| c.name() == "actix-session") - .is_some()); + let request = test::TestRequest::get().to_request(); + let response = app.call(request).await.unwrap(); + assert!(response + .response() + .cookies() + .find(|c| c.name() == "actix-session") + .is_some()); + }) } #[test] fn basics() { - let mut app = test::init_service( - App::new() - .wrap( - CookieSession::signed(&[0; 32]) - .path("/test/") - .name("actix-test") - .domain("localhost") - .http_only(true) - .same_site(SameSite::Lax) - .max_age(100), - ) - .service(web::resource("/").to(|ses: Session| { - let _ = ses.set("counter", 100); - "test" - })) - .service(web::resource("/test/").to(|ses: Session| { - let val: usize = ses.get("counter").unwrap().unwrap(); - format!("counter: {}", val) - })), - ); + test::block_on(async { + let mut app = test::init_service( + App::new() + .wrap( + CookieSession::signed(&[0; 32]) + .path("/test/") + .name("actix-test") + .domain("localhost") + .http_only(true) + .same_site(SameSite::Lax) + .max_age(100), + ) + .service(web::resource("/").to(|ses: Session| { + let _ = ses.set("counter", 100); + "test" + })) + .service(web::resource("/test/").to(|ses: Session| { + let val: usize = ses.get("counter").unwrap().unwrap(); + format!("counter: {}", val) + })), + ) + .await; - let request = test::TestRequest::get().to_request(); - let response = test::block_on(app.call(request)).unwrap(); - let cookie = response - .response() - .cookies() - .find(|c| c.name() == "actix-test") - .unwrap() - .clone(); - assert_eq!(cookie.path().unwrap(), "/test/"); + let request = test::TestRequest::get().to_request(); + let response = app.call(request).await.unwrap(); + let cookie = response + .response() + .cookies() + .find(|c| c.name() == "actix-test") + .unwrap() + .clone(); + assert_eq!(cookie.path().unwrap(), "/test/"); - let request = test::TestRequest::with_uri("/test/") - .cookie(cookie) - .to_request(); - let body = test::read_response(&mut app, request); - assert_eq!(body, Bytes::from_static(b"counter: 100")); + let request = test::TestRequest::with_uri("/test/") + .cookie(cookie) + .to_request(); + let body = test::read_response(&mut app, request).await; + assert_eq!(body, Bytes::from_static(b"counter: 100")); + }) } } diff --git a/actix-session/src/lib.rs b/actix-session/src/lib.rs index 2e9e5171..def35a1e 100644 --- a/actix-session/src/lib.rs +++ b/actix-session/src/lib.rs @@ -47,6 +47,7 @@ use std::rc::Rc; use actix_web::dev::{Extensions, Payload, ServiceRequest, ServiceResponse}; use actix_web::{Error, FromRequest, HttpMessage, HttpRequest}; +use futures::future::{ok, Ready}; use hashbrown::HashMap; use serde::de::DeserializeOwned; use serde::Serialize; @@ -230,12 +231,12 @@ impl Session { /// ``` impl FromRequest for Session { type Error = Error; - type Future = Result; + type Future = Ready>; type Config = (); #[inline] fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { - Ok(Session::get_session(&mut *req.extensions_mut())) + ok(Session::get_session(&mut *req.extensions_mut())) } }