actix_web_lab/
redirect_to_www.rs1use actix_web::{
2 body::MessageBody,
3 dev::{ServiceRequest, ServiceResponse},
4 web::Redirect,
5 Error, Responder,
6};
7
8use crate::middleware_from_fn::Next;
9
10pub async fn redirect_to_www(
21 req: ServiceRequest,
22 next: Next<impl MessageBody + 'static>,
23) -> Result<ServiceResponse<impl MessageBody>, Error> {
24 #![allow(clippy::await_holding_refcell_ref)] let (req, pl) = req.into_parts();
27 let conn_info = req.connection_info();
28
29 if !conn_info.host().starts_with("www.") {
30 let scheme = conn_info.scheme();
31 let host = conn_info.host();
32 let path = req.uri().path();
33 let uri = format!("{scheme}://www.{host}{path}");
34
35 let res = Redirect::to(uri).respond_to(&req);
36
37 drop(conn_info);
38 return Ok(ServiceResponse::new(req, res).map_into_right_body());
39 }
40
41 drop(conn_info);
42 let req = ServiceRequest::from_parts(req, pl);
43 Ok(next.call(req).await?.map_into_left_body())
44}
45
46#[cfg(test)]
47mod test_super {
48 use actix_web::{
49 dev::ServiceFactory,
50 http::{header, StatusCode},
51 test, web, App, HttpResponse,
52 };
53
54 use super::*;
55 use crate::middleware::from_fn;
56
57 fn test_app() -> App<
58 impl ServiceFactory<
59 ServiceRequest,
60 Response = ServiceResponse<impl MessageBody>,
61 Config = (),
62 InitError = (),
63 Error = Error,
64 >,
65 > {
66 App::new().wrap(from_fn(redirect_to_www)).route(
67 "/",
68 web::get().to(|| async { HttpResponse::Ok().body("content") }),
69 )
70 }
71
72 #[actix_web::test]
73 async fn redirect_non_www() {
74 let app = test::init_service(test_app()).await;
75
76 let req = test::TestRequest::default().to_request();
77 let res = test::call_service(&app, req).await;
78 assert_eq!(res.status(), StatusCode::TEMPORARY_REDIRECT);
79
80 let loc = res.headers().get(header::LOCATION);
81 assert!(loc.is_some());
82 assert!(loc.unwrap().as_bytes().starts_with(b"http://www"));
83
84 let body = test::read_body(res).await;
85 assert!(body.is_empty());
86 }
87
88 #[actix_web::test]
89 async fn do_not_redirect_already_www() {
90 let app = test::init_service(test_app()).await;
91
92 let req = test::TestRequest::default()
93 .uri("http://www.localhost/")
94 .to_request();
95 let res = test::call_service(&app, req).await;
96 assert_eq!(res.status(), StatusCode::OK);
97
98 let loc = res.headers().get(header::LOCATION);
99 assert!(loc.is_none());
100
101 let body = test::read_body(res).await;
102 assert_eq!(body, "content");
103 }
104}