1pub(crate) use std::{marker::PhantomData, net::IpAddr, sync::Arc, time::Duration};
2use std::{
3 net::{Ipv4Addr, SocketAddr},
4 str::FromStr,
5};
6
7#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct Validated;
10
11#[derive(Debug, Clone, Copy, PartialEq)]
13pub struct Unvalidated;
14
15#[cfg(feature = "chrono")]
16pub use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
17
18#[cfg(feature = "time")]
19pub use time::{Date, OffsetDateTime, Time, UtcOffset};
20
21#[derive(Debug, Clone, PartialEq, strum::Display, strum::AsRefStr, strum::EnumString)]
22pub enum EdgeResultType {
23 Hit,
24 RefreshHit,
25 Miss,
26 LimitExceeded,
27 CapacityExceeded,
28 Error,
29 Redirect,
30
31 LambdaGeneratedResponse,
33
34 #[strum(default)]
36 Other(String),
37}
38
39#[derive(Debug, Clone, PartialEq, strum::Display, strum::AsRefStr, strum::EnumString)]
40pub enum DetailedEdgeResultType {
41 Hit,
43 RefreshHit,
44 Miss,
45 LimitExceeded,
46 CapacityExceeded,
47 Error,
48 Redirect,
49
50 LambdaGeneratedResponse,
52
53 OriginShieldHit,
55
56 MissGeneratedResponse,
58
59 AbortedOrigin,
61 ClientCommError,
62 ClientGeoBlocked,
63 ClientHungUpRequest,
64 InvalidRequest,
65 InvalidRequestBlocked,
66 InvalidRequestCertificate,
67 InvalidRequestHeader,
68 InvalidRequestMethod,
69 OriginCommError,
70 OriginConnectError,
71 OriginContentRangeLengthError,
72 OriginDnsError,
73 OriginError,
74 OriginHeaderTooBigError,
75 OriginInvalidResponseError,
76 OriginReadError,
77 OriginWriteError,
78 OriginZeroSizeObjectError,
79 SlowReaderOriginError,
80
81 #[strum(default)]
83 Other(String),
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, strum::Display, strum::AsRefStr, strum::EnumString)]
87pub enum CsProtocol {
88 #[strum(serialize = "http")]
89 Http,
90 #[strum(serialize = "https")]
91 Https,
92 #[strum(serialize = "ws")]
93 Ws,
94 #[strum(serialize = "wss")]
95 Wss,
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, strum::Display, strum::AsRefStr, strum::EnumString)]
99pub enum CsProtocolVersion {
100 #[strum(serialize = "HTTP/3.0")]
101 HTTP3_0,
102 #[strum(serialize = "HTTP/2.0")]
103 HTTP2_0,
104 #[strum(serialize = "HTTP/1.1")]
105 HTTP1_1,
106 #[strum(serialize = "HTTP/1.0")]
107 HTTP1_0,
108 #[strum(serialize = "HTTP/0.9")]
109 HTTP0_9,
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, strum::Display, strum::AsRefStr, strum::EnumString)]
115pub enum SslProtocol {
116 #[strum(serialize = "TLSv1.3")]
117 TLSv1_3,
118 #[strum(serialize = "TLSv1.2")]
119 TLSv1_2,
120 #[strum(serialize = "TLSv1.1")]
121 TLSv1_1,
122 #[strum(serialize = "TLSv1")]
123 TLSv1_0,
124 #[strum(serialize = "SSLv3")]
125 SSLv3,
126}
127
128#[derive(Debug, Clone, PartialEq)]
133pub enum Addressable {
134 IpAddr(IpAddr),
135 Socket(SocketAddr),
136 Unknown,
137}
138
139impl From<IpAddr> for Addressable {
140 fn from(ip: IpAddr) -> Self {
141 Self::IpAddr(ip)
142 }
143}
144
145impl From<SocketAddr> for Addressable {
146 fn from(socket: SocketAddr) -> Self {
147 Self::Socket(socket)
148 }
149}
150
151impl TryFrom<&str> for Addressable {
152 type Error = &'static str;
153
154 fn try_from(input: &str) -> Result<Self, Self::Error> {
155 if input == "unknown" {
156 return Ok(Self::Unknown);
157 }
158 let maybe_ip = input.parse::<IpAddr>();
159 if let Ok(ip) = maybe_ip {
160 return Ok(Self::IpAddr(ip));
161 } else {
162 if input.starts_with('0') && input.contains('.') {
164 let octets = input
165 .splitn(4, '.')
166 .filter_map(|s| s.parse::<u8>().ok())
167 .collect::<Vec<u8>>();
168 if octets.len() == 4 {
169 return Ok(Self::IpAddr(IpAddr::V4(Ipv4Addr::new(
170 octets[0], octets[1], octets[2], octets[3],
171 ))));
172 }
173 }
174 }
175 input
176 .parse::<SocketAddr>()
177 .map(Self::Socket)
178 .map_err(|_e| "invalid X-Forwarded-For IP/socket address")
179 }
180}
181
182impl FromStr for Addressable {
183 type Err = &'static str;
184
185 fn from_str(input: &str) -> Result<Self, Self::Err> {
186 Self::try_from(input)
187 }
188}
189
190#[derive(Debug, Clone, PartialEq)]
194pub struct ForwardedForAddrs(pub Vec<Addressable>);
195
196impl TryFrom<&str> for ForwardedForAddrs {
197 type Error = &'static str;
198
199 #[inline]
200 fn try_from(input: &str) -> Result<Self, Self::Error> {
201 const ESCAPED_SPACE: &str = "\\x20";
202 const ESCAPED_SPACE_LEN: usize = ESCAPED_SPACE.len();
203
204 let addresses: Vec<Addressable> = input
205 .split(',')
206 .map(|address| {
207 let trimmed = address.trim();
209 if trimmed.starts_with(ESCAPED_SPACE) {
210 &trimmed[ESCAPED_SPACE_LEN..]
211 } else {
212 trimmed
213 }
214 })
215 .map(str::parse)
217 .collect::<Result<Vec<Addressable>, _>>()
218 .map_err(|_e| "invalid X-Forwarded-For IP(s)")?;
219 Ok(Self(addresses))
220 }
221}
222
223impl FromStr for ForwardedForAddrs {
224 type Err = &'static str;
225
226 fn from_str(input: &str) -> Result<Self, Self::Err> {
227 Self::try_from(input)
228 }
229}