mirror of
https://github.com/actix/examples
synced 2024-11-27 16:02:57 +01:00
Update basics/middleware to v4 (#482)
Co-authored-by: Rob Ede <robjtede@icloud.com>
This commit is contained in:
parent
9a00813b93
commit
e903184a12
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -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]]
|
||||||
|
@ -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"
|
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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,12 +72,10 @@ 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) {
|
||||||
|
@ -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()
|
||||||
.into_body(),
|
.map_into_right_body();
|
||||||
)))
|
|
||||||
}
|
Ok(ServiceResponse::new(request, response))
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user