From 817c7e115082d2193b8dfafbb163d58d0d2eec13 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 6 Oct 2021 23:04:19 -0400 Subject: [PATCH] Working middleware using extensions_mut (#402) Co-authored-by: Rob Ede --- Cargo.lock | 8 ++ Cargo.toml | 1 + basics/middleware-ext-mut/Cargo.toml | 10 +++ basics/middleware-ext-mut/README.md | 18 +++++ basics/middleware-ext-mut/src/add_msg.rs | 97 ++++++++++++++++++++++++ basics/middleware-ext-mut/src/main.rs | 36 +++++++++ basics/middleware/README.md | 3 +- 7 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 basics/middleware-ext-mut/Cargo.toml create mode 100644 basics/middleware-ext-mut/README.md create mode 100644 basics/middleware-ext-mut/src/add_msg.rs create mode 100644 basics/middleware-ext-mut/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 7aca074..39ed64c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3760,6 +3760,14 @@ dependencies = [ "pin-project 0.4.28", ] +[[package]] +name = "middleware-ext-mut" +version = "0.1.0" +dependencies = [ + "actix-web 3.3.2", + "env_logger 0.9.0", +] + [[package]] name = "mime" version = "0.3.16" diff --git a/Cargo.toml b/Cargo.toml index d2fb892..af509ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "basics/http-proxy", "basics/json-validation", "basics/middleware", + "basics/middleware-ext-mut", "basics/nested-routing", "basics/run-in-thread", "basics/shutdown-server", diff --git a/basics/middleware-ext-mut/Cargo.toml b/basics/middleware-ext-mut/Cargo.toml new file mode 100644 index 0000000..9cfd3a8 --- /dev/null +++ b/basics/middleware-ext-mut/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "middleware-ext-mut" +version = "0.1.0" +authors = ["Eric McCarthy "] +edition = "2018" + +[dependencies] +actix-web = "3" + +env_logger = "0.9" diff --git a/basics/middleware-ext-mut/README.md b/basics/middleware-ext-mut/README.md new file mode 100644 index 0000000..f16a1f2 --- /dev/null +++ b/basics/middleware-ext-mut/README.md @@ -0,0 +1,18 @@ +# middleware examples + +This example showcases a middleware that adds and retreives request-local data. See also the [Middleware guide](https://actix.rs/docs/middleware/). + +## Usage + +```bash +cd basics/middleware-ext-mut +cargo run +# Started http server: 127.0.0.1:8080 +``` + +Look in `src/add_msg.rs` to see how it works. + +## Routes + +- [GET /on](http://localhost:8080/on) - `200 OK` with "hello from middleware" body and console log showing the request passed through the middleware +- [GET /off](http://localhost:8080/off) - `500 Internal Server Error` with "no message found" body and console log showing the request passed through the middleware diff --git a/basics/middleware-ext-mut/src/add_msg.rs b/basics/middleware-ext-mut/src/add_msg.rs new file mode 100644 index 0000000..cc0a03d --- /dev/null +++ b/basics/middleware-ext-mut/src/add_msg.rs @@ -0,0 +1,97 @@ +use std::{ + future::{ready, Future, Ready}, + pin::Pin, + task::{Context, Poll}, +}; + +use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform}; +use actix_web::Error; + +#[derive(Debug, Clone)] +pub struct Msg(pub String); + +#[doc(hidden)] +pub struct AddMsgService { + service: S, + enabled: bool, +} + +impl Service for AddMsgService +where + S: Service< + Request = ServiceRequest, + Response = ServiceResponse, + Error = actix_web::Error, + >, + S::Future: 'static, + B: 'static, +{ + type Request = ServiceRequest; + type Response = ServiceResponse; + type Error = Error; + type Future = Pin>>>; + + fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll> { + self.service.poll_ready(ctx) + } + + fn call(&mut self, req: Self::Request) -> Self::Future { + println!("request is passing through the AddMsg middleware"); + + // get mut HttpRequest from ServiceRequest + let (request, pl) = req.into_parts(); + + if self.enabled { + // insert data into extensions if enabled + request + .extensions_mut() + .insert(Msg("Hello from Middleware!".to_owned())); + } + + // construct a new service response + match ServiceRequest::from_parts(request, pl) { + Ok(req) => Box::pin(self.service.call(req)), + Err(_) => Box::pin(ready(Err(Error::from(())))), + } + } +} + +#[derive(Clone, Debug)] +pub struct AddMsg { + enabled: bool, +} + +impl AddMsg { + pub fn enabled() -> Self { + Self { enabled: true } + } + + pub fn disabled() -> Self { + Self { enabled: false } + } +} + +impl Transform for AddMsg +where + S: Service< + Request = ServiceRequest, + Response = ServiceResponse, + Error = actix_web::Error, + >, + S::Future: 'static, + B: 'static, +{ + type Request = ServiceRequest; + type Response = ServiceResponse; + type Error = Error; + type Future = Ready>; + type Transform = AddMsgService; + type InitError = (); + + fn new_transform(&self, service: S) -> Self::Future { + ready(Ok(AddMsgService { + service, + enabled: self.enabled, + })) + } +} diff --git a/basics/middleware-ext-mut/src/main.rs b/basics/middleware-ext-mut/src/main.rs new file mode 100644 index 0000000..241b8d8 --- /dev/null +++ b/basics/middleware-ext-mut/src/main.rs @@ -0,0 +1,36 @@ +use std::{env, io}; + +use actix_web::{ + middleware, + web::{self, ReqData}, + App, HttpResponse, HttpServer, +}; + +mod add_msg; +use crate::add_msg::{AddMsg, Msg}; + +// wrap route in our middleware factory +async fn index(msg: Option>) -> HttpResponse { + if let Some(msg_data) = msg { + let Msg(message) = msg_data.into_inner(); + HttpResponse::Ok().body(message) + } else { + HttpResponse::InternalServerError().body("No message found.") + } +} + +#[actix_web::main] +async fn main() -> io::Result<()> { + env::set_var("RUST_LOG", "info"); + env_logger::init(); + + HttpServer::new(|| { + App::new() + .wrap(middleware::Logger::default()) + .service(web::resource("/on").wrap(AddMsg::enabled()).to(index)) + .service(web::resource("/off").wrap(AddMsg::disabled()).to(index)) + }) + .bind(("127.0.0.1", 8080))? + .run() + .await +} diff --git a/basics/middleware/README.md b/basics/middleware/README.md index 0c19235..7cdadaf 100644 --- a/basics/middleware/README.md +++ b/basics/middleware/README.md @@ -10,8 +10,7 @@ cargo run # Started http server: 127.0.0.1:8080 ``` -Look in `src/main.rs` and comment the different middlewares in/out to see how -they function. +Look in `src/main.rs` and comment the different middlewares in/out to see how they function. ## Middlewares