1use std::net::IpAddr;
2use std::ops::Deref;
3use std::time::Duration;
4use serde::{Serialize, Deserialize};
5use ulid::Ulid;
6use url::Url;
7use chrono::{DateTime, Utc};
8use crate::shared::NamedU16;
9use crate::proxy_server::ProcessInfo;
10use crate::serde_helpers::option_duration_millis;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
17#[serde(rename_all = "camelCase")]
18pub struct SessionEntry {
19 pub id: Ulid,
20 pub url: Url,
21 pub client_addr: Option<NetAddress>,
22 pub remote_addr: Option<NetAddress>,
23 pub http_version: String,
24 pub transaction_type: TransactionType,
25 pub request: Request,
26 pub response: Option<Response>,
27 #[serde(rename = "isWebSocket")]
28 pub is_websocket: bool,
29 pub tls: TlsSettings,
30 pub http2: Option<Http2StreamRef>,
31 pub timings: Timings,
32 pub process: Option<ProcessInfo>,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
37#[serde(rename_all = "camelCase")]
38pub struct NetAddress {
39 pub ip: IpAddr,
40 pub port: Option<u16>,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
45#[serde(rename_all = "snake_case")]
46pub enum TransactionType {
47 Request,
48 PushPromise,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct TlsSettings {
55 pub connection_id: Option<Ulid>,
56 pub tls_version: Option<NamedU16>,
57 pub cipher_suite: Option<NamedU16>,
58 pub ja3: Option<Ja3>,
59 pub ja4: Option<Ja4>,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
64#[serde(rename_all = "camelCase")]
65pub struct Http2StreamRef {
66 pub connection_id: Ulid,
67 pub stream_id: u32,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
75#[serde(rename_all = "camelCase")]
76pub struct Timings {
77 pub started_at: DateTime<Utc>,
79 #[serde(with = "option_duration_millis")]
81 pub blocked: Option<Duration>,
82 #[serde(with = "option_duration_millis")]
84 pub dns: Option<Duration>,
85 #[serde(with = "option_duration_millis")]
87 pub connect: Option<Duration>,
88 #[serde(with = "option_duration_millis")]
90 pub send: Option<Duration>,
91 #[serde(with = "option_duration_millis")]
93 pub wait: Option<Duration>,
94 #[serde(with = "option_duration_millis")]
96 pub receive: Option<Duration>,
97 #[serde(with = "option_duration_millis")]
99 pub ssl: Option<Duration>,
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
104#[serde(rename_all = "camelCase")]
105pub struct Ja3 {
106 pub string: String,
107 pub hash: String,
108}
109
110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
112pub struct Ja4 {
113 pub raw: String,
114 pub hashed: String,
115}
116
117#[derive(Debug, Clone, Default, PartialEq, Eq)]
133pub struct Headers {
134 inner: Vec<(String, String)>,
135}
136
137impl Headers {
138 pub fn new() -> Self {
140 Self { inner: Vec::new() }
141 }
142
143 pub fn get(&self, name: &str) -> Option<&str> {
145 let name_lower = name.to_lowercase();
146 self.inner
147 .iter()
148 .find(|(name, _)| name.to_lowercase() == name_lower)
149 .map(|(_, value)| value.as_str())
150 }
151
152 pub fn get_all(&self, name: &str) -> Vec<&str> {
154 let name_lower = name.to_lowercase();
155 self.inner
156 .iter()
157 .filter(|(name, _)| name.to_lowercase() == name_lower)
158 .map(|(_, value)| value.as_str())
159 .collect()
160 }
161
162 pub fn contains(&self, name: &str) -> bool {
164 let name_lower = name.to_lowercase();
165 self.inner.iter().any(|(name, _)| name.to_lowercase() == name_lower)
166 }
167
168 pub fn set(&mut self, name: impl Into<String>, value: impl Into<String>) {
170 let name = name.into();
171 let name_lower = name.to_lowercase();
172 if let Some((_, v)) = self.inner.iter_mut().find(|(name, _)| name.to_lowercase() == name_lower) {
173 *v = value.into();
174 } else {
175 self.inner.push((name, value.into()));
176 }
177 }
178
179 pub fn push(&mut self, name: impl Into<String>, value: impl Into<String>) {
181 self.inner.push((name.into(), value.into()));
182 }
183
184 pub fn remove(&mut self, name: &str) -> Option<String> {
186 let name_lower = name.to_lowercase();
187 if let Some(pos) = self.inner.iter().position(|(name, _)| name.to_lowercase() == name_lower) {
188 Some(self.inner.remove(pos).1)
189 } else {
190 None
191 }
192 }
193
194 pub fn iter(&self) -> std::slice::Iter<'_, (String, String)> {
195 self.inner.iter()
196 }
197
198 pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, (String, String)> {
199 self.inner.iter_mut()
200 }
201
202 pub fn len(&self) -> usize {
203 self.inner.len()
204 }
205
206 pub fn is_empty(&self) -> bool {
207 self.inner.is_empty()
208 }
209}
210
211impl Deref for Headers {
212 type Target = [(String, String)];
213
214 fn deref(&self) -> &Self::Target {
215 &self.inner
216 }
217}
218
219impl IntoIterator for Headers {
220 type Item = (String, String);
221 type IntoIter = std::vec::IntoIter<(String, String)>;
222
223 fn into_iter(self) -> Self::IntoIter {
224 self.inner.into_iter()
225 }
226}
227
228impl<'a> IntoIterator for &'a Headers {
229 type Item = &'a (String, String);
230 type IntoIter = std::slice::Iter<'a, (String, String)>;
231
232 fn into_iter(self) -> Self::IntoIter {
233 self.inner.iter()
234 }
235}
236
237impl<'a> IntoIterator for &'a mut Headers {
238 type Item = &'a mut (String, String);
239 type IntoIter = std::slice::IterMut<'a, (String, String)>;
240
241 fn into_iter(self) -> Self::IntoIter {
242 self.inner.iter_mut()
243 }
244}
245
246impl FromIterator<(String, String)> for Headers {
247 fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
248 Self {
249 inner: Vec::from_iter(iter)
250 }
251 }
252}
253
254impl From<Vec<(String, String)>> for Headers {
255 fn from(vec: Vec<(String, String)>) -> Self {
256 Self { inner: vec }
257 }
258}
259
260impl From<Headers> for Vec<(String, String)> {
261 fn from(headers: Headers) -> Self {
262 headers.inner
263 }
264}
265
266impl Serialize for Headers {
267 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
268 self.inner.serialize(serializer)
269 }
270}
271
272impl<'de> Deserialize<'de> for Headers {
273 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
274 Vec::<(String, String)>::deserialize(deserializer).map(|inner| Headers { inner })
275 }
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize)]
280#[serde(rename_all = "camelCase")]
281pub struct Request {
282 pub method: Option<String>,
283 pub path: Option<String>,
284 pub http_version: Option<String>,
285 pub headers: Headers,
286 pub body_size: Option<usize>,
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
291#[serde(rename_all = "camelCase")]
292pub struct Response {
293 pub http_version: Option<String>,
294 pub status_code: Option<u16>,
295 pub status_text: Option<String>,
296 pub headers: Headers,
297 pub body_size: Option<usize>,
298}
299
300#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
302#[serde(rename_all = "camelCase")]
303pub struct SessionInfo {
304 pub id: Ulid,
305 pub name: String,
306}