mirror of
https://github.com/actix/examples
synced 2025-06-26 17:17:42 +02:00
restructure folders
This commit is contained in:
@ -1 +0,0 @@
|
||||
Dockerfile
|
@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "docker_sample"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.0.0-beta.21"
|
||||
env_logger = "0.9"
|
||||
log = "0.4"
|
@ -1,38 +0,0 @@
|
||||
# NB: This is not a production-grade Dockerfile.
|
||||
|
||||
#################
|
||||
## build stage ##
|
||||
#################
|
||||
FROM rust:1-slim-bullseye AS builder
|
||||
WORKDIR /code
|
||||
|
||||
# Download crates-io index and fetch dependency code.
|
||||
# This step avoids needing to spend time on every build downloading the index
|
||||
# which can take a long time within the docker context. Docker will cache it.
|
||||
RUN USER=root cargo init
|
||||
COPY Cargo.toml Cargo.toml
|
||||
RUN cargo fetch
|
||||
|
||||
# copy app files
|
||||
COPY src src
|
||||
|
||||
# compile app
|
||||
RUN cargo build --release
|
||||
|
||||
###############
|
||||
## run stage ##
|
||||
###############
|
||||
FROM debian:bullseye-slim
|
||||
WORKDIR /app
|
||||
|
||||
# copy server binary from build stage
|
||||
COPY --from=builder /code/target/release/docker_sample docker_sample
|
||||
|
||||
# set user to non-root unless root is required for your app
|
||||
USER 1001
|
||||
|
||||
# indicate what port the server is running on
|
||||
EXPOSE 8080
|
||||
|
||||
# run server
|
||||
CMD [ "/app/docker_sample" ]
|
@ -1,22 +0,0 @@
|
||||
# Docker sample
|
||||
|
||||
## Build image
|
||||
|
||||
```shell
|
||||
docker build -t docker_sample .
|
||||
```
|
||||
|
||||
## Run built image
|
||||
|
||||
```shell
|
||||
docker run -d -p 8080:8080 docker_sample
|
||||
# and the server should start instantly
|
||||
curl http://localhost:8080
|
||||
```
|
||||
|
||||
## Running unit tests
|
||||
|
||||
```shell
|
||||
docker build -t docker_sample:test .
|
||||
docker run --rm docker_sample:test
|
||||
```
|
@ -1,28 +0,0 @@
|
||||
use actix_web::{get, middleware::Logger, App, HttpResponse, HttpServer, Responder};
|
||||
|
||||
#[get("/")]
|
||||
async fn index() -> impl Responder {
|
||||
HttpResponse::Ok().body("Hello world!")
|
||||
}
|
||||
|
||||
#[get("/again")]
|
||||
async fn again() -> impl Responder {
|
||||
HttpResponse::Ok().body("Hello world again!")
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
|
||||
log::info!("Starting HTTP server: go to http://localhost:8080");
|
||||
|
||||
HttpServer::new(|| {
|
||||
App::new()
|
||||
.wrap(Logger::default())
|
||||
.service(index)
|
||||
.service(again)
|
||||
})
|
||||
.bind(("0.0.0.0", 8080))?
|
||||
.run()
|
||||
.await
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
[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"
|
@ -1,18 +0,0 @@
|
||||
# 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
|
@ -1,77 +0,0 @@
|
||||
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,
|
||||
}))
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
[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"
|
@ -1,12 +0,0 @@
|
||||
## 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 +0,0 @@
|
||||
cert.pem
|
@ -1 +0,0 @@
|
||||
key.pem
|
@ -1,72 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
[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"
|
@ -1,32 +0,0 @@
|
||||
# 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.
|
@ -1,42 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
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))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
[package]
|
||||
name = "shutdown-server"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
description = "Send a request to the server to shut it down"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.0.0-rc.1"
|
||||
env_logger = "0.9"
|
||||
futures = "0.3"
|
||||
tokio = { version = "1.16", features = ["signal"] }
|
@ -1,27 +0,0 @@
|
||||
# shutdown-server
|
||||
|
||||
Demonstrates how to shutdown the web server in a couple of ways:
|
||||
|
||||
1. remotely, via http request
|
||||
- Created in response to actix/actix-web#1315
|
||||
1. sending a SIGINT signal to the server (control-c)
|
||||
- actix-server natively supports SIGINT
|
||||
|
||||
## Usage
|
||||
|
||||
### Running The Server
|
||||
|
||||
```bash
|
||||
cd basics/shutdown-server
|
||||
cargo run --bin shutdown-server
|
||||
|
||||
# Starting 8 workers
|
||||
# Starting "actix-web-service-127.0.0.1:8080" service on 127.0.0.1:8080
|
||||
```
|
||||
|
||||
### Available Routes
|
||||
|
||||
- [GET /hello](http://localhost:8080/hello)
|
||||
- Regular hello world route
|
||||
- [POST /stop](http://localhost:8080/stop)
|
||||
- Calling this will shutdown the server and exit
|
@ -1,52 +0,0 @@
|
||||
use actix_web::{get, middleware, post, web, App, HttpResponse, HttpServer};
|
||||
use futures::executor;
|
||||
use std::{sync::mpsc, thread};
|
||||
|
||||
#[get("/hello")]
|
||||
async fn hello() -> &'static str {
|
||||
"Hello world!"
|
||||
}
|
||||
|
||||
#[post("/stop")]
|
||||
async fn stop(stopper: web::Data<mpsc::Sender<()>>) -> HttpResponse {
|
||||
// make request that sends message through the Sender
|
||||
stopper.send(()).unwrap();
|
||||
|
||||
HttpResponse::NoContent().finish()
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
std::env::set_var("RUST_LOG", "actix_server=debug,actix_web=debug");
|
||||
env_logger::init();
|
||||
|
||||
// create a channel
|
||||
let (tx, rx) = mpsc::channel::<()>();
|
||||
|
||||
let bind = ("127.0.0.1", 8080);
|
||||
|
||||
// start server as normal but don't .await after .run() yet
|
||||
let server = HttpServer::new(move || {
|
||||
// give the server a Sender in .data
|
||||
App::new()
|
||||
.app_data(web::Data::new(tx.clone()))
|
||||
.wrap(middleware::Logger::default())
|
||||
.service(hello)
|
||||
.service(stop)
|
||||
})
|
||||
.bind(&bind)?
|
||||
.run();
|
||||
|
||||
// clone the Server handle
|
||||
let srv = server.handle();
|
||||
thread::spawn(move || {
|
||||
// wait for shutdown signal
|
||||
rx.recv().unwrap();
|
||||
|
||||
// stop server gracefully
|
||||
executor::block_on(srv.stop(true))
|
||||
});
|
||||
|
||||
// run server
|
||||
server.await
|
||||
}
|
2
basics/static_index/.gitattributes
vendored
2
basics/static_index/.gitattributes
vendored
@ -1,2 +0,0 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
@ -4,6 +4,7 @@ version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.0.0-rc.1"
|
||||
actix-web = "4.0.0-rc.3"
|
||||
actix-files = "0.6.0-beta.15"
|
||||
env_logger = "0.9.0"
|
||||
log = "0.4"
|
||||
|
@ -1,15 +1,14 @@
|
||||
use actix_files::Files;
|
||||
use actix_web::{middleware, App, HttpServer};
|
||||
use actix_web::{middleware::Logger, App, HttpServer};
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
std::env::set_var("RUST_LOG", "actix_web=info");
|
||||
env_logger::init();
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
|
||||
log::info!("starting HTTP server at http://localhost:8080");
|
||||
|
||||
HttpServer::new(|| {
|
||||
App::new()
|
||||
// Enable the logger.
|
||||
.wrap(middleware::Logger::default())
|
||||
// We allow the visitor to see an index of the images at `/images`.
|
||||
.service(Files::new("/images", "static/images/").show_files_listing())
|
||||
// Serve a tree of static files at the web root and specify the index file.
|
||||
@ -17,6 +16,8 @@ async fn main() -> std::io::Result<()> {
|
||||
// resolved in the order they are defined. If this would be placed before the `/images`
|
||||
// path then the service for the static images would never be reached.
|
||||
.service(Files::new("/", "./static/root/").index_file("index.html"))
|
||||
// Enable the logger.
|
||||
.wrap(Logger::default())
|
||||
})
|
||||
.bind(("127.0.0.1", 8080))?
|
||||
.run()
|
||||
|
Reference in New Issue
Block a user