1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-30 10:42:55 +01:00

migrate actix-session

This commit is contained in:
Nikolay Kim 2019-11-21 13:08:22 +06:00
parent 0de101bc4d
commit 60ada97b3d
4 changed files with 132 additions and 112 deletions

View File

@ -34,7 +34,7 @@ members = [
"actix-cors", "actix-cors",
"actix-files", "actix-files",
"actix-framed", "actix-framed",
#"actix-session", "actix-session",
"actix-identity", "actix-identity",
#"actix-multipart", #"actix-multipart",
"actix-web-actors", "actix-web-actors",

View File

@ -24,15 +24,15 @@ default = ["cookie-session"]
cookie-session = ["actix-web/secure-cookies"] cookie-session = ["actix-web/secure-cookies"]
[dependencies] [dependencies]
actix-web = "1.0.9" actix-web = "2.0.0-alpha.1"
actix-service = "0.4.2" actix-service = "1.0.0-alpha.1"
bytes = "0.4" bytes = "0.4"
derive_more = "0.15.0" derive_more = "0.15.0"
futures = "0.1.24" futures = "0.3.1"
hashbrown = "0.6.3" hashbrown = "0.6.3"
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
time = "0.1.42" time = "0.1.42"
[dev-dependencies] [dev-dependencies]
actix-rt = "0.2.2" actix-rt = "1.0.0-alpha.1"

View File

@ -17,6 +17,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::task::{Context, Poll};
use actix_service::{Service, Transform}; use actix_service::{Service, Transform};
use actix_web::cookie::{Cookie, CookieJar, Key, SameSite}; 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::http::{header::SET_COOKIE, HeaderValue};
use actix_web::{Error, HttpMessage, ResponseError}; use actix_web::{Error, HttpMessage, ResponseError};
use derive_more::{Display, From}; use derive_more::{Display, From};
use futures::future::{ok, Future, FutureResult}; use futures::future::{ok, FutureExt, LocalBoxFuture, Ready};
use futures::Poll;
use serde_json::error::Error as JsonError; use serde_json::error::Error as JsonError;
use crate::{Session, SessionStatus}; use crate::{Session, SessionStatus};
@ -284,7 +284,7 @@ where
type Error = S::Error; type Error = S::Error;
type InitError = (); type InitError = ();
type Transform = CookieSessionMiddleware<S>; type Transform = CookieSessionMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>; type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future { fn new_transform(&self, service: S) -> Self::Future {
ok(CookieSessionMiddleware { ok(CookieSessionMiddleware {
@ -309,10 +309,10 @@ where
type Request = ServiceRequest; type Request = ServiceRequest;
type Response = ServiceResponse<B>; type Response = ServiceResponse<B>;
type Error = S::Error; type Error = S::Error;
type Future = Box<dyn Future<Item = Self::Response, Error = Self::Error>>; type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready() self.service.poll_ready(cx)
} }
/// On first request, a new session cookie is returned in response, regardless /// 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); let (is_new, state) = self.inner.load(&req);
Session::set_session(state.into_iter(), &mut req); Session::set_session(state.into_iter(), &mut req);
Box::new(self.service.call(req).map(move |mut res| { let fut = self.service.call(req);
match Session::get_changes(&mut res) {
(SessionStatus::Changed, Some(state)) async move {
| (SessionStatus::Renewed, Some(state)) => { fut.await.map(|mut res| {
res.checked_expr(|res| inner.set_cookie(res, state)) match Session::get_changes(&mut res) {
} (SessionStatus::Changed, Some(state))
(SessionStatus::Unchanged, _) => | (SessionStatus::Renewed, Some(state)) => {
// set a new session cookie upon first request (new client) res.checked_expr(|res| inner.set_cookie(res, state))
{ }
if is_new { (SessionStatus::Unchanged, _) =>
let state: HashMap<String, String> = HashMap::new(); // set a new session cookie upon first request (new client)
res.checked_expr(|res| inner.set_cookie(res, state.into_iter())) {
} else { if is_new {
let state: HashMap<String, String> = 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
} }
_ => res,
} }
(SessionStatus::Purged, _) => { })
let _ = inner.remove_cookie(&mut res); }
res .boxed_local()
}
_ => res,
}
}))
} }
} }
@ -359,101 +366,113 @@ mod tests {
#[test] #[test]
fn cookie_session() { fn cookie_session() {
let mut app = test::init_service( test::block_on(async {
App::new() let mut app = test::init_service(
.wrap(CookieSession::signed(&[0; 32]).secure(false)) App::new()
.service(web::resource("/").to(|ses: Session| { .wrap(CookieSession::signed(&[0; 32]).secure(false))
let _ = ses.set("counter", 100); .service(web::resource("/").to(|ses: Session| {
"test" let _ = ses.set("counter", 100);
})), "test"
); })),
)
.await;
let request = test::TestRequest::get().to_request(); let request = test::TestRequest::get().to_request();
let response = test::block_on(app.call(request)).unwrap(); let response = app.call(request).await.unwrap();
assert!(response assert!(response
.response() .response()
.cookies() .cookies()
.find(|c| c.name() == "actix-session") .find(|c| c.name() == "actix-session")
.is_some()); .is_some());
})
} }
#[test] #[test]
fn private_cookie() { fn private_cookie() {
let mut app = test::init_service( test::block_on(async {
App::new() let mut app = test::init_service(
.wrap(CookieSession::private(&[0; 32]).secure(false)) App::new()
.service(web::resource("/").to(|ses: Session| { .wrap(CookieSession::private(&[0; 32]).secure(false))
let _ = ses.set("counter", 100); .service(web::resource("/").to(|ses: Session| {
"test" let _ = ses.set("counter", 100);
})), "test"
); })),
)
.await;
let request = test::TestRequest::get().to_request(); let request = test::TestRequest::get().to_request();
let response = test::block_on(app.call(request)).unwrap(); let response = app.call(request).await.unwrap();
assert!(response assert!(response
.response() .response()
.cookies() .cookies()
.find(|c| c.name() == "actix-session") .find(|c| c.name() == "actix-session")
.is_some()); .is_some());
})
} }
#[test] #[test]
fn cookie_session_extractor() { fn cookie_session_extractor() {
let mut app = test::init_service( test::block_on(async {
App::new() let mut app = test::init_service(
.wrap(CookieSession::signed(&[0; 32]).secure(false)) App::new()
.service(web::resource("/").to(|ses: Session| { .wrap(CookieSession::signed(&[0; 32]).secure(false))
let _ = ses.set("counter", 100); .service(web::resource("/").to(|ses: Session| {
"test" let _ = ses.set("counter", 100);
})), "test"
); })),
)
.await;
let request = test::TestRequest::get().to_request(); let request = test::TestRequest::get().to_request();
let response = test::block_on(app.call(request)).unwrap(); let response = app.call(request).await.unwrap();
assert!(response assert!(response
.response() .response()
.cookies() .cookies()
.find(|c| c.name() == "actix-session") .find(|c| c.name() == "actix-session")
.is_some()); .is_some());
})
} }
#[test] #[test]
fn basics() { fn basics() {
let mut app = test::init_service( test::block_on(async {
App::new() let mut app = test::init_service(
.wrap( App::new()
CookieSession::signed(&[0; 32]) .wrap(
.path("/test/") CookieSession::signed(&[0; 32])
.name("actix-test") .path("/test/")
.domain("localhost") .name("actix-test")
.http_only(true) .domain("localhost")
.same_site(SameSite::Lax) .http_only(true)
.max_age(100), .same_site(SameSite::Lax)
) .max_age(100),
.service(web::resource("/").to(|ses: Session| { )
let _ = ses.set("counter", 100); .service(web::resource("/").to(|ses: Session| {
"test" let _ = ses.set("counter", 100);
})) "test"
.service(web::resource("/test/").to(|ses: Session| { }))
let val: usize = ses.get("counter").unwrap().unwrap(); .service(web::resource("/test/").to(|ses: Session| {
format!("counter: {}", val) let val: usize = ses.get("counter").unwrap().unwrap();
})), format!("counter: {}", val)
); })),
)
.await;
let request = test::TestRequest::get().to_request(); let request = test::TestRequest::get().to_request();
let response = test::block_on(app.call(request)).unwrap(); let response = app.call(request).await.unwrap();
let cookie = response let cookie = response
.response() .response()
.cookies() .cookies()
.find(|c| c.name() == "actix-test") .find(|c| c.name() == "actix-test")
.unwrap() .unwrap()
.clone(); .clone();
assert_eq!(cookie.path().unwrap(), "/test/"); assert_eq!(cookie.path().unwrap(), "/test/");
let request = test::TestRequest::with_uri("/test/") let request = test::TestRequest::with_uri("/test/")
.cookie(cookie) .cookie(cookie)
.to_request(); .to_request();
let body = test::read_response(&mut app, request); let body = test::read_response(&mut app, request).await;
assert_eq!(body, Bytes::from_static(b"counter: 100")); assert_eq!(body, Bytes::from_static(b"counter: 100"));
})
} }
} }

View File

@ -47,6 +47,7 @@ use std::rc::Rc;
use actix_web::dev::{Extensions, Payload, ServiceRequest, ServiceResponse}; use actix_web::dev::{Extensions, Payload, ServiceRequest, ServiceResponse};
use actix_web::{Error, FromRequest, HttpMessage, HttpRequest}; use actix_web::{Error, FromRequest, HttpMessage, HttpRequest};
use futures::future::{ok, Ready};
use hashbrown::HashMap; use hashbrown::HashMap;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::Serialize; use serde::Serialize;
@ -230,12 +231,12 @@ impl Session {
/// ``` /// ```
impl FromRequest for Session { impl FromRequest for Session {
type Error = Error; type Error = Error;
type Future = Result<Session, Error>; type Future = Ready<Result<Session, Error>>;
type Config = (); type Config = ();
#[inline] #[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { 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()))
} }
} }