barbacane_wasm/
body_access.rs1use crate::instance::PluginInstance;
12
13pub struct BodyAccessControl {
18 metadata_json: Vec<u8>,
20 held_body: Option<Vec<u8>>,
22}
23
24impl BodyAccessControl {
25 pub fn new(metadata_json: Vec<u8>, body: Option<Vec<u8>>) -> Self {
31 Self {
32 metadata_json,
33 held_body: body,
34 }
35 }
36
37 pub fn prepare_instance(&self, instance: &mut PluginInstance, body_access: bool) -> Vec<u8> {
44 if body_access {
45 instance.set_request_body(self.held_body.clone());
46 } else {
47 instance.set_request_body(None);
48 }
49 self.metadata_json.clone()
50 }
51
52 pub fn collect_after(
58 &mut self,
59 instance: &mut PluginInstance,
60 output: Vec<u8>,
61 body_access: bool,
62 ) {
63 if !output.is_empty() {
64 self.metadata_json = output;
65 }
66 if body_access {
67 if let Some(new_body) = instance.take_output_body() {
70 self.held_body = new_body;
71 }
72 }
73 }
74
75 pub fn body(&self) -> &Option<Vec<u8>> {
77 &self.held_body
78 }
79
80 pub fn finalize(self) -> (Vec<u8>, Option<Vec<u8>>) {
82 (self.metadata_json, self.held_body)
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use serde_json::json;
90
91 fn make_metadata(headers: serde_json::Value) -> Vec<u8> {
92 serde_json::to_vec(&json!({
93 "method": "POST",
94 "path": "/upload",
95 "query": null,
96 "headers": headers,
97 "client_ip": "127.0.0.1",
98 "path_params": {}
99 }))
100 .expect("serialize")
101 }
102
103 fn parse_header(json_bytes: &[u8], key: &str) -> Option<String> {
104 let v: serde_json::Value = serde_json::from_slice(json_bytes).expect("parse JSON");
105 v["headers"][key].as_str().map(|s| s.to_string())
106 }
107
108 #[test]
111 fn new_with_body() {
112 let meta = make_metadata(json!({}));
113 let ctrl = BodyAccessControl::new(meta, Some(b"hello".to_vec()));
114 assert_eq!(ctrl.held_body, Some(b"hello".to_vec()));
115 }
116
117 #[test]
118 fn new_without_body() {
119 let meta = make_metadata(json!({}));
120 let ctrl = BodyAccessControl::new(meta, None);
121 assert_eq!(ctrl.held_body, None);
122 }
123
124 #[test]
127 fn finalize_returns_metadata_and_body() {
128 let meta = make_metadata(json!({"content-type": "text/plain"}));
129 let body = Some(b"the body".to_vec());
130 let ctrl = BodyAccessControl::new(meta.clone(), body.clone());
131
132 let (final_meta, final_body) = ctrl.finalize();
133 assert_eq!(final_meta, meta);
134 assert_eq!(final_body, body);
135 }
136
137 #[test]
138 fn finalize_none_body() {
139 let meta = make_metadata(json!({}));
140 let ctrl = BodyAccessControl::new(meta, None);
141
142 let (_final_meta, final_body) = ctrl.finalize();
143 assert_eq!(final_body, None);
144 }
145
146 #[test]
151 fn collect_updates_metadata_from_non_empty_output() {
152 let meta = make_metadata(json!({}));
153 let new_meta = make_metadata(json!({"x-added": "value"}));
154 let mut ctrl = BodyAccessControl::new(meta, Some(b"body".to_vec()));
155
156 ctrl.metadata_json = new_meta.clone();
159
160 assert_eq!(
161 parse_header(&ctrl.metadata_json, "x-added"),
162 Some("value".to_string())
163 );
164 assert_eq!(ctrl.held_body, Some(b"body".to_vec()));
166 }
167
168 #[test]
169 fn body_accessor_returns_held_body() {
170 let meta = make_metadata(json!({}));
171 let ctrl = BodyAccessControl::new(meta, Some(b"raw bytes".to_vec()));
172 assert_eq!(ctrl.body(), &Some(b"raw bytes".to_vec()));
173 }
174}