Skip to main content

reinhardt_http/request/
methods.rs

1use super::Request;
2
3impl Request {
4	/// Returns true if the request was made over HTTPS
5	///
6	/// This can be determined either by:
7	/// 1. The actual connection being TLS (is_secure flag)
8	/// 2. X-Forwarded-Proto header indicating HTTPS (only from trusted proxies)
9	///
10	/// # Examples
11	///
12	/// ```
13	/// use reinhardt_http::{Request, TrustedProxies};
14	/// use hyper::Method;
15	/// use std::net::{SocketAddr, IpAddr, Ipv4Addr};
16	///
17	/// // Direct HTTPS connection
18	/// let request = Request::builder()
19	///     .method(Method::GET)
20	///     .uri("/")
21	///     .secure(true)
22	///     .build()
23	///     .unwrap();
24	/// assert!(request.is_secure());
25	///
26	/// // Behind trusted reverse proxy
27	/// let proxy_ip = IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1));
28	/// let mut headers = hyper::HeaderMap::new();
29	/// headers.insert("x-forwarded-proto", "https".parse().unwrap());
30	/// let request = Request::builder()
31	///     .method(Method::GET)
32	///     .uri("/")
33	///     .headers(headers)
34	///     .remote_addr(SocketAddr::new(proxy_ip, 8080))
35	///     .build()
36	///     .unwrap();
37	/// request.set_trusted_proxies(TrustedProxies::new(vec![proxy_ip]));
38	/// assert!(request.is_secure());
39	/// ```
40	pub fn is_secure(&self) -> bool {
41		if self.is_secure {
42			return true;
43		}
44
45		// Only trust X-Forwarded-Proto header from configured trusted proxies
46		if self.is_from_trusted_proxy()
47			&& let Some(proto) = self
48				.headers
49				.get("x-forwarded-proto")
50				.and_then(|h| h.to_str().ok())
51		{
52			return proto.eq_ignore_ascii_case("https");
53		}
54
55		false
56	}
57
58	/// Returns the scheme of the request (http or https)
59	///
60	/// # Examples
61	///
62	/// ```
63	/// use reinhardt_http::Request;
64	/// use hyper::{Method, Uri, Version, HeaderMap};
65	/// use bytes::Bytes;
66	///
67	/// let request = Request::builder()
68	///     .method(Method::GET)
69	///     .uri("/")
70	///     .secure(true)
71	///     .build()
72	///     .unwrap();
73	/// assert_eq!(request.scheme(), "https");
74	///
75	/// let request = Request::builder()
76	///     .method(Method::GET)
77	///     .uri("/")
78	///     .build()
79	///     .unwrap();
80	/// assert_eq!(request.scheme(), "http");
81	/// ```
82	pub fn scheme(&self) -> &str {
83		if self.is_secure() { "https" } else { "http" }
84	}
85
86	/// Build an absolute URI for the request
87	///
88	/// Example: "<https://example.com:8000/path?query=value>"
89	///
90	/// # Examples
91	///
92	/// ```
93	/// use reinhardt_http::Request;
94	/// use hyper::{Method, Uri, Version, HeaderMap};
95	/// use bytes::Bytes;
96	///
97	/// let mut headers = hyper::HeaderMap::new();
98	/// headers.insert("host", "example.com".parse().unwrap());
99	///
100	/// let request = Request::builder()
101	///     .method(Method::GET)
102	///     .uri("/api/users")
103	///     .headers(headers)
104	///     .secure(true)
105	///     .build()
106	///     .unwrap();
107	///
108	/// let uri = request.build_absolute_uri(None);
109	/// assert_eq!(uri, "https://example.com/api/users");
110	///
111	/// let uri = request.build_absolute_uri(Some("/other/path"));
112	/// assert_eq!(uri, "https://example.com/other/path");
113	/// ```
114	pub fn build_absolute_uri(&self, path: Option<&str>) -> String {
115		let scheme = self.scheme();
116		let host = self.get_host().unwrap_or_else(|| "localhost".to_string());
117		let path = path.unwrap_or_else(|| self.path());
118
119		format!("{}://{}{}", scheme, host, path)
120	}
121
122	/// Get the host from the request headers
123	fn get_host(&self) -> Option<String> {
124		self.headers
125			.get(hyper::header::HOST)
126			.and_then(|h| h.to_str().ok())
127			.map(|s| s.to_string())
128	}
129}