1use classy::stream::PropertyAccessor;
6use pdk_core::policy_context::authentication::{
7 Authentication, AuthenticationData, AuthenticationHandler,
8};
9use pdk_core::policy_context::policy_violation::{PolicyViolation, PolicyViolations};
10use proxy_wasm_stub::types::Bytes;
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12use std::cell::RefCell;
13use std::collections::HashMap;
14use std::fmt::{Debug, Formatter};
15use std::rc::Rc;
16
17#[derive(Clone, Debug, PartialEq)]
38pub struct UnitHttpRequest {
39 pub(crate) inner: RequestResponse,
40}
41
42#[derive(Clone, Debug, PartialEq)]
62pub struct UnitHttpResponse {
63 pub(crate) inner: RequestResponse,
64}
65
66macro_rules! http_method {
67 ($fn_name:ident, $method:expr) => {
68 #[doc = "Creates a `"]
69 #[doc = $method]
70 #[doc = "` request."]
71 pub fn $fn_name() -> Self {
72 Self::custom($method)
73 }
74 };
75}
76
77pub trait UnitHttpMessage {
92 fn header(&self, header: &str) -> Option<&str>;
94
95 fn headers(&self) -> &Vec<(String, String)>;
97
98 fn body(&self) -> &[u8];
100
101 fn property<K: Into<String>>(&self, key: Vec<K>) -> Option<Bytes>;
103
104 fn properties(&self) -> HashMap<Vec<String>, Bytes>;
106
107 fn authentication(&self) -> Option<AuthenticationData>;
109
110 fn violation(&self) -> Option<PolicyViolation>;
112}
113
114macro_rules! impl_request_response_methods {
115 () => {
116 pub fn with_header<K: Into<String>, V: Into<String>>(mut self, key: K, val: V) -> Self {
118 self.inner = self.inner.with_header(key, val);
119 self
120 }
121
122 pub fn with_body<B: Into<Vec<u8>>>(mut self, body: B) -> Self {
124 self.inner = self.inner.with_body(body);
125 self
126 }
127
128 pub fn with_property<K: Into<String>, V: Into<Vec<u8>>>(
130 mut self,
131 key: Vec<K>,
132 value: V,
133 ) -> Self {
134 self.inner = self.inner.with_property(key, value);
135 self
136 }
137
138 pub fn with_properties(mut self, properties: HashMap<Vec<String>, Bytes>) -> Self {
140 self.inner = self.inner.with_properties(properties);
141 self
142 }
143
144 pub fn with_authentication_data(mut self, authentication: AuthenticationData) -> Self {
146 self.inner = self.inner.with_authentication_data(authentication);
147 self
148 }
149
150 pub fn with_policy_violation(mut self, violation: PolicyViolation) -> Self {
152 self.inner = self.inner.with_policy_violation(violation);
153 self
154 }
155 };
156}
157
158macro_rules! impl_unit_http_message {
159 ($type:ty) => {
160 impl UnitHttpMessage for $type {
161 fn header(&self, header: &str) -> Option<&str> {
162 self.inner.header(header)
163 }
164
165 fn headers(&self) -> &Vec<(String, String)> {
166 self.inner.headers()
167 }
168
169 fn body(&self) -> &[u8] {
170 self.inner.body()
171 }
172
173 fn property<K: Into<String>>(&self, key: Vec<K>) -> Option<Bytes> {
174 self.inner.property(key)
175 }
176
177 fn properties(&self) -> HashMap<Vec<String>, Bytes> {
178 self.inner.properties()
179 }
180
181 fn authentication(&self) -> Option<AuthenticationData> {
182 self.inner.authentication()
183 }
184
185 fn violation(&self) -> Option<PolicyViolation> {
186 self.inner.violation()
187 }
188 }
189 };
190}
191
192impl_unit_http_message!(UnitHttpRequest);
193impl_unit_http_message!(UnitHttpResponse);
194
195impl UnitHttpRequest {
196 pub fn custom<M: Into<String>>(method: M) -> Self {
198 Self {
199 inner: RequestResponse::default().with_header(":method", method.into()),
200 }
201 }
202
203 http_method!(get, "GET");
204 http_method!(post, "POST");
205 http_method!(put, "PUT");
206 http_method!(patch, "PATCH");
207 http_method!(delete, "DELETE");
208 http_method!(head, "HEAD");
209 http_method!(options, "OPTIONS");
210
211 impl_request_response_methods!();
212
213 pub fn with_path<P: Into<String>>(mut self, path: P) -> Self {
215 self.inner = self.inner.with_header(":path", path.into());
216 self
217 }
218}
219
220impl From<RequestResponse> for UnitHttpRequest {
221 fn from(value: RequestResponse) -> Self {
222 Self { inner: value }
223 }
224}
225
226impl UnitHttpResponse {
227 pub fn new(status: u32) -> Self {
229 Self {
230 inner: RequestResponse::default().with_header(":status", status.to_string()),
231 }
232 }
233
234 impl_request_response_methods!();
235
236 pub fn status_code(&self) -> u32 {
239 self.inner
240 .header(":status")
241 .and_then(|s| s.parse().ok())
242 .unwrap_or_default()
243 }
244}
245
246impl From<RequestResponse> for UnitHttpResponse {
247 fn from(value: RequestResponse) -> Self {
248 Self { inner: value }
249 }
250}
251
252#[derive(Clone, Default, Serialize, Deserialize)]
268pub(crate) struct RequestResponse {
269 pub(crate) headers: Vec<(String, String)>,
270 pub(crate) body: Vec<u8>,
271 #[serde(deserialize_with = "de_properties")]
272 properties: Properties,
273}
274
275impl RequestResponse {
276 pub(crate) fn create(
277 headers: Vec<(String, String)>,
278 body: Vec<u8>,
279 properties: HashMap<Vec<String>, Bytes>,
280 ) -> Self {
281 Self {
282 headers,
283 body,
284 properties: Properties::new(properties),
285 }
286 }
287
288 pub fn new(headers: Vec<(&str, &str)>, body: Option<&[u8]>) -> Self {
295 Self {
296 headers: headers
297 .into_iter()
298 .map(|(key, value)| (key.to_string(), value.into()))
299 .collect(),
300 body: body.map(|body| body.into()).unwrap_or_default(),
301 properties: Properties::default(),
302 }
303 }
304
305 pub fn with_header<K: Into<String>, V: Into<String>>(mut self, key: K, val: V) -> Self {
307 self.headers.push((key.into(), val.into()));
308 self
309 }
310
311 pub fn header(&self, header: &str) -> Option<&str> {
313 self.headers.iter().find_map(|(key, value)| {
314 if key.eq_ignore_ascii_case(header) {
315 Some(value.as_str())
316 } else {
317 None
318 }
319 })
320 }
321
322 pub fn headers(&self) -> &Vec<(String, String)> {
324 &self.headers
325 }
326
327 pub fn with_body<B: Into<Vec<u8>>>(mut self, body: B) -> Self {
329 self.body = body.into();
330 self
331 }
332
333 pub fn body(&self) -> &[u8] {
335 self.body.as_slice()
336 }
337
338 pub fn with_property<K: Into<String>, V: Into<Vec<u8>>>(self, key: Vec<K>, value: V) -> Self {
342 let key = key.into_iter().map(|k| k.into()).collect();
343 self.properties
344 .properties
345 .borrow_mut()
346 .insert(key, value.into());
347 self
348 }
349
350 pub fn property<K: Into<String>>(&self, key: Vec<K>) -> Option<Bytes> {
352 let key: Vec<String> = key.into_iter().map(|k| k.into()).collect();
353 self.properties.properties.borrow().get(&key).cloned()
354 }
355
356 pub fn with_properties(mut self, properties: HashMap<Vec<String>, Bytes>) -> Self {
358 self.properties = Properties {
359 properties: Rc::new(RefCell::new(properties)),
360 };
361 self
362 }
363
364 pub fn properties(&self) -> HashMap<Vec<String>, Bytes> {
366 self.properties.properties.borrow().clone()
367 }
368
369 pub fn with_authentication_data(self, authentication: AuthenticationData) -> Self {
373 Authentication::new(self.properties.shared()).set_authentication(Some(&authentication));
374 self
375 }
376
377 pub fn authentication(&self) -> Option<AuthenticationData> {
379 Authentication::new(self.properties.shared()).authentication()
380 }
381
382 pub fn with_policy_violation(self, violation: PolicyViolation) -> Self {
386 let violations = PolicyViolations::new(
387 self.properties.shared(),
388 violation.get_policy_name().to_string(),
389 );
390 if let Some(id) = violation.get_client_id() {
391 violations.generate_policy_violation_for_client_app(
392 violation.get_client_name().unwrap_or_default(),
393 id,
394 );
395 } else {
396 violations.generate_policy_violation();
397 }
398
399 self
400 }
401
402 pub fn violation(&self) -> Option<PolicyViolation> {
404 PolicyViolations::new(self.properties.shared(), String::default()).policy_violation()
405 }
406
407 pub(crate) fn with_property_if_missing<B: Into<String>>(
408 self,
409 key: &[&str],
410 bytes: B,
411 ) -> RequestResponse {
412 if self.property(key.to_vec()).is_none() {
413 self.with_property(key.to_vec(), bytes.into().into_bytes())
414 } else {
415 self
416 }
417 }
418}
419
420impl PartialEq for RequestResponse {
421 fn eq(&self, other: &Self) -> bool {
422 self.headers == other.headers && self.body == other.body
423 }
424}
425
426impl Debug for RequestResponse {
427 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
428 f.write_str("RequestResponse {")?;
429 f.write_str("headers: ")?;
430 f.write_str(format!("{:?}", self.headers).as_str())?;
431 f.write_str("body: ")?;
432 f.write_str(format!("{:?}", String::from_utf8_lossy(self.body.as_slice())).as_str())?;
433 f.write_str("}")
434 }
435}
436
437#[derive(Default)]
439struct Properties {
440 properties: Rc<RefCell<HashMap<Vec<String>, Bytes>>>,
441}
442
443impl Clone for Properties {
444 fn clone(&self) -> Self {
445 Self {
446 properties: Rc::new(RefCell::new(self.properties.borrow().clone())),
447 }
448 }
449}
450
451impl Properties {
452 pub fn new(properties: HashMap<Vec<String>, Bytes>) -> Self {
453 Self {
454 properties: Rc::new(RefCell::new(properties)),
455 }
456 }
457
458 pub fn shared(&self) -> Self {
459 Self {
460 properties: Rc::clone(&self.properties),
461 }
462 }
463}
464
465#[derive(Serialize, Deserialize)]
466struct Property {
467 key: Vec<String>,
468 value: Bytes,
469}
470
471impl Serialize for Properties {
472 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
473 where
474 S: Serializer,
475 {
476 self.properties
477 .borrow()
478 .clone()
479 .into_iter()
480 .map(|(key, value)| Property { key, value })
481 .collect::<Vec<Property>>()
482 .serialize(serializer)
483 }
484}
485
486fn de_properties<'de, D>(deserializer: D) -> Result<Properties, D::Error>
487where
488 D: Deserializer<'de>,
489{
490 let exp: Vec<Property> = serde::de::Deserialize::deserialize(deserializer)?;
491 Ok(Properties {
492 properties: Rc::new(RefCell::new(
493 exp.into_iter()
494 .map(|property| (property.key, property.value))
495 .collect(),
496 )),
497 })
498}
499
500impl PropertyAccessor for Properties {
501 fn read_property(&self, path: &[&str]) -> Option<Bytes> {
502 self.properties
503 .borrow()
504 .get(&path.iter().map(|s| s.to_string()).collect::<Vec<String>>())
505 .cloned()
506 }
507
508 fn set_property(&self, path: &[&str], value: Option<&[u8]>) {
509 match value {
510 None => {
511 self.properties
512 .borrow_mut()
513 .remove(&path.iter().map(|s| s.to_string()).collect::<Vec<String>>());
514 }
515 Some(value) => {
516 self.properties.borrow_mut().insert(
517 path.iter().map(|s| s.to_string()).collect::<Vec<String>>(),
518 value.into(),
519 );
520 }
521 }
522 }
523}
524
525#[derive(Clone, Default, Serialize, Deserialize)]
530pub struct UnitGrpcRequest {
531 service: String,
532 method: String,
533 initial_metadata: Vec<(String, Bytes)>,
534 message: Option<Bytes>,
535}
536
537impl UnitGrpcRequest {
538 pub(crate) fn new(
539 service: &str,
540 method: &str,
541 initial_metadata: Vec<(&str, &[u8])>,
542 message: Option<&[u8]>,
543 ) -> UnitGrpcRequest {
544 UnitGrpcRequest {
545 service: service.to_string(),
546 method: method.to_string(),
547 initial_metadata: initial_metadata
548 .iter()
549 .map(|(key, value)| (key.to_string(), value.to_vec()))
550 .collect(),
551 message: message.map(|m| m.to_vec()),
552 }
553 }
554
555 pub fn service(&self) -> &str {
557 &self.service
558 }
559
560 pub fn method(&self) -> &str {
562 &self.method
563 }
564
565 pub fn initial_metadata(&self) -> &Vec<(String, Bytes)> {
567 &self.initial_metadata
568 }
569
570 pub fn message(&self) -> Option<&Bytes> {
572 self.message.as_ref()
573 }
574}
575
576#[derive(Clone, Default, Serialize, Deserialize)]
590pub struct UnitGrpcResponse {
591 pub(crate) status_code: u32,
592 pub(crate) status: Option<String>,
593 pub(crate) message: Bytes,
594}
595
596impl UnitGrpcResponse {
597 pub fn with_status_code(mut self, status: u32) -> Self {
601 self.status_code = status;
602 self
603 }
604
605 pub fn with_message(mut self, message: Vec<u8>) -> Self {
607 self.message = message;
608 self
609 }
610
611 pub fn with_status<S: Into<String>>(mut self, status: S) -> Self {
613 self.status = Some(status.into());
614 self
615 }
616}