1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9pub const PROTOCOL_VERSION: u32 = 1;
11
12pub const MAX_MESSAGE_SIZE: usize = 10 * 1024 * 1024;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(rename_all = "snake_case")]
18pub enum EventType {
19 RequestHeaders,
21 RequestBodyChunk,
23 ResponseHeaders,
25 ResponseBodyChunk,
27 RequestComplete,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33#[serde(rename_all = "snake_case")]
34pub enum Decision {
35 Allow,
37 Block {
39 status: u16,
41 body: Option<String>,
43 headers: Option<HashMap<String, String>>,
45 },
46 Redirect {
48 url: String,
50 status: u16,
52 },
53 Challenge {
55 challenge_type: String,
57 params: HashMap<String, String>,
59 },
60}
61
62impl Default for Decision {
63 fn default() -> Self {
64 Self::Allow
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
70#[serde(rename_all = "snake_case")]
71pub enum HeaderOp {
72 Set { name: String, value: String },
74 Add { name: String, value: String },
76 Remove { name: String },
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct RequestMetadata {
83 pub correlation_id: String,
85 pub request_id: String,
87 pub client_ip: String,
89 pub client_port: u16,
91 pub server_name: Option<String>,
93 pub protocol: String,
95 pub tls_version: Option<String>,
97 pub tls_cipher: Option<String>,
99 pub route_id: Option<String>,
101 pub upstream_id: Option<String>,
103 pub timestamp: String,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct RequestHeadersEvent {
110 pub metadata: RequestMetadata,
112 pub method: String,
114 pub uri: String,
116 pub headers: HashMap<String, Vec<String>>,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct RequestBodyChunkEvent {
123 pub correlation_id: String,
125 pub data: String,
127 pub is_last: bool,
129 pub total_size: Option<usize>,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct ResponseHeadersEvent {
136 pub correlation_id: String,
138 pub status: u16,
140 pub headers: HashMap<String, Vec<String>>,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct ResponseBodyChunkEvent {
147 pub correlation_id: String,
149 pub data: String,
151 pub is_last: bool,
153 pub total_size: Option<usize>,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct RequestCompleteEvent {
160 pub correlation_id: String,
162 pub status: u16,
164 pub duration_ms: u64,
166 pub request_body_size: usize,
168 pub response_body_size: usize,
170 pub upstream_attempts: u32,
172 pub error: Option<String>,
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct AgentRequest {
179 pub version: u32,
181 pub event_type: EventType,
183 pub payload: serde_json::Value,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct AgentResponse {
190 pub version: u32,
192 pub decision: Decision,
194 #[serde(default)]
196 pub request_headers: Vec<HeaderOp>,
197 #[serde(default)]
199 pub response_headers: Vec<HeaderOp>,
200 #[serde(default)]
202 pub routing_metadata: HashMap<String, String>,
203 #[serde(default)]
205 pub audit: AuditMetadata,
206}
207
208impl AgentResponse {
209 pub fn default_allow() -> Self {
211 Self {
212 version: PROTOCOL_VERSION,
213 decision: Decision::Allow,
214 request_headers: vec![],
215 response_headers: vec![],
216 routing_metadata: HashMap::new(),
217 audit: AuditMetadata::default(),
218 }
219 }
220
221 pub fn block(status: u16, body: Option<String>) -> Self {
223 Self {
224 version: PROTOCOL_VERSION,
225 decision: Decision::Block {
226 status,
227 body,
228 headers: None,
229 },
230 request_headers: vec![],
231 response_headers: vec![],
232 routing_metadata: HashMap::new(),
233 audit: AuditMetadata::default(),
234 }
235 }
236
237 pub fn redirect(url: String, status: u16) -> Self {
239 Self {
240 version: PROTOCOL_VERSION,
241 decision: Decision::Redirect { url, status },
242 request_headers: vec![],
243 response_headers: vec![],
244 routing_metadata: HashMap::new(),
245 audit: AuditMetadata::default(),
246 }
247 }
248
249 pub fn add_request_header(mut self, op: HeaderOp) -> Self {
251 self.request_headers.push(op);
252 self
253 }
254
255 pub fn add_response_header(mut self, op: HeaderOp) -> Self {
257 self.response_headers.push(op);
258 self
259 }
260
261 pub fn with_audit(mut self, audit: AuditMetadata) -> Self {
263 self.audit = audit;
264 self
265 }
266}
267
268#[derive(Debug, Clone, Default, Serialize, Deserialize)]
270pub struct AuditMetadata {
271 #[serde(default)]
273 pub tags: Vec<String>,
274 #[serde(default)]
276 pub rule_ids: Vec<String>,
277 pub confidence: Option<f32>,
279 #[serde(default)]
281 pub reason_codes: Vec<String>,
282 #[serde(default)]
284 pub custom: HashMap<String, serde_json::Value>,
285}