mirror of
https://github.com/ntex-rs/ntex-extras.git
synced 2025-04-03 21:07:40 +03:00
Update to ntex 1.0
This commit is contained in:
parent
1270f0c8a6
commit
14c6930954
11 changed files with 140 additions and 177 deletions
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ntex-cors"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0-b.0"
|
||||
authors = ["ntex contributors <team@ntex.rs>"]
|
||||
description = "Cross-origin resource sharing (CORS) for ntex applications."
|
||||
readme = "README.md"
|
||||
|
@ -16,9 +16,9 @@ name = "ntex_cors"
|
|||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
ntex = "0.7.0"
|
||||
ntex = "1.0.0-b.1"
|
||||
derive_more = "0.99"
|
||||
futures = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
ntex = { version = "0.7.0", features=["tokio"] }
|
||||
ntex = { version = "1.0.0-b.1", features=["tokio"] }
|
||||
|
|
|
@ -45,16 +45,15 @@
|
|||
//! endpoint.
|
||||
//!
|
||||
//! Cors middleware automatically handle *OPTIONS* preflight request.
|
||||
use std::task::{Context, Poll};
|
||||
use std::{
|
||||
collections::HashSet, convert::TryFrom, iter::FromIterator, marker::PhantomData, rc::Rc,
|
||||
};
|
||||
|
||||
use derive_more::Display;
|
||||
use futures::future::{ok, Either, FutureExt, LocalBoxFuture, Ready};
|
||||
use ntex::http::header::{self, HeaderName, HeaderValue};
|
||||
use ntex::http::{error::HttpError, HeaderMap, Method, RequestHead, StatusCode, Uri};
|
||||
use ntex::service::{Middleware, Service, ServiceCtx};
|
||||
use ntex::util::Either;
|
||||
use ntex::web::{
|
||||
DefaultError, ErrorRenderer, HttpResponse, WebRequest, WebResponse, WebResponseError,
|
||||
};
|
||||
|
@ -747,40 +746,30 @@ where
|
|||
{
|
||||
type Response = WebResponse;
|
||||
type Error = S::Error;
|
||||
type Future<'f> = Either<
|
||||
Ready<Result<Self::Response, S::Error>>,
|
||||
LocalBoxFuture<'f, Result<Self::Response, S::Error>>,
|
||||
> where Self: 'f;
|
||||
|
||||
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.service.poll_ready(cx)
|
||||
}
|
||||
ntex::forward_poll_ready!(service);
|
||||
ntex::forward_poll_shutdown!(service);
|
||||
|
||||
fn poll_shutdown(&self, cx: &mut Context<'_>) -> Poll<()> {
|
||||
self.service.poll_shutdown(cx)
|
||||
}
|
||||
|
||||
fn call<'a>(&'a self, req: WebRequest<Err>, ctx: ServiceCtx<'a, Self>) -> Self::Future<'a> {
|
||||
async fn call(
|
||||
&self,
|
||||
req: WebRequest<Err>,
|
||||
ctx: ServiceCtx<'_, Self>,
|
||||
) -> Result<Self::Response, S::Error> {
|
||||
match self.inner.preflight_check(req.head()) {
|
||||
Ok(Either::Left(res)) => Either::Left(ok(req.into_response(res))),
|
||||
Ok(Either::Left(res)) => Ok(req.into_response(res)),
|
||||
Ok(Either::Right(_)) => {
|
||||
let inner = self.inner.clone();
|
||||
let has_origin = req.headers().contains_key(&header::ORIGIN);
|
||||
let allowed_origin = inner.access_control_allow_origin(req.headers());
|
||||
|
||||
Either::Right(
|
||||
async move {
|
||||
let mut res = ctx.call(&self.service, req).await?;
|
||||
let mut res = ctx.call(&self.service, req).await?;
|
||||
|
||||
if has_origin {
|
||||
inner.handle_response(res.headers_mut(), allowed_origin);
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
.boxed_local(),
|
||||
)
|
||||
if has_origin {
|
||||
inner.handle_response(res.headers_mut(), allowed_origin);
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
Err(e) => Either::Left(ok(req.render_error(e))),
|
||||
Err(e) => Ok(req.render_error(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -821,7 +810,7 @@ mod tests {
|
|||
|
||||
#[ntex::test]
|
||||
async fn test_preflight() {
|
||||
let mut cors: Pipeline<_> = Cors::new()
|
||||
let cors: Pipeline<_> = Cors::new()
|
||||
.send_wildcard()
|
||||
.max_age(3600)
|
||||
.allowed_methods(vec![Method::GET, Method::OPTIONS, Method::POST])
|
||||
|
@ -1006,8 +995,8 @@ mod tests {
|
|||
.expose_headers(exposed_headers.clone())
|
||||
.allowed_header(header::CONTENT_TYPE)
|
||||
.finish()
|
||||
.create(fn_service(|req: WebRequest<DefaultError>| {
|
||||
ok::<_, std::convert::Infallible>(req.into_response(
|
||||
.create(fn_service(|req: WebRequest<DefaultError>| async move {
|
||||
Ok::<_, std::convert::Infallible>(req.into_response(
|
||||
HttpResponse::Ok().header(header::VARY, "Accept").finish(),
|
||||
))
|
||||
}))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ntex-files"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0-b.0"
|
||||
authors = ["ntex contributors <team@ntex.rs>"]
|
||||
description = "Static files support for ntex web."
|
||||
readme = "README.md"
|
||||
|
@ -18,8 +18,8 @@ name = "ntex_files"
|
|||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
ntex = "0.7.0"
|
||||
ntex-http = "0.1.8"
|
||||
ntex = "1.0.0-b.1"
|
||||
ntex-http = "0.1.11"
|
||||
bitflags = "2.1"
|
||||
futures = "0.3"
|
||||
derive_more = "0.99"
|
||||
|
@ -31,7 +31,7 @@ percent-encoding = "2.1"
|
|||
v_htmlescape = "0.15.8"
|
||||
unicase = "2.6.0"
|
||||
language-tags = "0.3.2"
|
||||
httpdate = "1.0.2"
|
||||
httpdate = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
ntex = { version = "0.7.0", features = ["tokio", "openssl", "compress"] }
|
||||
ntex = { version = "1.0.0-b.1", features = ["tokio", "openssl", "compress"] }
|
||||
|
|
|
@ -7,14 +7,14 @@ use std::{
|
|||
cmp, fmt::Write, io, io::Read, io::Seek, pin::Pin, rc::Rc, task::Context, task::Poll,
|
||||
};
|
||||
|
||||
use futures::future::{ok, ready, Either, FutureExt, LocalBoxFuture, Ready};
|
||||
use futures::future::{FutureExt, LocalBoxFuture};
|
||||
use futures::{Future, Stream};
|
||||
use mime_guess::from_ext;
|
||||
use ntex::http::error::BlockingError;
|
||||
use ntex::http::{header, Method, Payload, Uri};
|
||||
use ntex::router::{ResourceDef, ResourcePath};
|
||||
use ntex::service::boxed::{self, BoxService, BoxServiceFactory};
|
||||
use ntex::service::{IntoServiceFactory, Service, ServiceCall, ServiceCtx, ServiceFactory};
|
||||
use ntex::service::{IntoServiceFactory, Service, ServiceCtx, ServiceFactory};
|
||||
use ntex::util::Bytes;
|
||||
use ntex::web::dev::{WebServiceConfig, WebServiceFactory};
|
||||
use ntex::web::error::ErrorRenderer;
|
||||
|
@ -404,9 +404,8 @@ where
|
|||
type Error = Err::Container;
|
||||
type Service = FilesService<Err>;
|
||||
type InitError = ();
|
||||
type Future<'f> = LocalBoxFuture<'f, Result<Self::Service, Self::InitError>>;
|
||||
|
||||
fn create(&self, _: ()) -> Self::Future<'_> {
|
||||
async fn create(&self, _: ()) -> Result<Self::Service, Self::InitError> {
|
||||
let mut srv = FilesService {
|
||||
directory: self.directory.clone(),
|
||||
index: self.index.clone(),
|
||||
|
@ -429,9 +428,9 @@ where
|
|||
}
|
||||
Err(_) => Err(()),
|
||||
})
|
||||
.boxed_local()
|
||||
.await
|
||||
} else {
|
||||
ok(srv).boxed_local()
|
||||
Ok(srv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -452,20 +451,17 @@ impl<Err: ErrorRenderer> FilesService<Err>
|
|||
where
|
||||
Err::Container: From<FilesError>,
|
||||
{
|
||||
fn handle_io_error<'a>(
|
||||
&'a self,
|
||||
async fn handle_io_error(
|
||||
&self,
|
||||
e: io::Error,
|
||||
req: WebRequest<Err>,
|
||||
ctx: ServiceCtx<'a, Self>,
|
||||
) -> Either<
|
||||
Ready<Result<WebResponse, Err::Container>>,
|
||||
ServiceCall<'a, HttpService<Err>, WebRequest<Err>>,
|
||||
> {
|
||||
ctx: ServiceCtx<'_, Self>,
|
||||
) -> Result<WebResponse, Err::Container> {
|
||||
log::debug!("Files: Failed to handle {}: {}", req.path(), e);
|
||||
if let Some(ref default) = self.default {
|
||||
Either::Right(ctx.call(default, req))
|
||||
ctx.call(default, req).await
|
||||
} else {
|
||||
Either::Left(ok(req.error_response(FilesError::from(e))))
|
||||
Ok(req.error_response(FilesError::from(e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -477,12 +473,12 @@ where
|
|||
{
|
||||
type Response = WebResponse;
|
||||
type Error = Err::Container;
|
||||
type Future<'f> = Either<
|
||||
Ready<Result<Self::Response, Self::Error>>,
|
||||
ServiceCall<'f, HttpService<Err>, WebRequest<Err>>,
|
||||
>;
|
||||
|
||||
fn call<'a>(&'a self, req: WebRequest<Err>, ctx: ServiceCtx<'a, Self>) -> Self::Future<'a> {
|
||||
async fn call(
|
||||
&self,
|
||||
req: WebRequest<Err>,
|
||||
ctx: ServiceCtx<'_, Self>,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
let is_method_valid = if let Some(guard) = &self.guards {
|
||||
// execute user defined guards
|
||||
(**guard).check(req.head())
|
||||
|
@ -492,30 +488,30 @@ where
|
|||
};
|
||||
|
||||
if !is_method_valid {
|
||||
return Either::Left(ok(req.error_response(FilesError::MethodNotAllowed)));
|
||||
return Ok(req.error_response(FilesError::MethodNotAllowed));
|
||||
}
|
||||
|
||||
let real_path = match PathBufWrp::get_pathbuf(req.match_info().path()) {
|
||||
Ok(item) => item,
|
||||
Err(e) => return Either::Left(ok(req.error_response(FilesError::from(e)))),
|
||||
Err(e) => return Ok(req.error_response(FilesError::from(e))),
|
||||
};
|
||||
|
||||
// full filepath
|
||||
let path = match self.directory.join(real_path.0).canonicalize() {
|
||||
Ok(path) => path,
|
||||
Err(e) => return self.handle_io_error(e, req, ctx),
|
||||
Err(e) => return self.handle_io_error(e, req, ctx).await,
|
||||
};
|
||||
|
||||
if path.is_dir() {
|
||||
if let Some(ref redir_index) = self.index {
|
||||
if self.redirect_to_slash && !req.path().ends_with('/') {
|
||||
let redirect_to = format!("{}/", req.path());
|
||||
return Either::Left(ok(req.into_response(
|
||||
return Ok(req.into_response(
|
||||
HttpResponse::Found()
|
||||
.header(header::LOCATION, redirect_to)
|
||||
.body("")
|
||||
.into_body(),
|
||||
)));
|
||||
));
|
||||
}
|
||||
|
||||
let path = path.join(redir_index);
|
||||
|
@ -530,26 +526,20 @@ where
|
|||
|
||||
named_file.flags = self.file_flags.clone();
|
||||
let (req, _) = req.into_parts();
|
||||
Either::Left(ok(WebResponse::new(named_file.into_response(&req), req)))
|
||||
Ok(WebResponse::new(named_file.into_response(&req), req))
|
||||
}
|
||||
Err(e) => self.handle_io_error(e, req, ctx),
|
||||
Err(e) => self.handle_io_error(e, req, ctx).await,
|
||||
}
|
||||
} else if self.show_index {
|
||||
let dir = Directory::new(self.directory.clone(), path);
|
||||
let (req, _) = req.into_parts();
|
||||
let x = (self.renderer)(&dir, &req);
|
||||
match x {
|
||||
Ok(resp) => Either::Left(ok(resp)),
|
||||
Err(e) => Either::Left(ok(WebResponse::from_err::<Err, _>(
|
||||
FilesError::from(e),
|
||||
req,
|
||||
))),
|
||||
Ok(resp) => Ok(resp),
|
||||
Err(e) => Ok(WebResponse::from_err::<Err, _>(FilesError::from(e), req)),
|
||||
}
|
||||
} else {
|
||||
Either::Left(ok(WebResponse::from_err::<Err, _>(
|
||||
FilesError::IsDirectory,
|
||||
req.into_parts().0,
|
||||
)))
|
||||
Ok(WebResponse::from_err::<Err, _>(FilesError::IsDirectory, req.into_parts().0))
|
||||
}
|
||||
} else {
|
||||
match NamedFile::open(path) {
|
||||
|
@ -561,9 +551,9 @@ where
|
|||
|
||||
named_file.flags = self.file_flags.clone();
|
||||
let (req, _) = req.into_parts();
|
||||
Either::Left(ok(WebResponse::new(named_file.into_response(&req), req)))
|
||||
Ok(WebResponse::new(named_file.into_response(&req), req))
|
||||
}
|
||||
Err(e) => self.handle_io_error(e, req, ctx),
|
||||
Err(e) => self.handle_io_error(e, req, ctx).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -603,10 +593,9 @@ impl PathBufWrp {
|
|||
|
||||
impl<Err> FromRequest<Err> for PathBufWrp {
|
||||
type Error = UriSegmentError;
|
||||
type Future = Ready<Result<Self, Self::Error>>;
|
||||
|
||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
||||
ready(PathBufWrp::get_pathbuf(req.match_info().path()))
|
||||
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
|
||||
PathBufWrp::get_pathbuf(req.match_info().path())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1179,8 +1168,8 @@ mod tests {
|
|||
#[ntex::test]
|
||||
async fn test_default_handler_file_missing() {
|
||||
let st = Files::new("/", ".")
|
||||
.default_handler(|req: WebRequest<DefaultError>| {
|
||||
ok(req.into_response(HttpResponse::Ok().body("default content")))
|
||||
.default_handler(|req: WebRequest<DefaultError>| async move {
|
||||
Ok(req.into_response(HttpResponse::Ok().body("default content")))
|
||||
})
|
||||
.pipeline(())
|
||||
.await
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ntex-identity"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0-b.0"
|
||||
authors = ["ntex contributors <team@ntex.rs>"]
|
||||
description = "Identity service for ntex web framework."
|
||||
readme = "README.md"
|
||||
|
@ -21,13 +21,13 @@ default = ["cookie-policy"]
|
|||
cookie-policy = ["cookie/secure", "ntex/cookie"]
|
||||
|
||||
[dependencies]
|
||||
ntex = "0.7.0"
|
||||
ntex = "1.0.0-b.1"
|
||||
futures = "0.3"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
derive_more = "0.99"
|
||||
cookie = { version = "0.17", features = ["private"] }
|
||||
cookie = { version = "0.18", features = ["private"] }
|
||||
time = { version = "0.3", default-features = false, features = ["std"] }
|
||||
|
||||
[dev-dependencies]
|
||||
ntex = { version = "0.7.0", features=["tokio"] }
|
||||
ntex = { version = "1.0.0-b.1", features=["tokio"] }
|
||||
|
|
|
@ -44,13 +44,11 @@
|
|||
//! .service(web::resource("/login.html").to(login))
|
||||
//! .service(web::resource("/logout.html").to(logout));
|
||||
//! ```
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::SystemTime;
|
||||
use std::{convert::Infallible, future::Future, rc::Rc};
|
||||
use std::{convert::Infallible, future::Future, rc::Rc, time::SystemTime};
|
||||
|
||||
use cookie::{Cookie, CookieJar, Key, SameSite};
|
||||
use derive_more::{Display, From};
|
||||
use futures::future::{ok, FutureExt, LocalBoxFuture, Ready};
|
||||
use futures::future::{ok, Ready};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::Duration;
|
||||
|
||||
|
@ -164,11 +162,10 @@ where
|
|||
/// ```
|
||||
impl<Err: ErrorRenderer> FromRequest<Err> for Identity {
|
||||
type Error = Infallible;
|
||||
type Future = Ready<Result<Identity, Infallible>>;
|
||||
|
||||
#[inline]
|
||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
||||
ok(Identity(req.clone()))
|
||||
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Identity, Infallible> {
|
||||
Ok(Identity(req.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,43 +246,34 @@ where
|
|||
{
|
||||
type Response = WebResponse;
|
||||
type Error = S::Error;
|
||||
type Future<'f> = LocalBoxFuture<'f, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
self.service.poll_ready(cx)
|
||||
}
|
||||
ntex::forward_poll_ready!(service);
|
||||
ntex::forward_poll_shutdown!(service);
|
||||
|
||||
fn poll_shutdown(&self, cx: &mut Context) -> Poll<()> {
|
||||
self.service.poll_shutdown(cx)
|
||||
}
|
||||
|
||||
fn call<'a>(
|
||||
&'a self,
|
||||
async fn call(
|
||||
&self,
|
||||
mut req: WebRequest<Err>,
|
||||
ctx: ServiceCtx<'a, Self>,
|
||||
) -> Self::Future<'a> {
|
||||
async move {
|
||||
match self.backend.from_request(&mut req).await {
|
||||
Ok(id) => {
|
||||
req.extensions_mut().insert(IdentityItem { id, changed: false });
|
||||
ctx: ServiceCtx<'_, Self>,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
match self.backend.from_request(&mut req).await {
|
||||
Ok(id) => {
|
||||
req.extensions_mut().insert(IdentityItem { id, changed: false });
|
||||
|
||||
// https://github.com/actix/actix-web/issues/1263
|
||||
let mut res = ctx.call(&self.service, req).await?;
|
||||
let id = res.request().extensions_mut().remove::<IdentityItem>();
|
||||
// https://github.com/actix/actix-web/issues/1263
|
||||
let mut res = ctx.call(&self.service, req).await?;
|
||||
let id = res.request().extensions_mut().remove::<IdentityItem>();
|
||||
|
||||
if let Some(id) = id {
|
||||
match self.backend.to_response(id.id, id.changed, &mut res).await {
|
||||
Ok(_) => Ok(res),
|
||||
Err(e) => Ok(WebResponse::error_response::<Err, _>(res, e)),
|
||||
}
|
||||
} else {
|
||||
Ok(res)
|
||||
if let Some(id) = id {
|
||||
match self.backend.to_response(id.id, id.changed, &mut res).await {
|
||||
Ok(_) => Ok(res),
|
||||
Err(e) => Ok(WebResponse::error_response::<Err, _>(res, e)),
|
||||
}
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
Err(err) => Ok(req.error_response(err)),
|
||||
}
|
||||
Err(err) => Ok(req.error_response(err)),
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -621,12 +609,13 @@ mod tests {
|
|||
})),
|
||||
)
|
||||
.await;
|
||||
|
||||
let resp = test::call_service(&srv, TestRequest::with_uri("/index").to_request()).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
|
||||
let resp = test::call_service(&srv, TestRequest::with_uri("/login").to_request()).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let c = resp.response().cookies().next().unwrap().to_owned();
|
||||
let c = resp.response().cookies().next().unwrap().into_owned();
|
||||
|
||||
let resp = test::call_service(
|
||||
&srv,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ntex-multipart"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0-b.0"
|
||||
authors = ["ntex contributors <team@ntex.rs>"]
|
||||
description = "Multipart support for ntex web framework."
|
||||
readme = "README.md"
|
||||
|
@ -16,7 +16,7 @@ name = "ntex_multipart"
|
|||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
ntex = "0.7.0"
|
||||
ntex = "1.0.0-b.1"
|
||||
derive_more = "0.99"
|
||||
httparse = "1.3"
|
||||
futures = "0.3"
|
||||
|
@ -25,4 +25,4 @@ mime = "0.3"
|
|||
twoway = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
ntex = { version = "0.7.0", features=["tokio"] }
|
||||
ntex = { version = "1.0.0-b.1", features=["tokio"] }
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//! Multipart payload support
|
||||
use std::convert::Infallible;
|
||||
|
||||
use futures::future::{ok, Ready};
|
||||
use ntex::http::Payload;
|
||||
use ntex::web::{FromRequest, HttpRequest};
|
||||
|
||||
|
@ -34,10 +33,12 @@ use crate::server::Multipart;
|
|||
/// ```
|
||||
impl<Err> FromRequest<Err> for Multipart {
|
||||
type Error = Infallible;
|
||||
type Future = Ready<Result<Multipart, Infallible>>;
|
||||
|
||||
#[inline]
|
||||
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||
ok(Multipart::new(req.headers(), payload.take()))
|
||||
async fn from_request(
|
||||
req: &HttpRequest,
|
||||
payload: &mut Payload,
|
||||
) -> Result<Multipart, Infallible> {
|
||||
Ok(Multipart::new(req.headers(), payload.take()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ntex-session"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0-b.0"
|
||||
authors = ["ntex contributors <team@ntex.rs>"]
|
||||
description = "Session for ntex web framework."
|
||||
readme = "README.md"
|
||||
|
@ -22,8 +22,8 @@ default = ["cookie-session"]
|
|||
cookie-session = ["cookie/secure", "ntex/cookie"]
|
||||
|
||||
[dependencies]
|
||||
ntex = "0.7.0"
|
||||
cookie = "0.17"
|
||||
ntex = "1.0.0-b.1"
|
||||
cookie = "0.18"
|
||||
derive_more = "0.99"
|
||||
futures = "0.3"
|
||||
serde = "1.0"
|
||||
|
@ -31,4 +31,4 @@ serde_json = "1.0"
|
|||
time = { version = "0.3", default-features = false, features = ["std"] }
|
||||
|
||||
[dev-dependencies]
|
||||
ntex = { version = "0.7.0", features=["tokio"] }
|
||||
ntex = { version = "1.0.0-b.1", features=["tokio"] }
|
||||
|
|
|
@ -15,12 +15,10 @@
|
|||
//! The constructors take a key as an argument. This is the private key
|
||||
//! for cookie session - when this value is changed, all session data is lost.
|
||||
|
||||
use std::task::{Context, Poll};
|
||||
use std::{collections::HashMap, convert::Infallible, rc::Rc};
|
||||
|
||||
use cookie::{Cookie, CookieJar, Key, SameSite};
|
||||
use derive_more::{Display, From};
|
||||
use futures::future::{FutureExt, LocalBoxFuture};
|
||||
use ntex::http::{header::HeaderValue, header::SET_COOKIE, HttpMessage};
|
||||
use ntex::service::{Middleware, Service, ServiceCtx};
|
||||
use ntex::web::{DefaultError, ErrorRenderer, WebRequest, WebResponse, WebResponseError};
|
||||
|
@ -125,7 +123,7 @@ impl CookieSessionInner {
|
|||
|
||||
/// invalidates session cookie
|
||||
fn remove_cookie(&self, res: &mut WebResponse) -> Result<(), Infallible> {
|
||||
let mut cookie = Cookie::named(self.name.clone());
|
||||
let mut cookie = Cookie::from(self.name.clone());
|
||||
cookie.set_value("");
|
||||
cookie.set_max_age(Duration::ZERO);
|
||||
cookie.set_expires(OffsetDateTime::now_utc() - Duration::days(365));
|
||||
|
@ -301,58 +299,53 @@ where
|
|||
{
|
||||
type Response = WebResponse;
|
||||
type Error = S::Error;
|
||||
type Future<'f> = LocalBoxFuture<'f, Result<Self::Response, Self::Error>> where Self: 'f;
|
||||
|
||||
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
self.service.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn poll_shutdown(&self, cx: &mut Context) -> Poll<()> {
|
||||
self.service.poll_shutdown(cx)
|
||||
}
|
||||
ntex::forward_poll_ready!(service);
|
||||
ntex::forward_poll_shutdown!(service);
|
||||
|
||||
/// On first request, a new session cookie is returned in response, regardless
|
||||
/// of whether any session state is set. With subsequent requests, if the
|
||||
/// session state changes, then set-cookie is returned in response. As
|
||||
/// a user logs out, call session.purge() to set SessionStatus accordingly
|
||||
/// and this will trigger removal of the session cookie in the response.
|
||||
fn call<'a>(&'a self, req: WebRequest<Err>, ctx: ServiceCtx<'a, Self>) -> Self::Future<'a> {
|
||||
async fn call(
|
||||
&self,
|
||||
req: WebRequest<Err>,
|
||||
ctx: ServiceCtx<'_, Self>,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
let inner = self.inner.clone();
|
||||
let (is_new, state) = self.inner.load(&req);
|
||||
let prolong_expiration = self.inner.expires_in.is_some();
|
||||
Session::set_session(state.into_iter(), &req);
|
||||
|
||||
async move {
|
||||
ctx.call(&self.service, req).await.map(|mut res| {
|
||||
match Session::get_changes(&mut res) {
|
||||
(SessionStatus::Changed, Some(state))
|
||||
| (SessionStatus::Renewed, Some(state)) => {
|
||||
res.checked_expr::<Err, _, _>(|res| inner.set_cookie(res, state))
|
||||
}
|
||||
(SessionStatus::Unchanged, Some(state)) if prolong_expiration => {
|
||||
res.checked_expr::<Err, _, _>(|res| inner.set_cookie(res, state))
|
||||
}
|
||||
(SessionStatus::Unchanged, _) =>
|
||||
// set a new session cookie upon first request (new client)
|
||||
{
|
||||
if is_new {
|
||||
let state: HashMap<String, String> = HashMap::new();
|
||||
res.checked_expr::<Err, _, _>(|res| {
|
||||
inner.set_cookie(res, state.into_iter())
|
||||
})
|
||||
} else {
|
||||
res
|
||||
}
|
||||
}
|
||||
(SessionStatus::Purged, _) => {
|
||||
let _ = inner.remove_cookie(&mut res);
|
||||
ctx.call(&self.service, req).await.map(|mut res| {
|
||||
match Session::get_changes(&mut res) {
|
||||
(SessionStatus::Changed, Some(state))
|
||||
| (SessionStatus::Renewed, Some(state)) => {
|
||||
res.checked_expr::<Err, _, _>(|res| inner.set_cookie(res, state))
|
||||
}
|
||||
(SessionStatus::Unchanged, Some(state)) if prolong_expiration => {
|
||||
res.checked_expr::<Err, _, _>(|res| inner.set_cookie(res, state))
|
||||
}
|
||||
(SessionStatus::Unchanged, _) =>
|
||||
// set a new session cookie upon first request (new client)
|
||||
{
|
||||
if is_new {
|
||||
let state: HashMap<String, String> = HashMap::new();
|
||||
res.checked_expr::<Err, _, _>(|res| {
|
||||
inner.set_cookie(res, state.into_iter())
|
||||
})
|
||||
} else {
|
||||
res
|
||||
}
|
||||
_ => res,
|
||||
}
|
||||
})
|
||||
}
|
||||
.boxed_local()
|
||||
(SessionStatus::Purged, _) => {
|
||||
let _ = inner.remove_cookie(&mut res);
|
||||
res
|
||||
}
|
||||
_ => res,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,8 +432,12 @@ mod tests {
|
|||
|
||||
let request = test::TestRequest::get().to_request();
|
||||
let response = app.call(request).await.unwrap();
|
||||
let cookie =
|
||||
response.response().cookies().find(|c| c.name() == "ntex-test").unwrap().clone();
|
||||
let cookie = response
|
||||
.response()
|
||||
.cookies()
|
||||
.find(|c| c.name() == "ntex-test")
|
||||
.unwrap()
|
||||
.into_owned();
|
||||
assert_eq!(cookie.path().unwrap(), "/test/");
|
||||
|
||||
let request = test::TestRequest::with_uri("/test/").cookie(cookie).to_request();
|
||||
|
|
|
@ -46,7 +46,6 @@ use std::collections::HashMap;
|
|||
use std::convert::Infallible;
|
||||
use std::rc::Rc;
|
||||
|
||||
use futures::future::{ok, Ready};
|
||||
use ntex::http::{Payload, RequestHead};
|
||||
use ntex::util::Extensions;
|
||||
use ntex::web::{Error, FromRequest, HttpRequest, WebRequest, WebResponse};
|
||||
|
@ -228,11 +227,10 @@ impl Session {
|
|||
/// ```
|
||||
impl<Err> FromRequest<Err> for Session {
|
||||
type Error = Infallible;
|
||||
type Future = Ready<Result<Session, Infallible>>;
|
||||
|
||||
#[inline]
|
||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
||||
ok(Session::get_session(&mut req.extensions_mut()))
|
||||
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Session, Infallible> {
|
||||
Ok(Session::get_session(&mut req.extensions_mut()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue