1use crate::{
2 borrowed::raw::{UnvalidatedLogline as UnvalidatedRaw, ValidatedLogline as ValidatedRaw},
3 shared::*,
4 types::*,
5};
6
7pub type ValidatedLogline = Logline<Validated>;
8pub type UnvalidatedLogline = Logline<Unvalidated>;
9
10#[derive(Debug, Clone, PartialEq)]
15pub struct Logline<V> {
16 pub date: String,
17 pub time: String,
18 pub x_edge_location: String,
19 pub sc_bytes: u64,
20 pub c_ip: IpAddr,
21 pub cs_method: String,
22 pub cs_host: String,
23 pub cs_uri_stem: String,
24 pub sc_status: u16,
25 pub cs_referer: Option<String>,
26 pub cs_user_agent: String,
27 pub cs_uri_query: Option<String>,
28 pub cs_cookie: Option<String>,
29 pub x_edge_result_type: EdgeResultType,
30 pub x_edge_request_id: String,
31 pub x_host_header: String,
32 pub cs_protocol: CsProtocol,
33 pub cs_bytes: u64,
34 pub time_taken: Duration,
35 pub x_forwarded_for: Option<ForwardedForAddrs>,
36 pub ssl_protocol: Option<SslProtocol>,
37 pub ssl_cipher: Option<String>, pub x_edge_response_result_type: EdgeResultType,
39 pub cs_protocol_version: CsProtocolVersion,
40 pub fle_status: Option<String>, pub fle_encrypted_fields: Option<u64>,
42 pub c_port: u16,
43 pub time_to_first_byte: Duration,
44 pub x_edge_detailed_result_type: DetailedEdgeResultType,
45 pub sc_content_type: String,
46 pub sc_content_len: u64,
47 pub sc_range_start: Option<i64>,
48 pub sc_range_end: Option<i64>,
49 __marker: PhantomData<V>,
50}
51
52impl TryFrom<&str> for Logline<Validated> {
56 type Error = &'static str;
57
58 fn try_from(line: &str) -> Result<Self, Self::Error> {
59 validate_line(line)?;
60 new_log_line(line)
61 }
62}
63
64impl TryFrom<&str> for Logline<Unvalidated> {
65 type Error = &'static str;
66
67 fn try_from(line: &str) -> Result<Self, Self::Error> {
68 new_log_line(line)
69 }
70}
71
72fn new_log_line<V>(line: &str) -> Result<Logline<V>, &'static str> {
73 let mut iter = MemchrTabSplitter::new(line);
74
75 let line = Logline {
76 date: iter.next().unwrap().to_string(),
77 time: iter.next().unwrap().to_string(),
78 x_edge_location: iter.next().unwrap().to_string(),
79 sc_bytes: iter
80 .next()
81 .unwrap()
82 .parse::<u64>()
83 .map_err(|_e| "sc_bytes invalid")?,
84 c_ip: iter.next().unwrap().parse().map_err(|_e| "c_ip invalid")?,
85 cs_method: iter.next().unwrap().to_string(),
86 cs_host: iter.next().unwrap().to_string(),
87 cs_uri_stem: iter.next().unwrap().to_string(),
88 sc_status: iter
89 .next()
90 .unwrap()
91 .parse::<u16>()
92 .map_err(|_e| "sc_status invalid")?,
93 cs_referer: iter.next().unwrap().to_optional_string(),
94 cs_user_agent: iter.next().unwrap().to_string(),
95 cs_uri_query: iter.next().unwrap().to_optional_string(),
96 cs_cookie: iter.next().unwrap().to_optional_string(),
97 x_edge_result_type: iter
98 .next()
99 .unwrap()
100 .parse()
101 .map_err(|_e| "x_edge_result_type invalid")?,
102 x_edge_request_id: iter.next().unwrap().to_string(),
103 x_host_header: iter.next().unwrap().to_string(),
104 cs_protocol: iter
105 .next()
106 .unwrap()
107 .parse()
108 .map_err(|_e| "cs_protocol invalid")?,
109 cs_bytes: iter
110 .next()
111 .unwrap()
112 .parse::<u64>()
113 .map_err(|_e| "cs_bytes invalid")?,
114 time_taken: iter
115 .next()
116 .unwrap()
117 .parse::<f64>()
118 .map(Duration::from_secs_f64)
119 .map_err(|_e| "time_taken invalid")?,
120 x_forwarded_for: iter
121 .next()
122 .and_then(as_optional_t)
123 .transpose()
124 .map_err(|_e| "x_forwarded_for invalid")?,
125 ssl_protocol: iter
126 .next()
127 .and_then(as_optional_t)
128 .transpose()
129 .map_err(|_e| "ssl_protocol invalid")?,
130 ssl_cipher: iter.next().unwrap().to_optional_string(),
131 x_edge_response_result_type: iter
132 .next()
133 .unwrap()
134 .parse()
135 .map_err(|_e| "x_edge_response_result_type invalid")?,
136 cs_protocol_version: iter
137 .next()
138 .unwrap()
139 .parse()
140 .map_err(|_e| "cs_protocol_version invalid")?,
141 fle_status: iter.next().unwrap().to_optional_string(),
142 fle_encrypted_fields: iter
143 .next()
144 .and_then(as_optional_t)
145 .transpose()
146 .map_err(|_e| "fle_encrypted_fields invalid")?,
147 c_port: iter
148 .next()
149 .unwrap()
150 .parse::<u16>()
151 .map_err(|_e| "c_port invalid")?,
152 time_to_first_byte: iter
153 .next()
154 .unwrap()
155 .parse::<f64>()
156 .map(Duration::from_secs_f64)
157 .map_err(|_e| "time_to_first_byte invalid")?,
158 x_edge_detailed_result_type: iter
159 .next()
160 .unwrap()
161 .parse()
162 .map_err(|_e| "x_edge_detailed_result_type invalid")?,
163 sc_content_type: iter.next().unwrap().to_string(),
164 sc_content_len: iter
165 .next()
166 .unwrap()
167 .parse::<u64>()
168 .map_err(|_e| "sc_content_len invalid")?,
169 sc_range_start: iter
170 .next()
171 .and_then(as_optional_t)
172 .transpose()
173 .map_err(|_e| "sc_range_start invalid")?,
174 sc_range_end: iter
175 .next()
176 .and_then(as_optional_t)
177 .transpose()
178 .map_err(|_e| "sc_range_end invalid")?,
179 __marker: PhantomData,
180 };
181 Ok(line)
182}
183
184impl Logline<Validated> {
185 pub fn try_from_with_raw(line: &str) -> Result<Self, &'static str> {
186 let raw = ValidatedRaw::try_from(line)?;
187 let line = Self::try_from(raw)?;
188 Ok(line)
189 }
190}
191
192impl Logline<Unvalidated> {
193 pub fn try_from_with_raw(line: &str) -> Result<Self, &'static str> {
194 let raw = UnvalidatedRaw::from(line);
195 let line = Self::try_from(raw)?;
196 Ok(line)
197 }
198}
199
200impl TryFrom<ValidatedRaw<'_>> for Logline<Validated> {
201 type Error = &'static str;
202
203 fn try_from(raw: ValidatedRaw<'_>) -> Result<Self, Self::Error> {
204 let line = Self {
205 date: raw.date.to_string(),
206 time: raw.time.to_string(),
207 x_edge_location: raw.x_edge_location.to_string(),
208 sc_bytes: raw
209 .sc_bytes
210 .parse::<u64>()
211 .map_err(|_e| "sc_bytes invalid")?,
212 c_ip: raw.c_ip.parse().map_err(|_e| "c_ip invalid")?,
213 cs_method: raw.cs_method.to_string(),
214 cs_host: raw.cs_host.to_string(),
215 cs_uri_stem: raw.cs_uri_stem.to_string(),
216 sc_status: raw
217 .sc_status
218 .parse::<u16>()
219 .map_err(|_e| "sc_status invalid")?,
220 cs_referer: raw.cs_referer.to_optional_string(),
221 cs_user_agent: raw.cs_user_agent.to_string(),
222 cs_uri_query: raw.cs_uri_query.to_optional_string(),
223 cs_cookie: raw.cs_cookie.to_optional_string(),
224 x_edge_result_type: raw
225 .x_edge_result_type
226 .parse()
227 .map_err(|_e| "x_edge_result_type invalid")?,
228 x_edge_request_id: raw.x_edge_request_id.to_string(),
229 x_host_header: raw.x_host_header.to_string(),
230 cs_protocol: raw
231 .cs_protocol
232 .parse()
233 .map_err(|_e| "cs_protocol invalid")?,
234 cs_bytes: raw
235 .cs_bytes
236 .parse::<u64>()
237 .map_err(|_e| "cs_bytes invalid")?,
238 time_taken: raw
239 .time_taken
240 .parse::<f64>()
241 .map(Duration::from_secs_f64)
242 .map_err(|_e| "time_taken invalid")?,
243 x_forwarded_for: parse_as_option(raw.x_forwarded_for)
244 .map_err(|_e| "x_forwarded_for invalid")?,
245 ssl_protocol: parse_as_option(raw.ssl_protocol).map_err(|_e| "ssl_protocol invalid")?,
246 ssl_cipher: raw.ssl_cipher.to_optional_string(),
247 x_edge_response_result_type: raw
248 .x_edge_response_result_type
249 .parse()
250 .map_err(|_e| "x_edge_response_result_type invalid")?,
251 cs_protocol_version: raw
252 .cs_protocol_version
253 .parse()
254 .map_err(|_e| "cs_protocol_version invalid")?,
255 fle_status: raw.fle_status.to_optional_string(),
256 fle_encrypted_fields: parse_as_option(raw.fle_encrypted_fields)
257 .map_err(|_e| "fle_encrypted_fields invalid")?,
258 c_port: raw.c_port.parse::<u16>().map_err(|_e| "c_port invalid")?,
259 time_to_first_byte: raw
260 .time_to_first_byte
261 .parse::<f64>()
262 .map(Duration::from_secs_f64)
263 .map_err(|_e| "time_to_first_byte invalid")?,
264 x_edge_detailed_result_type: raw
265 .x_edge_detailed_result_type
266 .parse()
267 .map_err(|_e| "x_edge_detailed_result_type invalid")?,
268 sc_content_type: raw.sc_content_type.to_string(),
269 sc_content_len: raw
270 .sc_content_len
271 .parse::<u64>()
272 .map_err(|_e| "sc_content_len invalid")?,
273 sc_range_start: parse_as_option(raw.sc_range_start)
274 .map_err(|_e| "sc_range_start invalid")?,
275 sc_range_end: parse_as_option(raw.sc_range_end).map_err(|_e| "sc_range_end invalid")?,
276 __marker: PhantomData,
277 };
278 Ok(line)
279 }
280}
281
282impl TryFrom<UnvalidatedRaw<'_>> for Logline<Unvalidated> {
283 type Error = &'static str;
284
285 fn try_from(raw: UnvalidatedRaw<'_>) -> Result<Self, Self::Error> {
286 let line = Self {
287 date: raw.date.to_string(),
288 time: raw.time.to_string(),
289 x_edge_location: raw.x_edge_location.to_string(),
290 sc_bytes: raw
291 .sc_bytes
292 .parse::<u64>()
293 .map_err(|_e| "sc_bytes invalid")?,
294 c_ip: raw.c_ip.parse().map_err(|_e| "c_ip invalid")?,
295 cs_method: raw.cs_method.to_string(),
296 cs_host: raw.cs_host.to_string(),
297 cs_uri_stem: raw.cs_uri_stem.to_string(),
298 sc_status: raw
299 .sc_status
300 .parse::<u16>()
301 .map_err(|_e| "sc_status invalid")?,
302 cs_referer: raw.cs_referer.to_optional_string(),
303 cs_user_agent: raw.cs_user_agent.to_string(),
304 cs_uri_query: raw.cs_uri_query.to_optional_string(),
305 cs_cookie: raw.cs_cookie.to_optional_string(),
306 x_edge_result_type: raw
307 .x_edge_result_type
308 .parse()
309 .map_err(|_e| "x_edge_result_type invalid")?,
310 x_edge_request_id: raw.x_edge_request_id.to_string(),
311 x_host_header: raw.x_host_header.to_string(),
312 cs_protocol: raw
313 .cs_protocol
314 .parse()
315 .map_err(|_e| "cs_protocol invalid")?,
316 cs_bytes: raw
317 .cs_bytes
318 .parse::<u64>()
319 .map_err(|_e| "cs_bytes invalid")?,
320 time_taken: raw
321 .time_taken
322 .parse::<f64>()
323 .map(Duration::from_secs_f64)
324 .map_err(|_e| "time_taken invalid")?,
325 x_forwarded_for: parse_as_option(raw.x_forwarded_for)
326 .map_err(|_e| "x_forwarded_for invalid")?,
327 ssl_protocol: parse_as_option(raw.ssl_protocol).map_err(|_e| "ssl_protocol invalid")?,
328 ssl_cipher: raw.ssl_cipher.to_optional_string(),
329 x_edge_response_result_type: raw
330 .x_edge_response_result_type
331 .parse()
332 .map_err(|_e| "x_edge_response_result_type invalid")?,
333 cs_protocol_version: raw
334 .cs_protocol_version
335 .parse()
336 .map_err(|_e| "cs_protocol_version invalid")?,
337 fle_status: raw.fle_status.to_optional_string(),
338 fle_encrypted_fields: parse_as_option(raw.fle_encrypted_fields)
339 .map_err(|_e| "fle_encrypted_fields invalid")?,
340 c_port: raw.c_port.parse::<u16>().map_err(|_e| "c_port invalid")?,
341 time_to_first_byte: raw
342 .time_to_first_byte
343 .parse::<f64>()
344 .map(Duration::from_secs_f64)
345 .map_err(|_e| "time_to_first_byte invalid")?,
346 x_edge_detailed_result_type: raw
347 .x_edge_detailed_result_type
348 .parse()
349 .map_err(|_e| "x_edge_detailed_result_type invalid")?,
350 sc_content_type: raw.sc_content_type.to_string(),
351 sc_content_len: raw
352 .sc_content_len
353 .parse::<u64>()
354 .map_err(|_e| "sc_content_len invalid")?,
355 sc_range_start: parse_as_option(raw.sc_range_start)
356 .map_err(|_e| "sc_range_start invalid")?,
357 sc_range_end: parse_as_option(raw.sc_range_end).map_err(|_e| "sc_range_end invalid")?,
358 __marker: PhantomData,
359 };
360 Ok(line)
361 }
362}