1use pdk_websockets_lib::{Frame, FrameType};
6
7#[cfg(feature = "pdk")]
8use classy::stream::PropertyAccessor;
9#[cfg(feature = "pdk")]
10use pdk_core::policy_context::authentication::{
11 Authentication, AuthenticationData, AuthenticationHandler,
12};
13#[cfg(feature = "pdk")]
14use pdk_core::policy_context::policy_violation::{PolicyViolation, PolicyViolations};
15use proxy_wasm_stub::types::Bytes;
16use serde::{Deserialize, Deserializer, Serialize, Serializer};
17use std::cell::RefCell;
18use std::collections::HashMap;
19use std::fmt::{Debug, Formatter};
20use std::rc::Rc;
21
22#[derive(Clone, Debug, PartialEq)]
43pub struct UnitHttpRequest {
44 pub(crate) inner: RequestResponse,
45}
46
47#[derive(Clone, Debug, PartialEq)]
67pub struct UnitHttpResponse {
68 pub(crate) inner: RequestResponse,
69}
70
71macro_rules! http_method {
72 ($fn_name:ident, $method:expr) => {
73 #[doc = "Creates a `"]
74 #[doc = $method]
75 #[doc = "` request."]
76 pub fn $fn_name() -> Self {
77 Self::custom($method)
78 }
79 };
80}
81
82pub trait UnitHttpMessage {
97 fn header(&self, header: &str) -> Option<&str>;
99
100 fn headers(&self) -> &Vec<(String, String)>;
102
103 fn body(&self) -> &[u8];
105
106 fn property<K: Into<String>>(&self, key: Vec<K>) -> Option<Bytes>;
108
109 fn properties(&self) -> HashMap<Vec<String>, Bytes>;
111
112 #[cfg(feature = "pdk")]
114 fn authentication(&self) -> Option<AuthenticationData>;
115
116 #[cfg(feature = "pdk")]
118 fn violation(&self) -> Option<PolicyViolation>;
119}
120
121macro_rules! impl_request_response_methods {
122 () => {
123 pub fn with_header<K: Into<String>, V: Into<String>>(mut self, key: K, val: V) -> Self {
125 self.inner = self.inner.with_header(key, val);
126 self
127 }
128
129 pub fn with_body<B: Into<Vec<u8>>>(mut self, body: B) -> Self {
131 self.inner = self.inner.with_body(body);
132 self
133 }
134
135 pub fn with_property<K: Into<String>, V: Into<Vec<u8>>>(
137 mut self,
138 key: Vec<K>,
139 value: V,
140 ) -> Self {
141 self.inner = self.inner.with_property(key, value);
142 self
143 }
144
145 pub fn with_properties(mut self, properties: HashMap<Vec<String>, Bytes>) -> Self {
147 self.inner = self.inner.with_properties(properties);
148 self
149 }
150
151 #[cfg(feature = "pdk")]
153 pub fn with_authentication_data(mut self, authentication: AuthenticationData) -> Self {
154 self.inner = self.inner.with_authentication_data(authentication);
155 self
156 }
157
158 #[cfg(feature = "pdk")]
160 pub fn with_policy_violation(mut self, violation: PolicyViolation) -> Self {
161 self.inner = self.inner.with_policy_violation(violation);
162 self
163 }
164 };
165}
166
167macro_rules! impl_unit_http_message {
168 ($type:ty) => {
169 impl UnitHttpMessage for $type {
170 fn header(&self, header: &str) -> Option<&str> {
171 self.inner.header(header)
172 }
173
174 fn headers(&self) -> &Vec<(String, String)> {
175 self.inner.headers()
176 }
177
178 fn body(&self) -> &[u8] {
179 self.inner.body()
180 }
181
182 fn property<K: Into<String>>(&self, key: Vec<K>) -> Option<Bytes> {
183 self.inner.property(key)
184 }
185
186 fn properties(&self) -> HashMap<Vec<String>, Bytes> {
187 self.inner.properties()
188 }
189
190 #[cfg(feature = "pdk")]
191 fn authentication(&self) -> Option<AuthenticationData> {
192 self.inner.authentication()
193 }
194
195 #[cfg(feature = "pdk")]
196 fn violation(&self) -> Option<PolicyViolation> {
197 self.inner.violation()
198 }
199 }
200 };
201}
202
203impl_unit_http_message!(UnitHttpRequest);
204impl_unit_http_message!(UnitHttpResponse);
205
206impl UnitHttpRequest {
207 pub fn custom<M: Into<String>>(method: M) -> Self {
209 Self {
210 inner: RequestResponse::default().with_header(":method", method.into()),
211 }
212 }
213
214 http_method!(get, "GET");
215 http_method!(post, "POST");
216 http_method!(put, "PUT");
217 http_method!(patch, "PATCH");
218 http_method!(delete, "DELETE");
219 http_method!(head, "HEAD");
220 http_method!(options, "OPTIONS");
221
222 pub fn upgrade() -> Self {
224 Self::custom("GET")
225 .with_header("connection", "Upgrade")
226 .with_header("upgrade", "websocket")
227 }
228
229 impl_request_response_methods!();
230
231 pub fn with_path<P: Into<String>>(mut self, path: P) -> Self {
233 self.inner = self.inner.with_header(":path", path.into());
234 self
235 }
236}
237
238impl From<RequestResponse> for UnitHttpRequest {
239 fn from(value: RequestResponse) -> Self {
240 Self { inner: value }
241 }
242}
243
244impl UnitHttpResponse {
245 pub fn new(status: u32) -> Self {
247 Self {
248 inner: RequestResponse::default().with_header(":status", status.to_string()),
249 }
250 }
251
252 pub fn upgrade() -> Self {
253 UnitHttpResponse::new(101)
254 .with_header("upgrade", "websocket")
255 .with_header("connection", "Upgrade")
256 }
257
258 impl_request_response_methods!();
259
260 pub fn status_code(&self) -> u32 {
263 self.inner
264 .header(":status")
265 .and_then(|s| s.parse().ok())
266 .unwrap_or_default()
267 }
268}
269
270impl From<RequestResponse> for UnitHttpResponse {
271 fn from(value: RequestResponse) -> Self {
272 Self { inner: value }
273 }
274}
275
276#[derive(Clone, Default, Serialize, Deserialize)]
292pub(crate) struct RequestResponse {
293 pub(crate) headers: Vec<(String, String)>,
294 pub(crate) body: Vec<u8>,
295 #[serde(deserialize_with = "de_properties")]
296 properties: Properties,
297}
298
299impl RequestResponse {
300 pub(crate) fn create(
301 headers: Vec<(String, String)>,
302 body: Vec<u8>,
303 properties: HashMap<Vec<String>, Bytes>,
304 ) -> Self {
305 Self {
306 headers,
307 body,
308 properties: Properties::new(properties),
309 }
310 }
311
312 pub fn new(headers: Vec<(&str, &str)>, body: Option<&[u8]>) -> Self {
319 Self {
320 headers: headers
321 .into_iter()
322 .map(|(key, value)| (key.to_string(), value.into()))
323 .collect(),
324 body: body.map(|body| body.into()).unwrap_or_default(),
325 properties: Properties::default(),
326 }
327 }
328
329 pub fn with_header<K: Into<String>, V: Into<String>>(mut self, key: K, val: V) -> Self {
331 self.headers.push((key.into(), val.into()));
332 self
333 }
334
335 pub fn header(&self, header: &str) -> Option<&str> {
337 self.headers.iter().find_map(|(key, value)| {
338 if key.eq_ignore_ascii_case(header) {
339 Some(value.as_str())
340 } else {
341 None
342 }
343 })
344 }
345
346 pub fn headers(&self) -> &Vec<(String, String)> {
348 &self.headers
349 }
350
351 pub fn with_body<B: Into<Vec<u8>>>(mut self, body: B) -> Self {
353 self.body = body.into();
354 self
355 }
356
357 pub fn body(&self) -> &[u8] {
359 self.body.as_slice()
360 }
361
362 pub fn with_property<K: Into<String>, V: Into<Vec<u8>>>(self, key: Vec<K>, value: V) -> Self {
366 let key = key.into_iter().map(|k| k.into()).collect();
367 self.properties
368 .properties
369 .borrow_mut()
370 .insert(key, value.into());
371 self
372 }
373
374 pub fn property<K: Into<String>>(&self, key: Vec<K>) -> Option<Bytes> {
376 let key: Vec<String> = key.into_iter().map(|k| k.into()).collect();
377 self.properties.properties.borrow().get(&key).cloned()
378 }
379
380 pub fn with_properties(mut self, properties: HashMap<Vec<String>, Bytes>) -> Self {
382 self.properties = Properties {
383 properties: Rc::new(RefCell::new(properties)),
384 };
385 self
386 }
387
388 pub fn properties(&self) -> HashMap<Vec<String>, Bytes> {
390 self.properties.properties.borrow().clone()
391 }
392
393 pub(crate) fn with_property_if_missing<B: Into<String>>(
394 self,
395 key: &[&str],
396 bytes: B,
397 ) -> RequestResponse {
398 if self.property(key.to_vec()).is_none() {
399 self.with_property(key.to_vec(), bytes.into().into_bytes())
400 } else {
401 self
402 }
403 }
404}
405
406#[cfg(feature = "pdk")]
407impl RequestResponse {
408 pub fn with_authentication_data(self, authentication: AuthenticationData) -> Self {
412 Authentication::new(self.properties.shared()).set_authentication(Some(&authentication));
413 self
414 }
415
416 pub fn authentication(&self) -> Option<AuthenticationData> {
418 Authentication::new(self.properties.shared()).authentication()
419 }
420
421 pub fn with_policy_violation(self, violation: PolicyViolation) -> Self {
425 let violations = PolicyViolations::new(
426 self.properties.shared(),
427 violation.get_policy_name().to_string(),
428 );
429 if let Some(id) = violation.get_client_id() {
430 violations.generate_policy_violation_for_client_app(
431 violation.get_client_name().unwrap_or_default(),
432 id,
433 );
434 } else {
435 violations.generate_policy_violation();
436 }
437
438 self
439 }
440
441 pub fn violation(&self) -> Option<PolicyViolation> {
443 PolicyViolations::new(self.properties.shared(), String::default()).policy_violation()
444 }
445}
446
447impl PartialEq for RequestResponse {
448 fn eq(&self, other: &Self) -> bool {
449 self.headers == other.headers && self.body == other.body
450 }
451}
452
453impl Debug for RequestResponse {
454 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
455 f.write_str("RequestResponse {")?;
456 f.write_str("headers: ")?;
457 f.write_str(format!("{:?}", self.headers).as_str())?;
458 f.write_str("body: ")?;
459 f.write_str(format!("{:?}", String::from_utf8_lossy(self.body.as_slice())).as_str())?;
460 f.write_str("}")
461 }
462}
463
464#[derive(Default)]
466struct Properties {
467 properties: Rc<RefCell<HashMap<Vec<String>, Bytes>>>,
468}
469
470impl Clone for Properties {
471 fn clone(&self) -> Self {
472 Self {
473 properties: Rc::new(RefCell::new(self.properties.borrow().clone())),
474 }
475 }
476}
477
478impl Properties {
479 pub fn new(properties: HashMap<Vec<String>, Bytes>) -> Self {
480 Self {
481 properties: Rc::new(RefCell::new(properties)),
482 }
483 }
484
485 #[cfg(feature = "pdk")]
486 pub fn shared(&self) -> Self {
487 Self {
488 properties: Rc::clone(&self.properties),
489 }
490 }
491}
492
493#[derive(Serialize, Deserialize)]
494struct Property {
495 key: Vec<String>,
496 value: Bytes,
497}
498
499impl Serialize for Properties {
500 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
501 where
502 S: Serializer,
503 {
504 self.properties
505 .borrow()
506 .clone()
507 .into_iter()
508 .map(|(key, value)| Property { key, value })
509 .collect::<Vec<Property>>()
510 .serialize(serializer)
511 }
512}
513
514fn de_properties<'de, D>(deserializer: D) -> Result<Properties, D::Error>
515where
516 D: Deserializer<'de>,
517{
518 let exp: Vec<Property> = serde::de::Deserialize::deserialize(deserializer)?;
519 Ok(Properties {
520 properties: Rc::new(RefCell::new(
521 exp.into_iter()
522 .map(|property| (property.key, property.value))
523 .collect(),
524 )),
525 })
526}
527
528#[cfg(feature = "pdk")]
529impl PropertyAccessor for Properties {
530 fn read_property(&self, path: &[&str]) -> Option<Bytes> {
531 self.properties
532 .borrow()
533 .get(&path.iter().map(|s| s.to_string()).collect::<Vec<String>>())
534 .cloned()
535 }
536
537 fn set_property(&self, path: &[&str], value: Option<&[u8]>) {
538 match value {
539 None => {
540 self.properties
541 .borrow_mut()
542 .remove(&path.iter().map(|s| s.to_string()).collect::<Vec<String>>());
543 }
544 Some(value) => {
545 self.properties.borrow_mut().insert(
546 path.iter().map(|s| s.to_string()).collect::<Vec<String>>(),
547 value.into(),
548 );
549 }
550 }
551 }
552}
553
554#[derive(Clone, Default, Serialize, Deserialize)]
559pub struct UnitGrpcRequest {
560 service: String,
561 method: String,
562 initial_metadata: Vec<(String, Bytes)>,
563 message: Option<Bytes>,
564}
565
566impl UnitGrpcRequest {
567 pub(crate) fn new(
568 service: &str,
569 method: &str,
570 initial_metadata: Vec<(&str, &[u8])>,
571 message: Option<&[u8]>,
572 ) -> UnitGrpcRequest {
573 UnitGrpcRequest {
574 service: service.to_string(),
575 method: method.to_string(),
576 initial_metadata: initial_metadata
577 .iter()
578 .map(|(key, value)| (key.to_string(), value.to_vec()))
579 .collect(),
580 message: message.map(|m| m.to_vec()),
581 }
582 }
583
584 pub fn service(&self) -> &str {
586 &self.service
587 }
588
589 pub fn method(&self) -> &str {
591 &self.method
592 }
593
594 pub fn initial_metadata(&self) -> &Vec<(String, Bytes)> {
596 &self.initial_metadata
597 }
598
599 pub fn message(&self) -> Option<&Bytes> {
601 self.message.as_ref()
602 }
603}
604
605#[derive(Clone, Default, Serialize, Deserialize)]
619pub struct UnitGrpcResponse {
620 pub(crate) status_code: u32,
621 pub(crate) status: Option<String>,
622 pub(crate) message: Bytes,
623}
624
625impl UnitGrpcResponse {
626 pub fn with_status_code(mut self, status: u32) -> Self {
630 self.status_code = status;
631 self
632 }
633
634 pub fn with_message(mut self, message: Vec<u8>) -> Self {
636 self.message = message;
637 self
638 }
639
640 pub fn with_status<S: Into<String>>(mut self, status: S) -> Self {
642 self.status = Some(status.into());
643 self
644 }
645}
646
647#[repr(u32)]
649#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
650pub enum UnitLogLevel {
651 #[default]
652 Trace = 0,
653 Debug = 1,
654 Info = 2,
655 Warn = 3,
656 Error = 4,
657 Critical = 5,
658 Disabled = 6,
660}
661
662pub struct UnitFrame {
666 pub(crate) frame: Frame,
667}
668
669impl UnitFrame {
670 pub fn text<T: Into<Vec<u8>>>(text: T, fin: bool) -> Self {
672 Self {
673 frame: Frame::text(text, fin),
674 }
675 }
676
677 pub fn binary<T: Into<Vec<u8>>>(data: T, fin: bool) -> Self {
679 Self {
680 frame: Frame::binary(data, fin),
681 }
682 }
683
684 pub fn continuation<T: Into<Vec<u8>>>(data: T, fin: bool) -> Self {
686 Self {
687 frame: Frame::continuation(data, fin),
688 }
689 }
690
691 pub fn ping() -> Self {
693 Self {
694 frame: Frame::ping(),
695 }
696 }
697
698 pub fn pong() -> Self {
700 Self {
701 frame: Frame::pong(),
702 }
703 }
704
705 pub fn connection_close() -> Self {
707 Self {
708 frame: Frame::connection_close(),
709 }
710 }
711
712 pub fn frame_type(&self) -> UnitFrameType {
714 frame_type_from_lib(self.frame.frame_type())
715 }
716
717 pub fn data(&self) -> &[u8] {
719 self.frame.data()
720 }
721
722 pub fn take(self) -> Vec<u8> {
724 self.frame.take()
725 }
726
727 pub fn update<U: Into<Vec<u8>>>(&mut self, data: U) {
729 self.frame.update(data);
730 }
731
732 pub fn fin(&self) -> bool {
734 self.frame.fin()
735 }
736}
737
738#[derive(Debug, Clone, Copy, PartialEq)]
740pub enum UnitFrameType {
741 Text,
742 Binary,
743 Continuation,
744 Ping,
745 Pong,
746 ConnectionClose,
747 Reserved,
748}
749
750fn frame_type_from_lib(ft: FrameType) -> UnitFrameType {
751 match ft {
752 FrameType::Text => UnitFrameType::Text,
753 FrameType::Binary => UnitFrameType::Binary,
754 FrameType::Continuation => UnitFrameType::Continuation,
755 FrameType::Ping => UnitFrameType::Ping,
756 FrameType::Pong => UnitFrameType::Pong,
757 FrameType::ConnectionClose => UnitFrameType::ConnectionClose,
758 _ => UnitFrameType::Reserved,
759 }
760}