rama_http/layer/forwarded/
set_forwarded.rs1use crate::Request;
2use crate::headers::HeaderMapExt;
3use crate::headers::forwarded::{
4 ForwardHeader, Via, XForwardedFor, XForwardedHost, XForwardedProto,
5};
6use rama_core::error::{BoxError, BoxErrorExt as _, ErrorContext as _};
7use rama_core::extensions::ExtensionsRef;
8use rama_core::{Layer, Service};
9use rama_http_headers::forwarded::Forwarded;
10use rama_net::address::Domain;
11use rama_net::forwarded::{ForwardedElement, NodeId};
12use rama_net::stream::SocketInfo;
13use rama_net::{AuthorityInputExt, Protocol, ProtocolInputExt};
14use std::fmt;
15use std::marker::PhantomData;
16
17pub struct SetForwardedHeaderLayer<T = Forwarded> {
92 by_node: NodeId,
93 _headers: PhantomData<fn() -> T>,
94}
95
96impl<T> fmt::Debug for SetForwardedHeaderLayer<T> {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 f.debug_struct("SetForwardedHeaderLayer")
99 .field("by_node", &self.by_node)
100 .field(
101 "_headers",
102 &format_args!("{}", std::any::type_name::<fn() -> T>()),
103 )
104 .finish()
105 }
106}
107
108impl<T> Clone for SetForwardedHeaderLayer<T> {
109 fn clone(&self) -> Self {
110 Self {
111 by_node: self.by_node.clone(),
112 _headers: PhantomData,
113 }
114 }
115}
116
117impl<T> SetForwardedHeaderLayer<T> {
118 rama_utils::macros::generate_set_and_with! {
119 pub fn forward_by(mut self, node_id: impl Into<NodeId>) -> Self {
123 self.by_node = node_id.into();
124 self
125 }
126 }
127}
128
129impl<T> SetForwardedHeaderLayer<T> {
130 #[must_use]
132 pub fn new() -> Self {
133 Self {
134 by_node: Domain::from_static("rama").into(),
135 _headers: PhantomData,
136 }
137 }
138}
139
140impl Default for SetForwardedHeaderLayer {
141 fn default() -> Self {
142 Self::forwarded()
143 }
144}
145
146impl SetForwardedHeaderLayer {
147 #[inline]
148 #[must_use]
150 pub fn forwarded() -> Self {
151 Self::new()
152 }
153}
154
155impl SetForwardedHeaderLayer<Via> {
156 #[inline]
157 #[must_use]
159 pub fn via() -> Self {
160 Self::new()
161 }
162}
163
164impl SetForwardedHeaderLayer<XForwardedFor> {
165 #[inline]
166 #[must_use]
168 pub fn x_forwarded_for() -> Self {
169 Self::new()
170 }
171}
172
173impl SetForwardedHeaderLayer<XForwardedHost> {
174 #[inline]
175 #[must_use]
177 pub fn x_forwarded_host() -> Self {
178 Self::new()
179 }
180}
181
182impl SetForwardedHeaderLayer<XForwardedProto> {
183 #[inline]
184 #[must_use]
186 pub fn x_forwarded_proto() -> Self {
187 Self::new()
188 }
189}
190
191impl<H, S> Layer<S> for SetForwardedHeaderLayer<H> {
192 type Service = SetForwardedHeaderService<S, H>;
193
194 fn layer(&self, inner: S) -> Self::Service {
195 Self::Service {
196 inner,
197 by_node: self.by_node.clone(),
198 _headers: PhantomData,
199 }
200 }
201
202 fn into_layer(self, inner: S) -> Self::Service {
203 Self::Service {
204 inner,
205 by_node: self.by_node,
206 _headers: PhantomData,
207 }
208 }
209}
210
211pub struct SetForwardedHeaderService<S, T = Forwarded> {
216 inner: S,
217 by_node: NodeId,
218 _headers: PhantomData<fn() -> T>,
219}
220
221impl<S: fmt::Debug, T> fmt::Debug for SetForwardedHeaderService<S, T> {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 f.debug_struct("SetForwardedHeaderService")
224 .field("inner", &self.inner)
225 .field("by_node", &self.by_node)
226 .field(
227 "_headers",
228 &format_args!("{}", std::any::type_name::<fn() -> T>()),
229 )
230 .finish()
231 }
232}
233
234impl<S: Clone, T> Clone for SetForwardedHeaderService<S, T> {
235 fn clone(&self) -> Self {
236 Self {
237 inner: self.inner.clone(),
238 by_node: self.by_node.clone(),
239 _headers: PhantomData,
240 }
241 }
242}
243
244impl<S, T> SetForwardedHeaderService<S, T> {
245 rama_utils::macros::generate_set_and_with! {
246 pub fn forward_by(mut self, node_id: impl Into<NodeId>) -> Self {
250 self.by_node = node_id.into();
251 self
252 }
253 }
254}
255
256impl<S, T> SetForwardedHeaderService<S, T> {
257 pub fn new(inner: S) -> Self {
259 Self {
260 inner,
261 by_node: Domain::from_static("rama").into(),
262 _headers: PhantomData,
263 }
264 }
265}
266
267impl<S> SetForwardedHeaderService<S> {
268 #[inline]
269 pub fn forwarded(inner: S) -> Self {
271 Self::new(inner)
272 }
273}
274
275impl<S> SetForwardedHeaderService<S, Via> {
276 #[inline]
277 pub fn via(inner: S) -> Self {
279 Self::new(inner)
280 }
281}
282
283impl<S> SetForwardedHeaderService<S, XForwardedFor> {
284 #[inline]
285 pub fn x_forwarded_for(inner: S) -> Self {
287 Self::new(inner)
288 }
289}
290
291impl<S> SetForwardedHeaderService<S, XForwardedHost> {
292 #[inline]
293 pub fn x_forwarded_host(inner: S) -> Self {
295 Self::new(inner)
296 }
297}
298
299impl<S> SetForwardedHeaderService<S, XForwardedProto> {
300 #[inline]
301 pub fn x_forwarded_proto(inner: S) -> Self {
303 Self::new(inner)
304 }
305}
306
307impl<S, H, Body> Service<Request<Body>> for SetForwardedHeaderService<S, H>
308where
309 S: Service<Request<Body>, Error: Into<BoxError>>,
310 H: ForwardHeader + Send + Sync + 'static,
311 Body: Send + 'static,
312{
313 type Output = S::Output;
314 type Error = BoxError;
315
316 async fn serve(&self, mut req: Request<Body>) -> Result<Self::Output, Self::Error> {
317 let forwarded: Option<rama_net::forwarded::Forwarded> = req.extensions().get_ref().cloned();
318
319 let mut forwarded_element = ForwardedElement::new_forwarded_by(self.by_node.clone());
320
321 if let Some(peer_addr) = req
322 .extensions()
323 .get_ref::<SocketInfo>()
324 .map(|socket| socket.peer_addr())
325 {
326 forwarded_element.set_forwarded_for(peer_addr);
327 }
328 let authority = req
329 .authority()
330 .ok_or_else(|| BoxError::from_static_str("set forwarded: no authority"))?;
331
332 forwarded_element.set_forwarded_host(authority);
333
334 let protocol = req.protocol().unwrap_or(&Protocol::HTTP);
335 if let Ok(forwarded_proto) = protocol.try_into() {
336 forwarded_element.set_forwarded_proto(forwarded_proto);
337 }
338
339 let forwarded = match forwarded {
340 None => Some(rama_net::forwarded::Forwarded::new(forwarded_element)),
341 Some(mut forwarded) => {
342 forwarded.append(forwarded_element);
343 Some(forwarded)
344 }
345 };
346
347 if let Some(forwarded) = forwarded
348 && let Some(header) = H::try_from_forwarded(forwarded.iter())
349 {
350 req.headers_mut().typed_insert(header);
351 }
352
353 self.inner.serve(req).await.into_box_error()
354 }
355}
356
357#[cfg(test)]
358mod tests {
359 use super::*;
360 use crate::{
361 Response, StatusCode,
362 headers::forwarded::{TrueClientIp, XRealIp},
363 service::web::response::IntoResponse,
364 };
365 use rama_core::{Layer, error::BoxError, extensions::ExtensionsRef, service::service_fn};
366 use std::{convert::Infallible, net::IpAddr};
367
368 fn assert_is_service<T: Service<Request<()>>>(_: T) {}
369
370 async fn dummy_service_fn() -> Result<Response, BoxError> {
371 Ok(StatusCode::OK.into_response())
372 }
373
374 #[test]
375 fn test_set_forwarded_service_is_service() {
376 assert_is_service(SetForwardedHeaderService::forwarded(service_fn(
377 dummy_service_fn,
378 )));
379 assert_is_service(SetForwardedHeaderService::via(service_fn(dummy_service_fn)));
380 assert_is_service(SetForwardedHeaderService::x_forwarded_for(service_fn(
381 dummy_service_fn,
382 )));
383 assert_is_service(SetForwardedHeaderService::x_forwarded_proto(service_fn(
384 dummy_service_fn,
385 )));
386 assert_is_service(SetForwardedHeaderService::x_forwarded_host(service_fn(
387 dummy_service_fn,
388 )));
389 assert_is_service(SetForwardedHeaderService::<_, TrueClientIp>::new(
390 service_fn(dummy_service_fn),
391 ));
392 assert_is_service(SetForwardedHeaderLayer::via().into_layer(service_fn(dummy_service_fn)));
393 assert_is_service(
394 SetForwardedHeaderLayer::<XRealIp>::new().into_layer(service_fn(dummy_service_fn)),
395 );
396 }
397
398 #[tokio::test]
399 async fn test_set_forwarded_service_forwarded() {
400 async fn svc(request: Request<()>) -> Result<(), Infallible> {
401 assert_eq!(
402 request.headers().get("Forwarded").unwrap(),
403 "by=rama;host=\"example.com:80\";proto=http"
404 );
405 Ok(())
406 }
407
408 let service = SetForwardedHeaderService::forwarded(service_fn(svc));
409 let req = Request::builder()
410 .uri("http://example.com")
411 .body(())
412 .unwrap();
413 service.serve(req).await.unwrap();
414 }
415
416 #[tokio::test]
417 async fn test_set_forwarded_service_forwarded_with_chain() {
418 async fn svc(request: Request<()>) -> Result<(), Infallible> {
419 assert_eq!(
420 request.headers().get("Forwarded").unwrap(),
421 "for=12.23.34.45,by=rama;for=\"127.0.0.1:62345\";host=\"www.example.com:443\";proto=https",
422 );
423 Ok(())
424 }
425
426 let service = SetForwardedHeaderService::forwarded(service_fn(svc));
427 let req = Request::builder()
428 .uri("https://www.example.com")
429 .body(())
430 .unwrap();
431 req.extensions().insert(rama_net::forwarded::Forwarded::new(
432 ForwardedElement::new_forwarded_for(IpAddr::from([12, 23, 34, 45])),
433 ));
434 req.extensions()
435 .insert(SocketInfo::new(None, "127.0.0.1:62345".parse().unwrap()));
436 service.serve(req).await.unwrap();
437 }
438
439 #[tokio::test]
440 async fn test_set_forwarded_service_x_forwarded_for_with_chain() {
441 async fn svc(request: Request<()>) -> Result<(), Infallible> {
442 assert_eq!(
443 request.headers().get("X-Forwarded-For").unwrap(),
444 "12.23.34.45, 127.0.0.1",
445 );
446 Ok(())
447 }
448
449 let service = SetForwardedHeaderService::x_forwarded_for(service_fn(svc));
450 let req = Request::builder()
451 .uri("https://www.example.com")
452 .body(())
453 .unwrap();
454 req.extensions().insert(rama_net::forwarded::Forwarded::new(
455 ForwardedElement::new_forwarded_for(IpAddr::from([12, 23, 34, 45])),
456 ));
457 req.extensions()
458 .insert(SocketInfo::new(None, "127.0.0.1:62345".parse().unwrap()));
459 service.serve(req).await.unwrap();
460 }
461
462 #[tokio::test]
463 async fn test_set_forwarded_service_forwarded_fully_defined() {
464 async fn svc(request: Request<()>) -> Result<(), Infallible> {
465 assert_eq!(
466 request.headers().get("Forwarded").unwrap(),
467 "by=12.23.34.45;for=\"127.0.0.1:62345\";host=\"www.example.com:443\";proto=https",
468 );
469 Ok(())
470 }
471
472 let service = SetForwardedHeaderService::forwarded(service_fn(svc))
473 .with_forward_by(IpAddr::from([12, 23, 34, 45]));
474 let req = Request::builder()
475 .uri("https://www.example.com")
476 .body(())
477 .unwrap();
478 req.extensions()
479 .insert(SocketInfo::new(None, "127.0.0.1:62345".parse().unwrap()));
480 service.serve(req).await.unwrap();
481 }
482
483 #[tokio::test]
484 async fn test_set_forwarded_service_forwarded_fully_defined_with_chain() {
485 async fn svc(request: Request<()>) -> Result<(), Infallible> {
486 assert_eq!(
487 request.headers().get("Forwarded").unwrap(),
488 "by=rama;for=\"127.0.0.1:62345\";host=\"www.example.com:443\";proto=https",
489 );
490 Ok(())
491 }
492
493 let service = SetForwardedHeaderService::forwarded(service_fn(svc));
494 let req = Request::builder()
495 .uri("https://www.example.com")
496 .body(())
497 .unwrap();
498 req.extensions()
499 .insert(SocketInfo::new(None, "127.0.0.1:62345".parse().unwrap()));
500 service.serve(req).await.unwrap();
501 }
502}