actix_web_middleware_redirect_scheme/
service.rs

1use actix_service::Service;
2use actix_web::{
3    dev::{ServiceRequest, ServiceResponse},
4    http, Error, HttpResponse,
5};
6use futures::future::{ok, Either, Ready};
7use std::task::{Context, Poll};
8
9pub struct RedirectSchemeService<S> {
10    pub service: S,
11    pub disable: bool,
12    pub https_to_http: bool,
13    pub temporary: bool,
14    pub replacements: Vec<(String, String)>,
15}
16
17type ReadyResult<R, E> = Ready<Result<R, E>>;
18
19impl<S, B> Service for RedirectSchemeService<S>
20where
21    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
22    S::Future: 'static,
23{
24    type Request = ServiceRequest;
25    type Response = ServiceResponse<B>;
26    type Error = Error;
27    type Future = Either<S::Future, ReadyResult<Self::Response, Self::Error>>;
28
29    fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
30        self.service.poll_ready(cx)
31    }
32
33    fn call(&mut self, req: ServiceRequest) -> Self::Future {
34        if self.disable
35            || (!self.https_to_http && req.connection_info().scheme() == "https")
36            || (self.https_to_http && req.connection_info().scheme() == "http")
37        {
38            Either::Left(self.service.call(req))
39        } else {
40            let host = req.connection_info().host().to_owned();
41            let uri = req.uri().to_owned();
42            let mut url = if self.https_to_http {
43                format!("http://{}{}", host, uri)
44            } else {
45                format!("https://{}{}", host, uri)
46            };
47            for (s1, s2) in self.replacements.iter() {
48                url = url.replace(s1, s2);
49            }
50            Either::Right(ok(req.into_response(
51                if self.temporary {
52                    HttpResponse::TemporaryRedirect()
53                } else {
54                    HttpResponse::MovedPermanently()
55                }
56                .header(http::header::LOCATION, url)
57                .finish()
58                .into_body(),
59            )))
60        }
61    }
62}