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"
version = "2.0.0"
dependencies = [
"actix-service 1.0.6",
"actix-web 3.3.3",
"env_logger 0.8.4",
"actix-web 4.0.0-beta.21",
"env_logger 0.9.0",
"futures",
"pin-project 0.4.29",
"pin-project 1.0.10",
]
[[package]]

View File

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

View File

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

View File

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

View File

@ -1,22 +1,21 @@
use std::future::Future;
use std::future::{ready, Ready};
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::body::{BodySize, MessageBody, ResponseBody};
use actix_web::body::{BodySize, MessageBody};
use actix_web::dev::{self, Service, Transform};
use actix_web::web::{Bytes, BytesMut};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use futures::future::{ok, Ready};
pub struct Logging;
impl<S: 'static, B> Transform<S> for Logging
impl<S: 'static, B> Transform<S, ServiceRequest> for Logging
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody + 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<BodyLogger<B>>;
type Error = Error;
type InitError = ();
@ -24,7 +23,7 @@ where
type Future = Ready<Result<Self::Transform, Self::InitError>>;
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,
}
impl<S, B> Service for LoggingMiddleware<S>
impl<S, B> Service<ServiceRequest> for LoggingMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody,
{
type Request = ServiceRequest;
type Response = ServiceResponse<BodyLogger<B>>;
type Error = Error;
type Future = WrapperStream<S, B>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
dev::forward_ready!(service);
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&self, req: ServiceRequest) -> Self::Future {
WrapperStream {
fut: self.service.call(req),
_t: PhantomData,
@ -58,7 +54,7 @@ where
pub struct WrapperStream<S, B>
where
B: MessageBody,
S: Service,
S: Service<ServiceRequest>,
{
#[pin]
fut: S::Future,
@ -68,7 +64,7 @@ where
impl<S, B> Future for WrapperStream<S, B>
where
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>;
@ -76,11 +72,9 @@ where
let res = futures::ready!(self.project().fut.poll(cx));
Poll::Ready(res.map(|res| {
res.map_body(move |_, body| {
ResponseBody::Body(BodyLogger {
body,
body_accum: BytesMut::new(),
})
res.map_body(move |_, body| BodyLogger {
body,
body_accum: BytesMut::new(),
})
}))
}
@ -89,7 +83,7 @@ where
#[pin_project::pin_project(PinnedDrop)]
pub struct BodyLogger<B> {
#[pin]
body: ResponseBody<B>,
body: B,
body_accum: BytesMut,
}
@ -101,6 +95,8 @@ impl<B> PinnedDrop for BodyLogger<B> {
}
impl<B: MessageBody> MessageBody for BodyLogger<B> {
type Error = B::Error;
fn size(&self) -> BodySize {
self.body.size()
}
@ -108,7 +104,7 @@ impl<B: MessageBody> MessageBody for BodyLogger<B> {
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Error>>> {
) -> Poll<Option<Result<Bytes, Self::Error>>> {
let this = self.project();
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::dev::{ServiceRequest, ServiceResponse};
use actix_web::body::EitherBody;
use actix_web::dev::{self, ServiceRequest, ServiceResponse};
use actix_web::dev::{Service, Transform};
use actix_web::{http, Error, HttpResponse};
use futures::future::{ok, Either, Ready};
use futures::future::LocalBoxFuture;
pub struct CheckLogin;
impl<S, B> Transform<S> for CheckLogin
impl<S, B> Transform<S, ServiceRequest> for CheckLogin
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Response = ServiceResponse<EitherBody<B>>;
type Error = Error;
type InitError = ();
type Transform = CheckLoginMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(CheckLoginMiddleware { service })
ready(Ok(CheckLoginMiddleware { service }))
}
}
pub struct CheckLoginMiddleware<S> {
service: S,
}
impl<S, B> Service for CheckLoginMiddleware<S>
impl<S, B> Service<ServiceRequest> for CheckLoginMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Response = ServiceResponse<EitherBody<B>>;
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>> {
self.service.poll_ready(cx)
}
dev::forward_ready!(service);
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.
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 {
Either::Left(self.service.call(req))
} else {
Box::pin(async move {
// Don't forward to /login if we are already on /login
if req.path() == "/login" {
Either::Left(self.service.call(req))
if is_logged_in || request.path() == "/login" {
svc_response.await.map(ServiceResponse::map_into_left_body)
} else {
Either::Right(ok(req.into_response(
HttpResponse::Found()
.header(http::header::LOCATION, "/login")
.finish()
.into_body(),
)))
let response = HttpResponse::Found()
.insert_header((http::header::LOCATION, "/login"))
.finish()
.map_into_right_body();
Ok(ServiceResponse::new(request, response))
}
}
})
}
}

View File

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