actix_web_lab/
redirect.rs1#![allow(deprecated)]
4
5use std::{borrow::Cow, future::ready};
6
7use actix_web::{
8 dev::{fn_service, AppService, HttpServiceFactory, ResourceDef, ServiceRequest},
9 http::{header::LOCATION, StatusCode},
10 HttpRequest, HttpResponse, Responder,
11};
12use tracing::debug;
13
14#[deprecated(since = "0.19.0", note = "Type has graduated to Actix Web.")]
40#[derive(Debug, Clone)]
41pub struct Redirect {
42 from: Cow<'static, str>,
43 to: Cow<'static, str>,
44 status_code: StatusCode,
45}
46
47impl Redirect {
48 pub fn new(from: impl Into<Cow<'static, str>>, to: impl Into<Cow<'static, str>>) -> Self {
67 Self {
68 from: from.into(),
69 to: to.into(),
70 status_code: StatusCode::TEMPORARY_REDIRECT,
71 }
72 }
73
74 pub fn to(to: impl Into<Cow<'static, str>>) -> Self {
78 Self {
79 from: "/".into(),
80 to: to.into(),
81 status_code: StatusCode::TEMPORARY_REDIRECT,
82 }
83 }
84
85 pub fn permanent(self) -> Self {
91 self.using_status_code(StatusCode::PERMANENT_REDIRECT)
92 }
93
94 pub fn temporary(self) -> Self {
100 self.using_status_code(StatusCode::TEMPORARY_REDIRECT)
101 }
102
103 pub fn using_status_code(mut self, status: StatusCode) -> Self {
119 self.status_code = status;
120 self
121 }
122}
123
124impl HttpServiceFactory for Redirect {
125 fn register(self, config: &mut AppService) {
126 let redirect = self.clone();
127 let rdef = ResourceDef::new(self.from.into_owned());
128 let redirect_factory = fn_service(move |mut req: ServiceRequest| {
129 let res = redirect.clone().respond_to(req.parts_mut().0);
130 ready(Ok(req.into_response(res.map_into_boxed_body())))
131 });
132
133 config.register_service(rdef, None, redirect_factory, None)
134 }
135}
136
137impl Responder for Redirect {
138 type Body = ();
139
140 fn respond_to(self, _req: &HttpRequest) -> HttpResponse<Self::Body> {
141 let mut res = HttpResponse::with_body(self.status_code, ());
142
143 if let Ok(hdr_val) = self.to.parse() {
144 res.headers_mut().insert(LOCATION, hdr_val);
145 } else {
146 debug!(
147 "redirect target location can not be converted to header value: {:?}",
148 self.to
149 );
150 }
151
152 res
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use actix_web::{dev::Service, http::StatusCode, test, App};
159
160 use super::*;
161
162 #[actix_web::test]
163 async fn absolute_redirects() {
164 let redirector = Redirect::new("/one", "/two").permanent();
165
166 let svc = test::init_service(App::new().service(redirector)).await;
167
168 let req = test::TestRequest::default().uri("/one").to_request();
169 let res = svc.call(req).await.unwrap();
170 assert_eq!(res.status(), StatusCode::from_u16(308).unwrap());
171 let hdr = res.headers().get(&LOCATION).unwrap();
172 assert_eq!(hdr.to_str().unwrap(), "/two");
173 }
174
175 #[actix_web::test]
176 async fn relative_redirects() {
177 let redirector = Redirect::new("/one", "two").permanent();
178
179 let svc = test::init_service(App::new().service(redirector)).await;
180
181 let req = test::TestRequest::default().uri("/one").to_request();
182 let res = svc.call(req).await.unwrap();
183 assert_eq!(res.status(), StatusCode::from_u16(308).unwrap());
184 let hdr = res.headers().get(&LOCATION).unwrap();
185 assert_eq!(hdr.to_str().unwrap(), "two");
186 }
187
188 #[actix_web::test]
189 async fn temporary_redirects() {
190 let external_service = Redirect::new("/external", "https://duck.com");
191
192 let svc = test::init_service(App::new().service(external_service)).await;
193
194 let req = test::TestRequest::default().uri("/external").to_request();
195 let res = svc.call(req).await.unwrap();
196 assert_eq!(res.status(), StatusCode::from_u16(307).unwrap());
197 let hdr = res.headers().get(&LOCATION).unwrap();
198 assert_eq!(hdr.to_str().unwrap(), "https://duck.com");
199 }
200
201 #[actix_web::test]
202 async fn as_responder() {
203 let responder = Redirect::to("https://duck.com");
204
205 let req = test::TestRequest::default().to_http_request();
206 let res = responder.respond_to(&req);
207
208 assert_eq!(res.status(), StatusCode::from_u16(307).unwrap());
209 let hdr = res.headers().get(&LOCATION).unwrap();
210 assert_eq!(hdr.to_str().unwrap(), "https://duck.com");
211 }
212}