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