trusted_proxies/
trusted.rs

1use crate::extract::RequestInformation;
2use crate::Config;
3use core::net::IpAddr;
4
5/// Trusted data extracted from a request
6///
7/// Values returned by this struct are trusted and can be used to determine the real client information,
8/// given your configuration.
9///
10/// # Example
11/// ```
12/// use trusted_proxies::{Config, Trusted};
13///
14/// let config = Config::new_local();
15/// let mut request = http::Request::get("/").body(()).unwrap();
16/// request.headers_mut().insert(http::header::FORWARDED, "for=1.2.3.4; proto=https; by=myproxy; host=mydomain.com:8080".parse().unwrap());
17/// let socket_ip_addr = core::net::IpAddr::from([127, 0, 0, 1]);
18///
19/// let trusted = Trusted::from(socket_ip_addr, &request, &config);
20///
21/// assert_eq!(trusted.scheme(), Some("https"));
22/// assert_eq!(trusted.host(), Some("mydomain.com"));
23/// assert_eq!(trusted.port(), Some(8080));
24/// assert_eq!(trusted.ip(), core::net::IpAddr::from([1, 2, 3, 4]));
25/// ```
26#[derive(Debug, Clone)]
27pub enum Trusted<'a> {
28    Borrowed(TrustedBorrowed<'a>),
29    Owned(TrustedOwned),
30}
31
32#[derive(Debug, Clone)]
33pub struct TrustedBorrowed<'a> {
34    host: Option<&'a str>,
35    scheme: Option<&'a str>,
36    by: Option<&'a str>,
37    ip: IpAddr,
38}
39
40#[derive(Debug, Clone)]
41pub struct TrustedOwned {
42    host: Option<String>,
43    scheme: Option<String>,
44    by: Option<String>,
45    ip: IpAddr,
46}
47
48/// Trim whitespace then any quote marks.
49fn unquote(val: &str) -> &str {
50    val.trim().trim_start_matches('"').trim_end_matches('"')
51}
52
53/// Remove port and IPv6 square brackets from a peer specification.
54fn bare_address(val: &str) -> &str {
55    if val.starts_with('[') {
56        val.split("]:")
57            .next()
58            .map(|s| s.trim_start_matches('[').trim_end_matches(']'))
59            // this indicates that the IPv6 address is malformed so shouldn't
60            // usually happen, but if it does, just return the original input
61            .unwrap_or(val)
62    } else {
63        val.split(':').next().unwrap_or(val)
64    }
65}
66
67impl Trusted<'_> {
68    pub fn into_owned(self) -> Trusted<'static> {
69        match self {
70            Self::Borrowed(trusted) => Trusted::Owned(TrustedOwned {
71                host: trusted.host.map(|s| s.to_string()),
72                scheme: trusted.scheme.map(|s| s.to_string()),
73                by: trusted.by.map(|s| s.to_string()),
74                ip: trusted.ip,
75            }),
76            Self::Owned(trusted) => Trusted::Owned(trusted),
77        }
78    }
79}
80
81impl<'a> Trusted<'a> {
82    /// Get the scheme of the request
83    pub fn scheme(&self) -> Option<&str> {
84        match self {
85            Self::Borrowed(trusted) => trusted.scheme,
86            Self::Owned(trusted) => trusted.scheme.as_deref(),
87        }
88    }
89
90    /// Get the host and potential port of the request
91    pub fn host_with_port(&self) -> Option<&str> {
92        match self {
93            Self::Borrowed(trusted) => trusted.host,
94            Self::Owned(trusted) => trusted.host.as_deref(),
95        }
96    }
97
98    /// Get the host of the request (without port)
99    pub fn host(&self) -> Option<&str> {
100        self.host_with_port()
101            .and_then(|host| host.split(':').next())
102    }
103
104    /// Get the port of the request
105    pub fn port(&self) -> Option<u16> {
106        self.host_with_port().and_then(|host| {
107            host.split(':')
108                .nth(1)
109                .and_then(|port| port.parse::<u16>().ok())
110        })
111    }
112
113    /// Get the proxy that forwarded the request
114    pub fn by(&self) -> Option<&str> {
115        match self {
116            Self::Borrowed(trusted) => trusted.by,
117            Self::Owned(trusted) => trusted.by.as_deref(),
118        }
119    }
120
121    /// Get first untrusted IP address from the request, which should be in most cases the real client IP address
122    pub fn ip(&self) -> IpAddr {
123        match self {
124            Self::Borrowed(trusted) => trusted.ip,
125            Self::Owned(trusted) => trusted.ip,
126        }
127    }
128
129    /// Create a new `Trusted` struct from a peer address, a request and a configuration
130    pub fn from<T: RequestInformation>(ip_addr: IpAddr, request: &'a T, config: &Config) -> Self {
131        let (trusted_host, trusted_scheme, trusted_by, trusted_ip) =
132            if !config.is_ip_trusted(&ip_addr) {
133                // if the peer address is not trusted, we can't trust the headers
134                // set the host and scheme to the server's configuration
135                (
136                    request.default_host(),
137                    request.default_scheme(),
138                    None,
139                    ip_addr,
140                )
141            } else {
142                // if the peer address is trusted, we can start to check trusted header to get correct information
143                let mut host = None;
144                let mut scheme = None;
145                let mut by = None;
146                let mut realip_remote_addr = None;
147
148                // first check the forwarded header if it is trusted
149                if config.is_forwarded_trusted {
150                    // quote from RFC 7239:
151                    // A proxy server that wants to add a new "Forwarded" header field value
152                    //    can either append it to the last existing "Forwarded" header field
153                    //    after a comma separator or add a new field at the end of the header
154                    //    block.
155                    // --- https://datatracker.ietf.org/doc/html/rfc7239#section-4
156                    // so we get the values in reverse order as we want to get the first untrusted value
157                    let forwarded_list = request
158                        .forwarded()
159                        // "for=1.2.3.4, for=5.6.7.8; scheme=https"
160                        .flat_map(|vals| vals.split(','))
161                        // ["for=1.2.3.4", "for=5.6.7.8; scheme=https"]
162                        .rev();
163
164                    'forwaded: for forwarded in forwarded_list {
165                        for (key, value) in forwarded.split(';').map(|item| {
166                            let mut kv = item.splitn(2, '=');
167
168                            (
169                                kv.next().map(|s| s.trim()).unwrap_or_default(),
170                                kv.next().map(|s| unquote(s.trim())).unwrap_or_default(),
171                            )
172                        }) {
173                            match key.to_lowercase().as_str() {
174                                "for" => {
175                                    if let Ok(ip) = bare_address(value).parse::<IpAddr>() {
176                                        realip_remote_addr = Some(ip);
177
178                                        if config.is_ip_trusted(&ip) {
179                                            host = None;
180                                            scheme = None;
181                                            by = None;
182                                            realip_remote_addr = None;
183
184                                            continue 'forwaded;
185                                        }
186                                    }
187                                }
188                                "proto" => {
189                                    scheme = Some(value);
190                                }
191                                "host" => {
192                                    host = Some(value);
193                                }
194                                "by" => {
195                                    by = Some(value);
196                                }
197                                _ => {}
198                            }
199                        }
200
201                        break;
202                    }
203                }
204
205                if realip_remote_addr.is_none() && config.is_x_forwarded_for_trusted {
206                    for value in request
207                        .x_forwarded_for()
208                        .flat_map(|vals| vals.split(','))
209                        .map(|s| s.trim())
210                        .rev()
211                    {
212                        if let Ok(ip) = bare_address(value).parse::<IpAddr>() {
213                            if config.is_ip_trusted(&ip) {
214                                continue;
215                            }
216
217                            realip_remote_addr = Some(ip);
218                        }
219
220                        break;
221                    }
222                }
223
224                if host.is_none() && config.is_x_forwarded_host_trusted {
225                    host = request
226                        .x_forwarded_host()
227                        .flat_map(|vals| vals.split(','))
228                        .map(|s| s.trim())
229                        .next_back();
230                }
231
232                if scheme.is_none() && config.is_x_forwarded_proto_trusted {
233                    scheme = request
234                        .x_forwarded_proto()
235                        .flat_map(|vals| vals.split(','))
236                        .map(|s| s.trim())
237                        .next_back();
238                }
239
240                if by.is_none() && config.is_x_forwarded_by_trusted {
241                    by = request
242                        .x_forwarded_by()
243                        .flat_map(|vals| vals.split(','))
244                        .map(|s| s.trim())
245                        .next_back();
246                }
247
248                (
249                    host.or_else(|| request.default_host()),
250                    scheme.or_else(|| request.default_scheme()),
251                    by,
252                    realip_remote_addr.unwrap_or(ip_addr),
253                )
254            };
255
256        Self::Borrowed(TrustedBorrowed {
257            host: trusted_host,
258            scheme: trusted_scheme,
259            by: trusted_by,
260            ip: trusted_ip,
261        })
262    }
263}
264
265#[cfg(all(test, feature = "http"))]
266mod tests {
267    use super::*;
268    use http::{header, Request, Version};
269
270    #[test]
271    fn default() {
272        let request = Request::get("http://localhost:8080/").body(()).unwrap();
273        let config = Config::default();
274        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
275
276        assert_eq!(trusted.scheme(), Some("http"));
277        assert_eq!(trusted.host(), Some("localhost"));
278        assert_eq!(trusted.port(), Some(8080));
279        assert_eq!(trusted.ip(), "127.0.0.1".parse::<IpAddr>().unwrap())
280    }
281
282    #[test]
283    fn host_header() {
284        let mut request = Request::get("http://localhost:8080/").body(()).unwrap();
285        request
286            .headers_mut()
287            .insert(header::HOST, "rust-lang.org:8081".parse().unwrap());
288        let config = Config::default();
289        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
290
291        assert_eq!(trusted.scheme(), Some("http"));
292        assert_eq!(trusted.host(), Some("rust-lang.org"));
293        assert_eq!(trusted.port(), Some(8081));
294        assert_eq!(trusted.ip(), "127.0.0.1".parse::<IpAddr>().unwrap());
295    }
296
297    #[test]
298    fn host_header_not_allowed() {
299        let mut request = Request::get("http://localhost:8080/").body(()).unwrap();
300        request
301            .headers_mut()
302            .insert(header::HOST, "rust-lang.org".parse().unwrap());
303        *request.version_mut() = Version::HTTP_2;
304        let config = Config::default();
305        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
306
307        assert_eq!(trusted.scheme(), Some("http"));
308        assert_eq!(trusted.host(), Some("localhost"));
309        assert_eq!(trusted.ip(), "127.0.0.1".parse::<IpAddr>().unwrap());
310    }
311
312    #[test]
313    fn x_forwarded_for_header_trusted() {
314        let mut request = Request::get("/").body(()).unwrap();
315        request.headers_mut().insert(
316            header::HeaderName::from_static("x-forwarded-for"),
317            "1.1.1.1".parse().unwrap(),
318        );
319
320        let config = Config::default();
321
322        // 192.168.2.60 is a local ip address, so it should be trusted by default
323        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
324
325        assert_eq!(trusted.ip(), "1.1.1.1".parse::<IpAddr>().unwrap());
326    }
327
328    #[test]
329    fn x_forwarded_for_header_trusted_multiple() {
330        let mut request = Request::get("/").body(()).unwrap();
331        request.headers_mut().append(
332            header::HeaderName::from_static("x-forwarded-for"),
333            "1.1.1.1".parse().unwrap(),
334        );
335        request.headers_mut().append(
336            header::HeaderName::from_static("x-forwarded-for"),
337            "8.8.8.8".parse().unwrap(),
338        );
339
340        let config = Config::default();
341
342        // 192.168.2.60 is a local ip address, so it should be trusted by default
343        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
344
345        assert_eq!(trusted.ip(), "8.8.8.8".parse::<IpAddr>().unwrap());
346
347        let mut request = Request::get("/").body(()).unwrap();
348        request.headers_mut().append(
349            header::HeaderName::from_static("x-forwarded-for"),
350            "1.1.1.1".parse().unwrap(),
351        );
352        request.headers_mut().append(
353            header::HeaderName::from_static("x-forwarded-for"),
354            "8.8.8.8".parse().unwrap(),
355        );
356
357        let mut config = Config::default();
358        config
359            .add_trusted_ip("8.8.8.8")
360            .expect("Failed to add trusted ip");
361
362        // 192.168.2.60 is a local ip address, so it should be trusted by default
363        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
364
365        assert_eq!(trusted.ip(), "1.1.1.1".parse::<IpAddr>().unwrap());
366
367        let mut request = Request::get("/").body(()).unwrap();
368        request.headers_mut().append(
369            header::HeaderName::from_static("x-forwarded-for"),
370            "1.1.1.1, 8.8.8.8".parse().unwrap(),
371        );
372
373        let config = Config::default();
374
375        // 192.168.2.60 is a local ip address, so it should be trusted by default
376        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
377
378        assert_eq!(trusted.ip(), "8.8.8.8".parse::<IpAddr>().unwrap());
379
380        let mut request = Request::get("/").body(()).unwrap();
381        request.headers_mut().append(
382            header::HeaderName::from_static("x-forwarded-for"),
383            "1.1.1.1, 8.8.8.8".parse().unwrap(),
384        );
385
386        let mut config = Config::default();
387        config
388            .add_trusted_ip("8.8.8.8")
389            .expect("Failed to add trusted ip");
390
391        // 192.168.2.60 is a local ip address, so it should be trusted by default
392        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
393
394        assert_eq!(trusted.ip(), "1.1.1.1".parse::<IpAddr>().unwrap());
395    }
396
397    #[test]
398    fn x_forwarded_for_header_untrusted() {
399        let mut request = Request::get("/").body(()).unwrap();
400        request.headers_mut().append(
401            header::HeaderName::from_static("x-forwarded-for"),
402            "8.8.8.8".parse().unwrap(),
403        );
404
405        let mut config = Config::new();
406        config
407            .add_trusted_ip("8.8.8.8")
408            .expect("Failed to add trusted ip");
409
410        // 192.168.2.60 is a local ip address, so it should be trusted by default
411        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
412
413        assert_eq!(trusted.ip(), "192.168.2.60".parse::<IpAddr>().unwrap());
414    }
415
416    #[test]
417    fn x_forwarded_host_header_trusted() {
418        let mut request = Request::get("/").body(()).unwrap();
419        request.headers_mut().append(
420            header::HeaderName::from_static("x-forwarded-host"),
421            "example.com:8080".parse().unwrap(),
422        );
423
424        let mut config = Config::default();
425        config.trust_x_forwarded_host();
426
427        // 192.168.2.60 is a local ip address, so it should be trusted by default
428        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
429
430        assert_eq!(trusted.host(), Some("example.com"));
431        assert_eq!(trusted.port(), Some(8080));
432
433        let mut request = Request::get("/").body(()).unwrap();
434        // In this cas we have multiple hosts, so we should take the last one
435        request.headers_mut().append(
436            header::HeaderName::from_static("x-forwarded-host"),
437            "first.com:1234, example.com".parse().unwrap(),
438        );
439
440        let mut config = Config::default();
441        config.trust_x_forwarded_host();
442
443        // 192.168.2.60 is a local ip address, so it should be trusted by default
444        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
445
446        assert_eq!(trusted.host(), Some("example.com"));
447        assert_eq!(trusted.port(), None);
448
449        let mut request = Request::get("/").body(()).unwrap();
450        // In this cas we have multiple hosts, so we should take the last one
451        request.headers_mut().append(
452            header::HeaderName::from_static("x-forwarded-host"),
453            "first.com, example.com".parse().unwrap(),
454        );
455
456        let mut config = Config::default();
457        config.trust_x_forwarded_host();
458
459        // 192.168.2.60 is a local ip address, so it should be trusted by default
460        let trusted = Trusted::from("1.1.1.1".parse().unwrap(), &request, &config);
461
462        assert_eq!(trusted.host(), None);
463    }
464
465    #[test]
466    fn x_forwarded_host_header_untrusted() {
467        let mut request = Request::get("/").body(()).unwrap();
468        // In this cas we have multiple hosts, so we should take the last one
469        request.headers_mut().append(
470            header::HeaderName::from_static("x-forwarded-host"),
471            "first.com, example.com".parse().unwrap(),
472        );
473
474        let config = Config::default();
475
476        // 192.168.2.60 is a local ip address, so it should be trusted by default
477        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
478
479        assert_eq!(trusted.host(), None);
480    }
481
482    #[test]
483    fn x_forwarded_proto_header_trusted() {
484        let mut request = Request::get("/").body(()).unwrap();
485        request.headers_mut().append(
486            header::HeaderName::from_static("x-forwarded-proto"),
487            "https".parse().unwrap(),
488        );
489
490        let mut config = Config::default();
491        config.trust_x_forwarded_proto();
492
493        // 192.168.2.60 is a local ip address, so it should be trusted by default
494        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
495
496        assert_eq!(trusted.scheme(), Some("https"));
497
498        let mut request = Request::get("/").body(()).unwrap();
499        request.headers_mut().append(
500            header::HeaderName::from_static("x-forwarded-proto"),
501            "http".parse().unwrap(),
502        );
503        request.headers_mut().append(
504            header::HeaderName::from_static("x-forwarded-proto"),
505            "https".parse().unwrap(),
506        );
507
508        let mut config = Config::default();
509        config.trust_x_forwarded_proto();
510
511        // 192.168.2.60 is a local ip address, so it should be trusted by default
512        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
513
514        assert_eq!(trusted.scheme(), Some("https"));
515
516        let mut request = Request::get("/").body(()).unwrap();
517        request.headers_mut().append(
518            header::HeaderName::from_static("x-forwarded-proto"),
519            "http, https".parse().unwrap(),
520        );
521
522        let mut config = Config::default();
523        config.trust_x_forwarded_proto();
524
525        // 192.168.2.60 is a local ip address, so it should be trusted by default
526        let trusted = Trusted::from("192.168.2.60".parse().unwrap(), &request, &config);
527
528        assert_eq!(trusted.scheme(), Some("https"));
529
530        let mut request = Request::get("/").body(()).unwrap();
531        // In this cas we have multiple hosts, so we should take the last one
532        request.headers_mut().append(
533            header::HeaderName::from_static("x-forwarded-proto"),
534            "https".parse().unwrap(),
535        );
536
537        let mut config = Config::default();
538        config.trust_x_forwarded_proto();
539
540        // 192.168.2.60 is a local ip address, so it should be trusted by default
541        let trusted = Trusted::from("1.1.1.1".parse().unwrap(), &request, &config);
542
543        assert_eq!(trusted.scheme(), None);
544    }
545
546    #[test]
547    fn x_forwarded_proto_header_untrusted() {
548        let mut request = Request::get("/").body(()).unwrap();
549        // In this cas we have multiple hosts, so we should take the last one
550        request.headers_mut().append(
551            header::HeaderName::from_static("x-forwarded-proto"),
552            "https".parse().unwrap(),
553        );
554
555        let config = Config::default();
556
557        // 192.168.2.60 is a local ip address, so it should be trusted by default
558        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
559
560        assert_eq!(trusted.scheme(), None);
561    }
562
563    #[test]
564    fn forwarded_header() {
565        let mut request = Request::get("/").body(()).unwrap();
566        request.headers_mut().append(
567            header::HeaderName::from_static("forwarded"),
568            "for=192.0.2.60; proto=https; by=203.0.113.43; host=rust-lang.org"
569                .parse()
570                .unwrap(),
571        );
572
573        let config = Config::default();
574
575        // 192.168.2.60 is a local ip address, so it should be trusted by default
576        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
577
578        assert_eq!(trusted.scheme(), Some("https"));
579        assert_eq!(trusted.host(), Some("rust-lang.org"));
580        assert_eq!(trusted.by(), Some("203.0.113.43"));
581        assert_eq!(trusted.ip(), "192.0.2.60".parse::<IpAddr>().unwrap());
582    }
583
584    #[test]
585    fn forwarded_case_sensitivity() {
586        let mut request = Request::get("/").body(()).unwrap();
587        request.headers_mut().append(
588            header::HeaderName::from_static("forwarded"),
589            "For=192.0.2.60".parse().unwrap(),
590        );
591
592        let config = Config::default();
593
594        // 192.168.2.60 is a local ip address, so it should be trusted by default
595        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
596
597        assert_eq!(trusted.ip(), "192.0.2.60".parse::<IpAddr>().unwrap());
598    }
599
600    #[test]
601    fn forwarded_for_quoted() {
602        let mut request = Request::get("/").body(()).unwrap();
603        request.headers_mut().append(
604            header::HeaderName::from_static("forwarded"),
605            r#"for="192.0.2.60:8080""#.parse().unwrap(),
606        );
607
608        let config = Config::default();
609
610        // 192.168.2.60 is a local ip address, so it should be trusted by default
611        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
612        assert_eq!(trusted.ip(), "192.0.2.60".parse::<IpAddr>().unwrap());
613    }
614
615    #[test]
616    fn forwarded_for_ipv6() {
617        let mut request = Request::get("/").body(()).unwrap();
618        request.headers_mut().append(
619            header::HeaderName::from_static("forwarded"),
620            r#"for="[2001:db8:cafe::17]""#.parse().unwrap(),
621        );
622
623        let config = Config::default();
624
625        // 192.168.2.60 is a local ip address, so it should be trusted by default
626        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
627        assert_eq!(trusted.ip(), "2001:db8:cafe::17".parse::<IpAddr>().unwrap());
628        assert!(trusted.ip().is_ipv6());
629    }
630
631    #[test]
632    fn forwarded_for_ipv6_with_port() {
633        let mut request = Request::get("/").body(()).unwrap();
634        request.headers_mut().append(
635            header::HeaderName::from_static("forwarded"),
636            r#"for="[2001:db8:cafe::17]:4711""#.parse().unwrap(),
637        );
638
639        let config = Config::default();
640
641        // 192.168.2.60 is a local ip address, so it should be trusted by default
642        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
643        assert_eq!(trusted.ip(), "2001:db8:cafe::17".parse::<IpAddr>().unwrap());
644        assert!(trusted.ip().is_ipv6());
645    }
646
647    #[test]
648    fn forwarded_for_multiple() {
649        let mut request = Request::get("/").body(()).unwrap();
650        request.headers_mut().append(
651            header::HeaderName::from_static("forwarded"),
652            "for=192.0.2.60, for=198.51.100.17".parse().unwrap(),
653        );
654
655        let config = Config::default();
656
657        // 192.168.2.60 is a local ip address, so it should be trusted by default
658        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
659        assert_eq!(trusted.ip(), "198.51.100.17".parse::<IpAddr>().unwrap());
660
661        let mut request = Request::get("/").body(()).unwrap();
662        request.headers_mut().append(
663            header::HeaderName::from_static("forwarded"),
664            "for=192.0.2.60;proto=https, for=198.51.100.17;proto=http"
665                .parse()
666                .unwrap(),
667        );
668
669        let mut config = Config::default();
670        config
671            .add_trusted_ip("198.51.100.17")
672            .expect("Failed to add trusted ip");
673
674        // 192.168.2.60 is a local ip address, so it should be trusted by default
675        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
676        assert_eq!(trusted.ip(), "192.0.2.60".parse::<IpAddr>().unwrap());
677        assert_eq!(trusted.scheme(), Some("https"));
678
679        let mut request = Request::get("/").body(()).unwrap();
680        request.headers_mut().append(
681            header::HeaderName::from_static("forwarded"),
682            "for=192.0.2.60, for=198.51.100.17;proto=http"
683                .parse()
684                .unwrap(),
685        );
686
687        let mut config = Config::default();
688        config
689            .add_trusted_ip("198.51.100.17")
690            .expect("Failed to add trusted ip");
691
692        // 192.168.2.60 is a local ip address, so it should be trusted by default
693        let trusted = Trusted::from("127.0.0.1".parse().unwrap(), &request, &config);
694        assert_eq!(trusted.ip(), "192.0.2.60".parse::<IpAddr>().unwrap());
695        assert_eq!(trusted.scheme(), None);
696    }
697}