1use actix_http::{header, uri::Uri, RequestHead, Version};
2
3use super::{Guard, GuardContext};
4
5#[allow(non_snake_case)]
58pub fn Host(host: impl AsRef<str>) -> HostGuard {
59 HostGuard {
60 host: host.as_ref().to_string(),
61 scheme: None,
62 }
63}
64
65fn get_host_uri(req: &RequestHead) -> Option<Uri> {
66 req.headers
67 .get(header::HOST)
68 .and_then(|host_value| host_value.to_str().ok())
69 .filter(|_| req.version < Version::HTTP_2)
70 .or_else(|| req.uri.host())
71 .and_then(|host| host.parse().ok())
72}
73
74#[doc(hidden)]
75pub struct HostGuard {
76 host: String,
77 scheme: Option<String>,
78}
79
80impl HostGuard {
81 pub fn scheme<H: AsRef<str>>(mut self, scheme: H) -> HostGuard {
83 self.scheme = Some(scheme.as_ref().to_string());
84 self
85 }
86}
87
88impl Guard for HostGuard {
89 fn check(&self, ctx: &GuardContext<'_>) -> bool {
90 let req_host_uri = match get_host_uri(ctx.head()) {
92 Some(uri) => uri,
93
94 None => return false,
96 };
97
98 match req_host_uri.host() {
99 Some(uri_host) if self.host == uri_host => {}
101
102 _ => return false,
106 }
107
108 if let Some(ref scheme) = self.scheme {
109 if let Some(ref req_host_uri_scheme) = req_host_uri.scheme_str() {
110 return scheme == req_host_uri_scheme;
111 }
112
113 }
116
117 true
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use crate::test::TestRequest;
126
127 #[test]
128 fn host_not_from_header_if_http2() {
129 let req = TestRequest::default()
130 .uri("www.rust-lang.org")
131 .insert_header((
132 header::HOST,
133 header::HeaderValue::from_static("www.example.com"),
134 ))
135 .to_srv_request();
136
137 let host = Host("www.example.com");
138 assert!(host.check(&req.guard_ctx()));
139
140 let host = Host("www.rust-lang.org");
141 assert!(!host.check(&req.guard_ctx()));
142
143 let req = TestRequest::default()
144 .version(actix_http::Version::HTTP_2)
145 .uri("www.rust-lang.org")
146 .insert_header((
147 header::HOST,
148 header::HeaderValue::from_static("www.example.com"),
149 ))
150 .to_srv_request();
151
152 let host = Host("www.example.com");
153 assert!(!host.check(&req.guard_ctx()));
154
155 let host = Host("www.rust-lang.org");
156 assert!(host.check(&req.guard_ctx()));
157 }
158
159 #[test]
160 fn host_from_header() {
161 let req = TestRequest::default()
162 .insert_header((
163 header::HOST,
164 header::HeaderValue::from_static("www.rust-lang.org"),
165 ))
166 .to_srv_request();
167
168 let host = Host("www.rust-lang.org");
169 assert!(host.check(&req.guard_ctx()));
170
171 let host = Host("www.rust-lang.org").scheme("https");
172 assert!(host.check(&req.guard_ctx()));
173
174 let host = Host("blog.rust-lang.org");
175 assert!(!host.check(&req.guard_ctx()));
176
177 let host = Host("blog.rust-lang.org").scheme("https");
178 assert!(!host.check(&req.guard_ctx()));
179
180 let host = Host("crates.io");
181 assert!(!host.check(&req.guard_ctx()));
182
183 let host = Host("localhost");
184 assert!(!host.check(&req.guard_ctx()));
185 }
186
187 #[test]
188 fn host_without_header() {
189 let req = TestRequest::default()
190 .uri("www.rust-lang.org")
191 .to_srv_request();
192
193 let host = Host("www.rust-lang.org");
194 assert!(host.check(&req.guard_ctx()));
195
196 let host = Host("www.rust-lang.org").scheme("https");
197 assert!(host.check(&req.guard_ctx()));
198
199 let host = Host("blog.rust-lang.org");
200 assert!(!host.check(&req.guard_ctx()));
201
202 let host = Host("blog.rust-lang.org").scheme("https");
203 assert!(!host.check(&req.guard_ctx()));
204
205 let host = Host("crates.io");
206 assert!(!host.check(&req.guard_ctx()));
207
208 let host = Host("localhost");
209 assert!(!host.check(&req.guard_ctx()));
210 }
211
212 #[test]
213 fn host_scheme() {
214 let req = TestRequest::default()
215 .insert_header((
216 header::HOST,
217 header::HeaderValue::from_static("https://www.rust-lang.org"),
218 ))
219 .to_srv_request();
220
221 let host = Host("www.rust-lang.org").scheme("https");
222 assert!(host.check(&req.guard_ctx()));
223
224 let host = Host("www.rust-lang.org");
225 assert!(host.check(&req.guard_ctx()));
226
227 let host = Host("www.rust-lang.org").scheme("http");
228 assert!(!host.check(&req.guard_ctx()));
229
230 let host = Host("blog.rust-lang.org");
231 assert!(!host.check(&req.guard_ctx()));
232
233 let host = Host("blog.rust-lang.org").scheme("https");
234 assert!(!host.check(&req.guard_ctx()));
235
236 let host = Host("crates.io").scheme("https");
237 assert!(!host.check(&req.guard_ctx()));
238
239 let host = Host("localhost");
240 assert!(!host.check(&req.guard_ctx()));
241 }
242}