cardinal_wasm_plugins/
context.rs1use 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}