cardinal_wasm_plugins/
context.rs

1use bytes::Bytes;
2use http::{HeaderMap, HeaderName, HeaderValue};
3use parking_lot::RwLock;
4use std::collections::HashMap;
5use std::sync::Arc;
6use wasmer::Memory;
7
8#[derive(Clone, Debug)]
9pub struct ResponseState {
10    headers: HeaderMap,
11    status: u16,
12    status_overridden: bool,
13}
14
15impl ResponseState {
16    pub fn with_default_status(status: u16) -> Self {
17        Self::from_parts(HeaderMap::new(), status, false)
18    }
19
20    pub fn from_parts(headers: HeaderMap, status: u16, status_overridden: bool) -> Self {
21        Self {
22            headers,
23            status,
24            status_overridden,
25        }
26    }
27
28    pub fn from_hash_map(
29        headers: HashMap<String, String>,
30        status: u16,
31        status_overridden: bool,
32    ) -> Self {
33        let map = header_map_from_hashmap(headers);
34        Self::from_parts(map, status, status_overridden)
35    }
36
37    pub fn headers(&self) -> &HeaderMap {
38        &self.headers
39    }
40
41    pub fn headers_mut(&mut self) -> &mut HeaderMap {
42        &mut self.headers
43    }
44
45    pub fn insert_header(&mut self, name: HeaderName, value: HeaderValue) {
46        self.headers.insert(name, value);
47    }
48
49    pub fn status(&self) -> u16 {
50        self.status
51    }
52
53    pub fn set_status(&mut self, status: u16) {
54        self.status = status;
55        self.status_overridden = true;
56    }
57
58    pub fn status_override(&self) -> Option<u16> {
59        self.status_overridden.then_some(self.status)
60    }
61}
62
63impl Default for ResponseState {
64    fn default() -> Self {
65        Self::with_default_status(0)
66    }
67}
68
69#[derive(Debug)]
70struct QueryStore {
71    entries: HashMap<String, Arc<Vec<String>>>,
72}
73
74impl QueryStore {
75    fn new(entries: HashMap<String, Vec<String>>) -> Self {
76        let mut map = HashMap::with_capacity(entries.len());
77        for (key, values) in entries {
78            let normalized = key.to_ascii_lowercase();
79            map.insert(normalized, Arc::new(values));
80        }
81        Self { entries: map }
82    }
83
84    fn get_first(&self, key: &str) -> Option<String> {
85        let normalized = key.to_ascii_lowercase();
86        self.entries
87            .get(&normalized)
88            .and_then(|values| values.first().cloned())
89    }
90
91    fn to_hash_map(&self) -> HashMap<String, Vec<String>> {
92        self.entries
93            .iter()
94            .map(|(key, values)| (key.clone(), (**values).clone()))
95            .collect()
96    }
97}
98
99#[derive(Clone, Debug)]
100pub struct RequestState {
101    headers: Arc<HeaderMap>,
102    query: Arc<QueryStore>,
103    body: Option<Bytes>,
104    persistent_vars: Arc<RwLock<HashMap<String, String>>>,
105}
106
107impl RequestState {
108    pub fn new(
109        headers: HashMap<String, String>,
110        query: HashMap<String, Vec<String>>,
111        body: Option<Bytes>,
112        persistent_vars: Arc<RwLock<HashMap<String, String>>>,
113    ) -> Self {
114        let header_map = header_map_from_hashmap(headers);
115        let query_store = QueryStore::new(query);
116        Self {
117            headers: Arc::new(header_map),
118            query: Arc::new(query_store),
119            body,
120            persistent_vars,
121        }
122    }
123
124    pub fn empty() -> Self {
125        Self {
126            headers: Arc::new(HeaderMap::new()),
127            query: Arc::new(QueryStore::new(HashMap::new())),
128            body: None,
129            persistent_vars: Arc::new(RwLock::new(HashMap::new())),
130        }
131    }
132
133    pub fn headers(&self) -> &HeaderMap {
134        &self.headers
135    }
136
137    pub fn header_bytes(&self, name: &str) -> Option<Vec<u8>> {
138        let header_name = HeaderName::from_bytes(name.as_bytes()).ok()?;
139        self.headers
140            .get(&header_name)
141            .map(|value| value.as_bytes().to_vec())
142    }
143
144    pub fn query_first(&self, key: &str) -> Option<String> {
145        self.query.get_first(key)
146    }
147
148    pub fn query_entries(&self) -> HashMap<String, Vec<String>> {
149        self.query.to_hash_map()
150    }
151
152    pub fn body(&self) -> Option<&Bytes> {
153        self.body.as_ref()
154    }
155
156    pub fn set_body(&mut self, body: Option<Bytes>) {
157        self.body = body;
158    }
159
160    pub fn persistent_vars(&self) -> &Arc<RwLock<HashMap<String, String>>> {
161        &self.persistent_vars
162    }
163}
164
165impl Default for RequestState {
166    fn default() -> Self {
167        Self::empty()
168    }
169}
170
171#[derive(Clone, Default, Debug)]
172pub struct ExecutionContext {
173    memory: Option<Memory>,
174    request: RequestState,
175    response: ResponseState,
176}
177
178impl ExecutionContext {
179    pub fn new() -> Self {
180        Self::default()
181    }
182
183    pub fn with_response(response: ResponseState) -> Self {
184        Self {
185            response,
186            ..Self::default()
187        }
188    }
189
190    pub fn from_parts(
191        req_headers: HashMap<String, String>,
192        query: HashMap<String, Vec<String>>,
193        body: Option<Bytes>,
194        response: ResponseState,
195        persistent_vars: Arc<RwLock<HashMap<String, String>>>,
196    ) -> Self {
197        let request = RequestState::new(req_headers, query, body, persistent_vars);
198        Self {
199            memory: None,
200            request,
201            response,
202        }
203    }
204
205    pub fn replace_memory(&mut self, memory: Memory) {
206        self.memory.replace(memory);
207    }
208
209    pub fn memory(&self) -> &Option<Memory> {
210        &self.memory
211    }
212
213    pub fn memory_mut(&mut self) -> &mut Option<Memory> {
214        &mut self.memory
215    }
216
217    pub fn request(&self) -> &RequestState {
218        &self.request
219    }
220
221    pub fn request_mut(&mut self) -> &mut RequestState {
222        &mut self.request
223    }
224
225    pub fn response(&self) -> &ResponseState {
226        &self.response
227    }
228
229    pub fn response_mut(&mut self) -> &mut ResponseState {
230        &mut self.response
231    }
232
233    pub fn persistent_vars(&self) -> &Arc<RwLock<HashMap<String, String>>> {
234        self.request.persistent_vars()
235    }
236}
237
238pub type SharedExecutionContext = Arc<RwLock<ExecutionContext>>;
239
240fn header_map_from_hashmap(headers: HashMap<String, String>) -> HeaderMap {
241    let mut header_map = HeaderMap::with_capacity(headers.len());
242    for (key, value) in headers {
243        if let (Ok(name), Ok(val)) = (
244            HeaderName::from_bytes(key.as_bytes()),
245            HeaderValue::from_str(&value),
246        ) {
247            header_map.append(name, val);
248        }
249    }
250    header_map
251}