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: 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: HeaderMap,
110        query: HashMap<String, Vec<String>>,
111        body: Option<Bytes>,
112        persistent_vars: Arc<RwLock<HashMap<String, String>>>,
113    ) -> Self {
114        let query_store = QueryStore::new(query);
115        Self {
116            headers,
117            query: Arc::new(query_store),
118            body,
119            persistent_vars,
120        }
121    }
122
123    pub fn empty() -> Self {
124        Self {
125            headers: HeaderMap::new(),
126            query: Arc::new(QueryStore::new(HashMap::new())),
127            body: None,
128            persistent_vars: Arc::new(RwLock::new(HashMap::new())),
129        }
130    }
131
132    pub fn headers(&self) -> &HeaderMap {
133        &self.headers
134    }
135
136    pub fn headers_mut(&mut self) -> &mut HeaderMap {
137        &mut self.headers
138    }
139
140    pub fn header_bytes(&self, name: &str) -> Option<Vec<u8>> {
141        let header_name = HeaderName::from_bytes(name.as_bytes()).ok()?;
142        self.headers
143            .get(&header_name)
144            .map(|value| value.as_bytes().to_vec())
145    }
146
147    pub fn query_first(&self, key: &str) -> Option<String> {
148        self.query.get_first(key)
149    }
150
151    pub fn query_entries(&self) -> HashMap<String, Vec<String>> {
152        self.query.to_hash_map()
153    }
154
155    pub fn body(&self) -> Option<&Bytes> {
156        self.body.as_ref()
157    }
158
159    pub fn set_body(&mut self, body: Option<Bytes>) {
160        self.body = body;
161    }
162
163    pub fn persistent_vars(&self) -> &Arc<RwLock<HashMap<String, String>>> {
164        &self.persistent_vars
165    }
166}
167
168impl Default for RequestState {
169    fn default() -> Self {
170        Self::empty()
171    }
172}
173
174#[derive(Clone, Default, Debug)]
175pub struct ExecutionContext {
176    memory: Option<Memory>,
177    request: RequestState,
178    response: ResponseState,
179}
180
181impl ExecutionContext {
182    pub fn new() -> Self {
183        Self::default()
184    }
185
186    pub fn with_response(response: ResponseState) -> Self {
187        Self {
188            response,
189            ..Self::default()
190        }
191    }
192
193    pub fn from_parts(
194        req_headers: HeaderMap,
195        query: HashMap<String, Vec<String>>,
196        body: Option<Bytes>,
197        response: ResponseState,
198        persistent_vars: Arc<RwLock<HashMap<String, String>>>,
199    ) -> Self {
200        let request = RequestState::new(req_headers, query, body, persistent_vars);
201        Self {
202            memory: None,
203            request,
204            response,
205        }
206    }
207
208    pub fn replace_memory(&mut self, memory: Memory) {
209        self.memory.replace(memory);
210    }
211
212    pub fn memory(&self) -> &Option<Memory> {
213        &self.memory
214    }
215
216    pub fn memory_mut(&mut self) -> &mut Option<Memory> {
217        &mut self.memory
218    }
219
220    pub fn request(&self) -> &RequestState {
221        &self.request
222    }
223
224    pub fn request_mut(&mut self) -> &mut RequestState {
225        &mut self.request
226    }
227
228    pub fn response(&self) -> &ResponseState {
229        &self.response
230    }
231
232    pub fn response_mut(&mut self) -> &mut ResponseState {
233        &mut self.response
234    }
235
236    pub fn persistent_vars(&self) -> &Arc<RwLock<HashMap<String, String>>> {
237        self.request.persistent_vars()
238    }
239}
240
241pub type SharedExecutionContext = Arc<RwLock<ExecutionContext>>;
242
243fn header_map_from_hashmap(headers: HashMap<String, String>) -> HeaderMap {
244    let mut header_map = HeaderMap::with_capacity(headers.len());
245    for (key, value) in headers {
246        if let (Ok(name), Ok(val)) = (
247            HeaderName::from_bytes(key.as_bytes()),
248            HeaderValue::from_str(&value),
249        ) {
250            header_map.append(name, val);
251        }
252    }
253    header_map
254}