mirror of
https://github.com/actix/examples
synced 2025-06-26 17:17:42 +02:00
restructure folders
This commit is contained in:
9
middleware/middleware-ext-mut/Cargo.toml
Normal file
9
middleware/middleware-ext-mut/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "middleware-ext-mut"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.0.0-rc.1"
|
||||
log = "0.4"
|
||||
env_logger = "0.9"
|
18
middleware/middleware-ext-mut/README.md
Normal file
18
middleware/middleware-ext-mut/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# middleware examples
|
||||
|
||||
This example showcases a middleware that adds and retrieves 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
|
77
middleware/middleware-ext-mut/src/add_msg.rs
Normal file
77
middleware/middleware-ext-mut/src/add_msg.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use std::{
|
||||
future::{ready, Ready},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use actix_web::Error;
|
||||
use actix_web::{
|
||||
dev::{Service, ServiceRequest, ServiceResponse, Transform},
|
||||
HttpMessage,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Msg(pub String);
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct AddMsgService<S> {
|
||||
service: S,
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl<S, B> Service<ServiceRequest> for AddMsgService<S>
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error>,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Future = S::Future;
|
||||
|
||||
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.service.poll_ready(ctx)
|
||||
}
|
||||
|
||||
fn call(&self, req: ServiceRequest) -> Self::Future {
|
||||
log::info!("request is passing through the AddMsg middleware");
|
||||
|
||||
if self.enabled {
|
||||
// insert data into extensions if enabled
|
||||
req.extensions_mut()
|
||||
.insert(Msg("Hello from Middleware!".to_owned()));
|
||||
}
|
||||
|
||||
self.service.call(req)
|
||||
}
|
||||
}
|
||||
|
||||
#[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<S, B> Transform<S, ServiceRequest> for AddMsg
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error>,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
type Transform = AddMsgService<S>;
|
||||
type InitError = ();
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
ready(Ok(AddMsgService {
|
||||
service,
|
||||
enabled: self.enabled,
|
||||
}))
|
||||
}
|
||||
}
|
36
middleware/middleware-ext-mut/src/main.rs
Normal file
36
middleware/middleware-ext-mut/src/main.rs
Normal file
@ -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<ReqData<Msg>>) -> 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
|
||||
}
|
10
middleware/middleware-http-to-https/Cargo.toml
Normal file
10
middleware/middleware-http-to-https/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "middleware-http-to-https"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = { version = "4.0.0-beta.21", features = ["rustls"] }
|
||||
rustls = "0.20.2"
|
||||
rustls-pemfile = "0.2.1"
|
||||
futures = "0.3"
|
12
middleware/middleware-http-to-https/README.md
Normal file
12
middleware/middleware-http-to-https/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
## Middleware eg - redirect any http connection to use https connection
|
||||
|
||||
This example is the next step after implementing this example : [Setup TLS via rustls](https://github.com/actix/examples/tree/master/security/rustls).
|
||||
|
||||
You might have already implemented TLS(using one of the ways mentioned in the example of security section), and have setup your server to listen to port 443(for https).
|
||||
|
||||
Now, the only problem left to solve is, to listen to **http** connections as well and redirect them to use **https**
|
||||
|
||||
## Usage
|
||||
|
||||
**Note :** You will be required to use sudo while running the binary to access port 80 and 443
|
||||
|
1
middleware/middleware-http-to-https/cert.pem
Symbolic link
1
middleware/middleware-http-to-https/cert.pem
Symbolic link
@ -0,0 +1 @@
|
||||
cert.pem
|
1
middleware/middleware-http-to-https/key.pem
Symbolic link
1
middleware/middleware-http-to-https/key.pem
Symbolic link
@ -0,0 +1 @@
|
||||
key.pem
|
72
middleware/middleware-http-to-https/src/main.rs
Normal file
72
middleware/middleware-http-to-https/src/main.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
|
||||
use actix_web::dev::Service;
|
||||
use futures::future::FutureExt;
|
||||
|
||||
use actix_web::{get, App, HttpServer};
|
||||
use actix_web::{http, HttpResponse};
|
||||
use futures::future;
|
||||
use futures::future::Either;
|
||||
use rustls::{Certificate, PrivateKey, ServerConfig};
|
||||
use rustls_pemfile::{certs, pkcs8_private_keys};
|
||||
|
||||
#[get("/")]
|
||||
async fn index() -> String {
|
||||
String::from(
|
||||
"<html><head><title>FOO BAR</title></head><body><h1>FOO BAR</h1></body></html>",
|
||||
)
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let cert_file = &mut BufReader::new(File::open("cert.pem").unwrap());
|
||||
let key_file = &mut BufReader::new(File::open("key.pem").unwrap());
|
||||
|
||||
let cert_chain: Vec<Certificate> = certs(cert_file)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(Certificate)
|
||||
.collect();
|
||||
let mut keys: Vec<PrivateKey> = pkcs8_private_keys(key_file)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PrivateKey)
|
||||
.collect();
|
||||
|
||||
let config = ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_no_client_auth()
|
||||
.with_single_cert(cert_chain, keys.remove(0))
|
||||
.unwrap();
|
||||
|
||||
HttpServer::new(|| {
|
||||
App::new()
|
||||
.wrap_fn(|sreq, srv| {
|
||||
let host = sreq.connection_info().host().to_owned();
|
||||
let uri = sreq.uri().to_owned();
|
||||
let url = format!("https://{}{}", host, uri);
|
||||
|
||||
// If the scheme is "https" then it will let other services below this wrap_fn
|
||||
// handle the request and if it's "http" then a response with redirect status code
|
||||
// will be sent whose "location" header will be same as before, with just "http"
|
||||
// changed to "https"
|
||||
//
|
||||
if sreq.connection_info().scheme() == "https" {
|
||||
Either::Left(srv.call(sreq).map(|res| res))
|
||||
} else {
|
||||
println!("An http request has arrived here, i will redirect it to use https");
|
||||
return Either::Right(future::ready(Ok(sreq.into_response(
|
||||
HttpResponse::MovedPermanently()
|
||||
.append_header((http::header::LOCATION, url))
|
||||
.finish(),
|
||||
))));
|
||||
}
|
||||
})
|
||||
.service(index)
|
||||
})
|
||||
.bind("0.0.0.0:80")? // Port 80 to listen for http request
|
||||
.bind_rustls("0.0.0.0:443", config)? // Port 443 to listen for https request
|
||||
.run()
|
||||
.await
|
||||
}
|
10
middleware/middleware/Cargo.toml
Normal file
10
middleware/middleware/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "middleware-example"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.0.0-rc.1"
|
||||
env_logger = "0.9"
|
||||
futures = "0.3.7"
|
||||
pin-project = "1"
|
32
middleware/middleware/README.md
Normal file
32
middleware/middleware/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# middleware examples
|
||||
|
||||
This example showcases a bunch of different uses of middlewares. See also the [Middleware guide](https://actix.rs/docs/middleware/).
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
cd basics/middleware
|
||||
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.
|
||||
|
||||
## Middlewares
|
||||
|
||||
### redirect::CheckLogin
|
||||
|
||||
A middleware implementing a request guard which sketches a rough approximation of what a login could look like.
|
||||
|
||||
### read_request_body::Logging
|
||||
|
||||
A middleware demonstrating how to read out the incoming request body.
|
||||
|
||||
### read_response_body::Logging
|
||||
|
||||
A middleware demonstrating how to read out the outgoing response body.
|
||||
|
||||
### simple::SayHi
|
||||
|
||||
A minimal middleware demonstrating the sequence of operations in an actix middleware.
|
||||
There is a second version of the same middleware using `wrap_fn` which shows how easily a middleware can be implemented in actix.
|
42
middleware/middleware/src/main.rs
Normal file
42
middleware/middleware/src/main.rs
Normal file
@ -0,0 +1,42 @@
|
||||
use actix_web::{dev::Service, web, App, HttpServer};
|
||||
use futures::FutureExt as _;
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod read_request_body;
|
||||
#[allow(dead_code)]
|
||||
mod read_response_body;
|
||||
#[allow(dead_code)]
|
||||
mod redirect;
|
||||
#[allow(dead_code)]
|
||||
mod simple;
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
std::env::set_var("RUST_LOG", "actix_web=debug");
|
||||
env_logger::init();
|
||||
|
||||
HttpServer::new(|| {
|
||||
App::new()
|
||||
.wrap(redirect::CheckLogin)
|
||||
.wrap(read_request_body::Logging)
|
||||
.wrap(read_response_body::Logging)
|
||||
.wrap(simple::SayHi)
|
||||
.wrap_fn(|req, srv| {
|
||||
println!("Hi from start. You requested: {}", req.path());
|
||||
|
||||
srv.call(req).map(|res| {
|
||||
println!("Hi from response");
|
||||
res
|
||||
})
|
||||
})
|
||||
.service(web::resource("/login").to(|| async {
|
||||
"You are on /login. Go to src/redirect.rs to change this behavior."
|
||||
}))
|
||||
.service(web::resource("/").to(|| async {
|
||||
"Hello, middleware! Check the console where the server is run."
|
||||
}))
|
||||
})
|
||||
.bind(("127.0.0.1", 8080))?
|
||||
.run()
|
||||
.await
|
||||
}
|
67
middleware/middleware/src/read_request_body.rs
Normal file
67
middleware/middleware/src/read_request_body.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use std::{
|
||||
future::{ready, Ready},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use actix_web::dev::{self, Service, Transform};
|
||||
use actix_web::web::BytesMut;
|
||||
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage};
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::stream::StreamExt;
|
||||
|
||||
pub struct Logging;
|
||||
|
||||
impl<S: 'static, B> Transform<S, ServiceRequest> for Logging
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = LoggingMiddleware<S>;
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
ready(Ok(LoggingMiddleware {
|
||||
service: Rc::new(service),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoggingMiddleware<S> {
|
||||
// This is special: We need this to avoid lifetime issues.
|
||||
service: Rc<S>,
|
||||
}
|
||||
|
||||
impl<S, B> Service<ServiceRequest> for LoggingMiddleware<S>
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
dev::forward_ready!(service);
|
||||
|
||||
fn call(&self, mut req: ServiceRequest) -> Self::Future {
|
||||
let svc = self.service.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
let mut body = BytesMut::new();
|
||||
let mut stream = req.take_payload();
|
||||
while let Some(chunk) = stream.next().await {
|
||||
body.extend_from_slice(&chunk?);
|
||||
}
|
||||
|
||||
println!("request body: {:?}", body);
|
||||
let res = svc.call(req).await?;
|
||||
|
||||
println!("response: {:?}", res.headers());
|
||||
Ok(res)
|
||||
})
|
||||
}
|
||||
}
|
120
middleware/middleware/src/read_response_body.rs
Normal file
120
middleware/middleware/src/read_response_body.rs
Normal file
@ -0,0 +1,120 @@
|
||||
use std::future::Future;
|
||||
use std::future::{ready, Ready};
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
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};
|
||||
|
||||
pub struct Logging;
|
||||
|
||||
impl<S: 'static, B> Transform<S, ServiceRequest> for Logging
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
type Response = ServiceResponse<BodyLogger<B>>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = LoggingMiddleware<S>;
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
ready(Ok(LoggingMiddleware { service }))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoggingMiddleware<S> {
|
||||
service: S,
|
||||
}
|
||||
|
||||
impl<S, B> Service<ServiceRequest> for LoggingMiddleware<S>
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
B: MessageBody,
|
||||
{
|
||||
type Response = ServiceResponse<BodyLogger<B>>;
|
||||
type Error = Error;
|
||||
type Future = WrapperStream<S, B>;
|
||||
|
||||
dev::forward_ready!(service);
|
||||
|
||||
fn call(&self, req: ServiceRequest) -> Self::Future {
|
||||
WrapperStream {
|
||||
fut: self.service.call(req),
|
||||
_t: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project::pin_project]
|
||||
pub struct WrapperStream<S, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
S: Service<ServiceRequest>,
|
||||
{
|
||||
#[pin]
|
||||
fut: S::Future,
|
||||
_t: PhantomData<(B,)>,
|
||||
}
|
||||
|
||||
impl<S, B> Future for WrapperStream<S, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
type Output = Result<ServiceResponse<BodyLogger<B>>, Error>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let res = futures::ready!(self.project().fut.poll(cx));
|
||||
|
||||
Poll::Ready(res.map(|res| {
|
||||
res.map_body(move |_, body| BodyLogger {
|
||||
body,
|
||||
body_accum: BytesMut::new(),
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project::pin_project(PinnedDrop)]
|
||||
pub struct BodyLogger<B> {
|
||||
#[pin]
|
||||
body: B,
|
||||
body_accum: BytesMut,
|
||||
}
|
||||
|
||||
#[pin_project::pinned_drop]
|
||||
impl<B> PinnedDrop for BodyLogger<B> {
|
||||
fn drop(self: Pin<&mut Self>) {
|
||||
println!("response body: {:?}", self.body_accum);
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: MessageBody> MessageBody for BodyLogger<B> {
|
||||
type Error = B::Error;
|
||||
|
||||
fn size(&self) -> BodySize {
|
||||
self.body.size()
|
||||
}
|
||||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
let this = self.project();
|
||||
|
||||
match this.body.poll_next(cx) {
|
||||
Poll::Ready(Some(Ok(chunk))) => {
|
||||
this.body_accum.extend_from_slice(&chunk);
|
||||
Poll::Ready(Some(Ok(chunk)))
|
||||
}
|
||||
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
63
middleware/middleware/src/redirect.rs
Normal file
63
middleware/middleware/src/redirect.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use std::future::{ready, Ready};
|
||||
|
||||
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::LocalBoxFuture;
|
||||
|
||||
pub struct CheckLogin;
|
||||
|
||||
impl<S, B> Transform<S, ServiceRequest> for CheckLogin
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
{
|
||||
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 {
|
||||
ready(Ok(CheckLoginMiddleware { service }))
|
||||
}
|
||||
}
|
||||
pub struct CheckLoginMiddleware<S> {
|
||||
service: S,
|
||||
}
|
||||
|
||||
impl<S, B> Service<ServiceRequest> for CheckLoginMiddleware<S>
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
{
|
||||
type Response = ServiceResponse<EitherBody<B>>;
|
||||
type Error = Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
dev::forward_ready!(service);
|
||||
|
||||
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));
|
||||
|
||||
Box::pin(async move {
|
||||
// Don't forward to /login if we are already on /login
|
||||
if is_logged_in || request.path() == "/login" {
|
||||
svc_response.await.map(ServiceResponse::map_into_left_body)
|
||||
} else {
|
||||
let response = HttpResponse::Found()
|
||||
.insert_header((http::header::LOCATION, "/login"))
|
||||
.finish()
|
||||
.map_into_right_body();
|
||||
|
||||
Ok(ServiceResponse::new(request, response))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
63
middleware/middleware/src/simple.rs
Normal file
63
middleware/middleware/src/simple.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use std::future::{ready, Ready};
|
||||
|
||||
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
|
||||
// next service in chain as parameter.
|
||||
// 2. Middleware's call method gets called with normal request.
|
||||
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, ServiceRequest> for SayHi
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = SayHiMiddleware<S>;
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
ready(Ok(SayHiMiddleware { service }))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SayHiMiddleware<S> {
|
||||
service: S,
|
||||
}
|
||||
|
||||
impl<S, B> Service<ServiceRequest> for SayHiMiddleware<S>
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
dev::forward_ready!(service);
|
||||
|
||||
fn call(&self, req: ServiceRequest) -> Self::Future {
|
||||
println!("Hi from start. You requested: {}", req.path());
|
||||
|
||||
let fut = self.service.call(req);
|
||||
|
||||
Box::pin(async move {
|
||||
let res = fut.await?;
|
||||
|
||||
println!("Hi from response");
|
||||
Ok(res)
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user