1use crate::macros::IntoCdniMetadata;
21use brooks_macros::CdniMetadata;
22use serde::{Deserialize, Serialize};
23use serde_json::Value;
24
25use crate::cdni::gmd::spec::TypedGenericMetadata;
26
27use std::fmt::Debug;
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct SyntheticResponse<A: Debug + Clone + Default> {
31 pub headers: Option<Vec<TypedHeader<A>>>,
32
33 #[serde(rename = "response-status")]
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub response_status: Option<String>,
36
37 #[serde(rename = "status-is-expression")]
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub response_status_expr: Option<bool>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub body: Option<String>,
43
44 #[serde(rename = "body-is-expression")]
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub body_expr: Option<bool>,
47
48 #[serde(skip)]
49 pub aug: A,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
53pub struct TypedSyntheticResponse<A: Debug + Clone + Default> {
54 #[serde(rename = "generic-metadata-type")]
55 pub tpe: String,
56 #[serde(rename = "generic-metadata-value")]
57 pub value: SyntheticResponse<A>,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct Header<A: Debug + Clone + Default> {
62 pub name: String,
63 pub value: String,
64 #[serde(rename = "value-is-expression")]
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub value_expr: Option<bool>,
67
68 #[serde(skip)]
69 pub aug: A,
70}
71#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
72pub struct TypedHeader<A: Debug + Clone + Default> {
73 #[serde(rename = "generic-metadata-type")]
74 pub tpe: String,
75 #[serde(rename = "generic-metadata-value")]
76 pub value: Header<A>,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, Default)]
80pub struct HeaderTransform<A: Debug + Clone + Default> {
81 #[serde(skip_serializing_if = "Option::is_none")]
82 pub delete: Option<Vec<String>>,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub add: Option<Vec<TypedHeader<A>>>,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub replace: Option<Vec<TypedHeader<A>>>,
87 #[serde(skip)]
88 pub aug: A,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
92pub struct TypedHeaderTransform<A: Debug + Clone + Default> {
93 #[serde(rename = "generic-metadata-type")]
94 pub tpe: String,
95 #[serde(rename = "generic-metadata-value")]
96 pub value: HeaderTransform<A>,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize, Default)]
100pub struct RequestTransform<A: Debug + Clone + Default> {
101 #[serde(rename = "header-transform")]
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub xform: Option<TypedHeaderTransform<A>>,
104
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub uri: Option<String>,
107
108 #[serde(rename = "uri-is-expression")]
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub uri_is_expr: Option<bool>,
111
112 #[serde(skip)]
113 pub aug: A,
114}
115#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
116pub struct TypedRequestTransform<A: Debug + Clone + Default> {
117 #[serde(rename = "generic-metadata-type")]
118 pub tpe: String,
119 #[serde(rename = "generic-metadata-value")]
120 pub value: RequestTransform<A>,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct ResponseTransform<A: Debug + Clone + Default> {
125 #[serde(rename = "header-transform")]
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub xform: Option<TypedHeaderTransform<A>>,
128
129 #[serde(rename = "response-status")]
130 #[serde(skip_serializing_if = "Option::is_none")]
131 pub response_status: Option<String>,
132
133 #[serde(rename = "status-is-expression")]
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub response_status_expr: Option<bool>,
136
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub synthetic: Option<TypedSyntheticResponse<A>>,
139
140 #[serde(skip)]
141 pub aug: A,
142}
143#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
144pub struct TypedResponseTransform<A: Debug + Clone + Default> {
145 #[serde(rename = "generic-metadata-type")]
146 pub tpe: String,
147 #[serde(rename = "generic-metadata-value")]
148 pub value: ResponseTransform<A>,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize, Default)]
152pub struct StageMetadata<A: Debug + Clone + Default> {
153 #[serde(rename = "generic-metadata")]
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub generic: Option<Vec<TypedGenericMetadata<A>>>,
156
157 #[serde(rename = "request-transform")]
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub request_xform: Option<TypedRequestTransform<A>>,
160
161 #[serde(rename = "response-transform")]
162 #[serde(skip_serializing_if = "Option::is_none")]
163 pub response_xform: Option<TypedResponseTransform<A>>,
164
165 #[serde(skip)]
166 pub aug: A,
167}
168#[derive(Debug, Clone, Serialize, Deserialize, Default, CdniMetadata)]
169pub struct TypedStageMetadata<A: Debug + Clone + Default> {
170 #[serde(rename = "generic-metadata-type")]
171 pub tpe: String,
172 #[serde(rename = "generic-metadata-value")]
173 pub value: StageMetadata<A>,
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct ExpressionMatch<A: Debug + Clone + Default> {
178 pub expression: String,
179 #[serde(skip)]
180 pub aug: A,
181}
182#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
183pub struct TypedExpressionMatch<A: Debug + Clone + Default> {
184 #[serde(rename = "generic-metadata-type")]
185 pub tpe: String,
186 #[serde(rename = "generic-metadata-value")]
187 pub value: ExpressionMatch<A>,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
191pub struct StageRules<A: Debug + Clone + Default> {
192 #[serde(rename = "match")]
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub mtch: Option<TypedExpressionMatch<A>>,
195 #[serde(rename = "stage-metadata")]
196 pub stage_metadata: TypedStageMetadata<A>,
197
198 #[serde(skip)]
199 pub aug: A,
200}
201#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
202pub struct TypedStageRules<A: Debug + Clone + Default> {
203 #[serde(rename = "generic-metadata-type")]
204 pub tpe: String,
205 #[serde(rename = "generic-metadata-value")]
206 pub value: StageRules<A>,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct MatchGroup<A: Debug + Clone + Default> {
211 #[serde(rename = "if-rule")]
212 pub if_rule: TypedStageRules<A>,
213 #[serde(skip_serializing_if = "Option::is_none")]
214 #[serde(rename = "else-if-rules")]
215 pub else_ifs: Option<Vec<TypedStageRules<A>>>,
216 #[serde(skip)]
217 pub aug: A,
218}
219#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
220pub struct TypedMatchGroup<A: Debug + Clone + Default> {
221 #[serde(rename = "generic-metadata-type")]
222 pub tpe: String,
223 #[serde(rename = "generic-metadata-value")]
224 pub value: MatchGroup<A>,
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize, Default)]
228pub struct ProcessingStages<A: Debug + Clone + Default> {
229 #[serde(rename = "client-request")]
230 pub client_req: Vec<TypedStageRules<A>>,
231 #[serde(rename = "origin-request")]
232 pub origin_req: Vec<TypedStageRules<A>>,
233 #[serde(rename = "origin-response")]
234 pub origin_res: Vec<TypedStageRules<A>>,
235 #[serde(rename = "client-response")]
236 pub client_res: Vec<TypedStageRules<A>>,
237
238 #[serde(skip)]
239 pub aug: A,
240}
241#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
242pub struct TypedProcessingStages<A: Debug + Clone + Default> {
243 #[serde(rename = "generic-metadata-type")]
244 pub tpe: String,
245 #[serde(rename = "generic-metadata-value")]
246 pub value: ProcessingStages<A>,
247}
248
249#[derive(Debug, Clone, Serialize, Deserialize)]
250pub struct ClientRequestStage<A: Debug + Clone + Default> {
251 #[serde(rename = "match-groups")]
252 pub match_groups: Vec<TypedMatchGroup<A>>,
253 #[serde(skip)]
254 pub aug: A,
255}
256#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
257pub struct TypedClientRequestStage<A: Debug + Clone + Default> {
258 #[serde(rename = "generic-metadata-type")]
259 pub tpe: String,
260 #[serde(rename = "generic-metadata-value")]
261 pub value: ClientRequestStage<A>,
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct ClientResponseStage<A: Debug + Clone + Default> {
266 #[serde(rename = "match-groups")]
267 pub match_groups: Vec<TypedMatchGroup<A>>,
268 #[serde(skip)]
269 pub aug: A,
270}
271#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
272pub struct TypedClientResponseStage<A: Debug + Clone + Default> {
273 #[serde(rename = "generic-metadata-type")]
274 pub tpe: String,
275 #[serde(rename = "generic-metadata-value")]
276 pub value: ClientResponseStage<A>,
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
280pub struct OriginRequestStage<A: Debug + Clone + Default> {
281 #[serde(rename = "match-groups")]
282 pub match_groups: Vec<TypedMatchGroup<A>>,
283 #[serde(skip)]
284 pub aug: A,
285}
286#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
287pub struct TypedOriginRequestStage<A: Debug + Clone + Default> {
288 #[serde(rename = "generic-metadata-type")]
289 pub tpe: String,
290 #[serde(rename = "generic-metadata-value")]
291 pub value: OriginRequestStage<A>,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct OriginResponseStage<A: Debug + Clone + Default> {
296 #[serde(rename = "match-groups")]
297 pub match_groups: Vec<TypedMatchGroup<A>>,
298 #[serde(skip)]
299 pub aug: A,
300}
301#[derive(Debug, Clone, Serialize, Deserialize, CdniMetadata)]
302pub struct TypedOriginResponseStage<A: Debug + Clone + Default> {
303 #[serde(rename = "generic-metadata-type")]
304 pub tpe: String,
305 #[serde(rename = "generic-metadata-value")]
306 pub value: OriginResponseStage<A>,
307}
308
309#[derive(Debug, Clone, PartialEq)]
310pub enum TypedStageTypes {
311 ClientRequest,
312 ClientResponse,
313 OriginRequest,
314 OriginResponse,
315}
316
317#[derive(Debug, Clone)]
318pub enum TypedStage<A: Debug + Clone + Default> {
319 ClientRequest(TypedClientRequestStage<A>),
320 ClientResponse(TypedClientResponseStage<A>),
321 OriginRequest(TypedOriginRequestStage<A>),
322 OriginResponse(TypedOriginResponseStage<A>),
323}
324
325impl<A: Debug + Clone + Default> From<&TypedStage<A>> for TypedStageTypes {
326 fn from(value: &TypedStage<A>) -> Self {
327 match value {
328 TypedStage::ClientRequest(_) => TypedStageTypes::ClientRequest,
329 TypedStage::ClientResponse(_) => TypedStageTypes::ClientResponse,
330 TypedStage::OriginRequest(_) => TypedStageTypes::OriginRequest,
331 TypedStage::OriginResponse(_) => TypedStageTypes::OriginResponse,
332 }
333 }
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct TypedGenericStage {
338 #[serde(rename = "generic-metadata-type")]
339 pub tpe: String,
340 #[serde(rename = "generic-metadata-value")]
341 pub value: Value,
342}
343
344#[cfg(test)]
345mod test_spec {
346 use std::path::Path;
347
348 use crate::cdni::tests::test_helpers::{expression_match, stage_metadata, stage_rule};
349
350 use crate::{
351 cdni::ps::spec::{ProcessingStages, TypedClientRequestStage, TypedProcessingStages},
352 tests::read_test_file,
353 };
354
355 #[test]
356 fn test_simple_serialize() {
357 let x = TypedProcessingStages::<()> {
358 tpe: "MI.ProcessingStages".to_string(),
359 value: ProcessingStages::<()> {
360 client_req: vec![stage_rule(
361 Some(expression_match("5 + 4")),
362 stage_metadata(),
363 )],
364 origin_req: vec![stage_rule(
365 Some(expression_match("5 + 4")),
366 stage_metadata(),
367 )],
368 origin_res: vec![stage_rule(
369 Some(expression_match("5 + 4")),
370 stage_metadata(),
371 )],
372 client_res: vec![stage_rule(
373 Some(expression_match("5 + 4")),
374 stage_metadata(),
375 )],
376 aug: (),
377 },
378 };
379 let expected = read_test_file(Path::new("./tests/data/processing/simple/serialize.json"));
380 let actual = serde_json::to_string_pretty(&x).expect("Could not serialize");
381 pretty_assertions::assert_eq!(expected, actual);
382 }
383
384 #[test]
385 fn test_deserialize_example8() {
386 let json = read_test_file(Path::new("./tests/data/processing/from-spec/example8.json"));
387
388 let result = serde_json::from_str::<TypedProcessingStages<()>>(&json)
389 .expect("Could not deserialize Example 8");
390
391 assert_eq!(result.value.client_req.len(), 1);
393 let client_req = &result.value.client_req[0];
394
395 assert!(client_req.value.mtch.is_some());
397 assert!(client_req.value.stage_metadata.value.generic.is_some());
399 assert!(
401 client_req
402 .value
403 .stage_metadata
404 .value
405 .response_xform
406 .is_some()
407 );
408 }
409
410 #[test]
411 fn test_deserialize_client_request_stage() {
412 let json = read_test_file(Path::new(
413 "./tests/data/processing/client_request_stage/if.json",
414 ));
415
416 let result = serde_json::from_str::<TypedClientRequestStage<()>>(&json)
417 .expect("Could not deserialize simple client request stage JSON");
418
419 assert_eq!(result.value.match_groups.len(), 1);
421 let mg = &result.value.match_groups[0];
422
423 assert!(mg.value.if_rule.value.mtch.is_some());
425 }
426}