1
0
mirror of https://github.com/actix/examples synced 2024-11-23 22:41:07 +01:00

Update basics/middleware to v4 (#482)

Co-authored-by: Rob Ede <robjtede@icloud.com>
This commit is contained in:
Luca Palmieri 2022-01-29 16:39:58 +00:00 committed by GitHub
parent 9a00813b93
commit e903184a12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 89 additions and 110 deletions

7
Cargo.lock generated
View File

@ -3569,11 +3569,10 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
name = "middleware-example" name = "middleware-example"
version = "2.0.0" version = "2.0.0"
dependencies = [ dependencies = [
"actix-service 1.0.6", "actix-web 4.0.0-beta.21",
"actix-web 3.3.3", "env_logger 0.9.0",
"env_logger 0.8.4",
"futures", "futures",
"pin-project 0.4.29", "pin-project 1.0.10",
] ]
[[package]] [[package]]

View File

@ -5,9 +5,7 @@ authors = ["Gorm Casper <gcasper@gmail.com>", "Sven-Hendrik Haase <svenstaro@gma
edition = "2018" edition = "2018"
[dependencies] [dependencies]
actix-service = "1" actix-web = "4.0.0-beta.21"
actix-web = "3" env_logger = "0.9"
futures = "0.3.7"
env_logger = "0.8" pin-project = "1"
futures = "0.3.1"
pin-project = "0.4"

View File

@ -1,8 +1,5 @@
#![allow(clippy::type_complexity)] use actix_web::{dev::Service, web, App, HttpServer};
use futures::FutureExt as _;
use actix_service::Service;
use actix_web::{web, App, HttpServer};
use futures::future::FutureExt;
#[allow(dead_code)] #[allow(dead_code)]
mod read_request_body; mod read_request_body;

View File

@ -1,23 +1,22 @@
use std::cell::RefCell; use std::{
use std::pin::Pin; future::{ready, Ready},
use std::rc::Rc; rc::Rc,
use std::task::{Context, Poll}; };
use actix_service::{Service, Transform}; use actix_web::dev::{self, Service, Transform};
use actix_web::web::BytesMut; use actix_web::web::BytesMut;
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage}; use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage};
use futures::future::{ok, Future, Ready}; use futures::future::LocalBoxFuture;
use futures::stream::StreamExt; use futures::stream::StreamExt;
pub struct Logging; pub struct Logging;
impl<S: 'static, B> Transform<S> for Logging impl<S: 'static, B> Transform<S, ServiceRequest> for Logging
where where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static, S::Future: 'static,
B: 'static, B: 'static,
{ {
type Request = ServiceRequest;
type Response = ServiceResponse<B>; type Response = ServiceResponse<B>;
type Error = Error; type Error = Error;
type InitError = (); type InitError = ();
@ -25,35 +24,31 @@ where
type Future = Ready<Result<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(LoggingMiddleware { ready(Ok(LoggingMiddleware {
service: Rc::new(RefCell::new(service)), service: Rc::new(service),
}) }))
} }
} }
pub struct LoggingMiddleware<S> { pub struct LoggingMiddleware<S> {
// This is special: We need this to avoid lifetime issues. // This is special: We need this to avoid lifetime issues.
service: Rc<RefCell<S>>, service: Rc<S>,
} }
impl<S, B> Service for LoggingMiddleware<S> impl<S, B> Service<ServiceRequest> for LoggingMiddleware<S>
where where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error> S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
+ 'static,
S::Future: 'static, S::Future: 'static,
B: 'static, B: 'static,
{ {
type Request = ServiceRequest;
type Response = ServiceResponse<B>; type Response = ServiceResponse<B>;
type Error = Error; type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>; type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> { dev::forward_ready!(service);
self.service.poll_ready(cx)
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future { fn call(&self, mut req: ServiceRequest) -> Self::Future {
let mut svc = self.service.clone(); let svc = self.service.clone();
Box::pin(async move { Box::pin(async move {
let mut body = BytesMut::new(); let mut body = BytesMut::new();

View File

@ -1,22 +1,21 @@
use std::future::Future; use std::future::Future;
use std::future::{ready, Ready};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use actix_service::{Service, Transform}; use actix_web::body::{BodySize, MessageBody};
use actix_web::body::{BodySize, MessageBody, ResponseBody}; use actix_web::dev::{self, Service, Transform};
use actix_web::web::{Bytes, BytesMut}; use actix_web::web::{Bytes, BytesMut};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error}; use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use futures::future::{ok, Ready};
pub struct Logging; pub struct Logging;
impl<S: 'static, B> Transform<S> for Logging impl<S: 'static, B> Transform<S, ServiceRequest> for Logging
where where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
type Request = ServiceRequest;
type Response = ServiceResponse<BodyLogger<B>>; type Response = ServiceResponse<BodyLogger<B>>;
type Error = Error; type Error = Error;
type InitError = (); type InitError = ();
@ -24,7 +23,7 @@ where
type Future = Ready<Result<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(LoggingMiddleware { service }) ready(Ok(LoggingMiddleware { service }))
} }
} }
@ -32,21 +31,18 @@ pub struct LoggingMiddleware<S> {
service: S, service: S,
} }
impl<S, B> Service for LoggingMiddleware<S> impl<S, B> Service<ServiceRequest> for LoggingMiddleware<S>
where where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody, B: MessageBody,
{ {
type Request = ServiceRequest;
type Response = ServiceResponse<BodyLogger<B>>; type Response = ServiceResponse<BodyLogger<B>>;
type Error = Error; type Error = Error;
type Future = WrapperStream<S, B>; type Future = WrapperStream<S, B>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> { dev::forward_ready!(service);
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future { fn call(&self, req: ServiceRequest) -> Self::Future {
WrapperStream { WrapperStream {
fut: self.service.call(req), fut: self.service.call(req),
_t: PhantomData, _t: PhantomData,
@ -58,7 +54,7 @@ where
pub struct WrapperStream<S, B> pub struct WrapperStream<S, B>
where where
B: MessageBody, B: MessageBody,
S: Service, S: Service<ServiceRequest>,
{ {
#[pin] #[pin]
fut: S::Future, fut: S::Future,
@ -68,7 +64,7 @@ where
impl<S, B> Future for WrapperStream<S, B> impl<S, B> Future for WrapperStream<S, B>
where where
B: MessageBody, B: MessageBody,
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{ {
type Output = Result<ServiceResponse<BodyLogger<B>>, Error>; type Output = Result<ServiceResponse<BodyLogger<B>>, Error>;
@ -76,11 +72,9 @@ where
let res = futures::ready!(self.project().fut.poll(cx)); let res = futures::ready!(self.project().fut.poll(cx));
Poll::Ready(res.map(|res| { Poll::Ready(res.map(|res| {
res.map_body(move |_, body| { res.map_body(move |_, body| BodyLogger {
ResponseBody::Body(BodyLogger { body,
body, body_accum: BytesMut::new(),
body_accum: BytesMut::new(),
})
}) })
})) }))
} }
@ -89,7 +83,7 @@ where
#[pin_project::pin_project(PinnedDrop)] #[pin_project::pin_project(PinnedDrop)]
pub struct BodyLogger<B> { pub struct BodyLogger<B> {
#[pin] #[pin]
body: ResponseBody<B>, body: B,
body_accum: BytesMut, body_accum: BytesMut,
} }
@ -101,6 +95,8 @@ impl<B> PinnedDrop for BodyLogger<B> {
} }
impl<B: MessageBody> MessageBody for BodyLogger<B> { impl<B: MessageBody> MessageBody for BodyLogger<B> {
type Error = B::Error;
fn size(&self) -> BodySize { fn size(&self) -> BodySize {
self.body.size() self.body.size()
} }
@ -108,7 +104,7 @@ impl<B: MessageBody> MessageBody for BodyLogger<B> {
fn poll_next( fn poll_next(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Error>>> { ) -> Poll<Option<Result<Bytes, Self::Error>>> {
let this = self.project(); let this = self.project();
match this.body.poll_next(cx) { match this.body.poll_next(cx) {

View File

@ -1,65 +1,63 @@
use std::task::{Context, Poll}; use std::future::{ready, Ready};
use actix_service::{Service, Transform}; use actix_web::body::EitherBody;
use actix_web::dev::{ServiceRequest, ServiceResponse}; use actix_web::dev::{self, ServiceRequest, ServiceResponse};
use actix_web::dev::{Service, Transform};
use actix_web::{http, Error, HttpResponse}; use actix_web::{http, Error, HttpResponse};
use futures::future::{ok, Either, Ready}; use futures::future::LocalBoxFuture;
pub struct CheckLogin; pub struct CheckLogin;
impl<S, B> Transform<S> for CheckLogin impl<S, B> Transform<S, ServiceRequest> for CheckLogin
where where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static, S::Future: 'static,
{ {
type Request = ServiceRequest; type Response = ServiceResponse<EitherBody<B>>;
type Response = ServiceResponse<B>;
type Error = Error; type Error = Error;
type InitError = (); type InitError = ();
type Transform = CheckLoginMiddleware<S>; type Transform = CheckLoginMiddleware<S>;
type Future = Ready<Result<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(CheckLoginMiddleware { service }) ready(Ok(CheckLoginMiddleware { service }))
} }
} }
pub struct CheckLoginMiddleware<S> { pub struct CheckLoginMiddleware<S> {
service: S, service: S,
} }
impl<S, B> Service for CheckLoginMiddleware<S> impl<S, B> Service<ServiceRequest> for CheckLoginMiddleware<S>
where where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static, S::Future: 'static,
{ {
type Request = ServiceRequest; type Response = ServiceResponse<EitherBody<B>>;
type Response = ServiceResponse<B>;
type Error = Error; type Error = Error;
type Future = Either<S::Future, Ready<Result<Self::Response, Self::Error>>>; type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> { dev::forward_ready!(service);
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future { fn call(&self, req: ServiceRequest) -> Self::Future {
// We only need to hook into the `start` for this middleware. // We only need to hook into the `start` for this middleware.
let is_logged_in = false; // Change this to see the change in outcome in the browser let is_logged_in = false; // Change this to see the change in outcome in the browser
let (request, payload) = req.into_parts();
let svc_response = self
.service
.call(ServiceRequest::from_parts(request.clone(), payload));
if is_logged_in { Box::pin(async move {
Either::Left(self.service.call(req))
} else {
// Don't forward to /login if we are already on /login // Don't forward to /login if we are already on /login
if req.path() == "/login" { if is_logged_in || request.path() == "/login" {
Either::Left(self.service.call(req)) svc_response.await.map(ServiceResponse::map_into_left_body)
} else { } else {
Either::Right(ok(req.into_response( let response = HttpResponse::Found()
HttpResponse::Found() .insert_header((http::header::LOCATION, "/login"))
.header(http::header::LOCATION, "/login") .finish()
.finish() .map_into_right_body();
.into_body(),
))) Ok(ServiceResponse::new(request, response))
} }
} })
} }
} }

View File

@ -1,10 +1,10 @@
use std::pin::Pin; use std::future::{ready, Ready};
use std::task::{Context, Poll};
use actix_service::{Service, Transform}; use actix_web::{
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error}; dev::{self, Service, ServiceRequest, ServiceResponse, Transform},
use futures::future::{ok, Ready}; Error,
use futures::Future; };
use futures::future::LocalBoxFuture;
// There are two steps in middleware processing. // There are two steps in middleware processing.
// 1. Middleware initialization, middleware factory gets called with // 1. Middleware initialization, middleware factory gets called with
@ -15,13 +15,12 @@ pub struct SayHi;
// Middleware factory is `Transform` trait from actix-service crate // Middleware factory is `Transform` trait from actix-service crate
// `S` - type of the next service // `S` - type of the next service
// `B` - type of response's body // `B` - type of response's body
impl<S, B> Transform<S> for SayHi impl<S, B> Transform<S, ServiceRequest> for SayHi
where where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static, S::Future: 'static,
B: 'static, B: 'static,
{ {
type Request = ServiceRequest;
type Response = ServiceResponse<B>; type Response = ServiceResponse<B>;
type Error = Error; type Error = Error;
type InitError = (); type InitError = ();
@ -29,7 +28,7 @@ where
type Future = Ready<Result<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(SayHiMiddleware { service }) ready(Ok(SayHiMiddleware { service }))
} }
} }
@ -37,22 +36,19 @@ pub struct SayHiMiddleware<S> {
service: S, service: S,
} }
impl<S, B> Service for SayHiMiddleware<S> impl<S, B> Service<ServiceRequest> for SayHiMiddleware<S>
where where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static, S::Future: 'static,
B: 'static, B: 'static,
{ {
type Request = ServiceRequest;
type Response = ServiceResponse<B>; type Response = ServiceResponse<B>;
type Error = Error; type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>; type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { dev::forward_ready!(service);
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future { fn call(&self, req: ServiceRequest) -> Self::Future {
println!("Hi from start. You requested: {}", req.path()); println!("Hi from start. You requested: {}", req.path());
let fut = self.service.call(req); let fut = self.service.call(req);