1use crate::*;
3
4#[macro_export]
7macro_rules! args {
8 ($input:expr, $index:expr, $ty:ident) => {
9 match $input[$index].$ty() {
10 Some(x) => x,
11 None => return Err($crate::Error::msg("Invalid input type"))
12 }
13 };
14 ($input:expr, $(($index:expr, $ty:ident)),*$(,)?) => {
15 ($(
16 $crate::args!($input, $index, $ty),
17 )*)
18 };
19}
20
21pub(crate) fn config_get(
25 mut caller: Caller<Internal>,
26 input: &[Val],
27 output: &mut [Val],
28) -> Result<(), Error> {
29 let data: &mut Internal = caller.data_mut();
30
31 let offset = args!(input, 0, i64) as u64;
32 let key = data.memory_read_str(offset)?;
33 let key = unsafe {
34 std::str::from_utf8_unchecked(std::slice::from_raw_parts(key.as_ptr(), key.len()))
35 };
36 let val = data.internal().manifest.as_ref().config.get(key);
37 let ptr = val.map(|x| (x.len(), x.as_ptr()));
38 let mem = match ptr {
39 Some((len, ptr)) => {
40 let bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
41 data.memory_alloc_bytes(bytes)?
42 }
43 None => {
44 output[0] = Val::I64(0);
45 return Ok(());
46 }
47 };
48 output[0] = Val::I64(mem as i64);
49 Ok(())
50}
51
52pub(crate) fn var_get(
56 mut caller: Caller<Internal>,
57 input: &[Val],
58 output: &mut [Val],
59) -> Result<(), Error> {
60 let data: &mut Internal = caller.data_mut();
61
62 let offset = args!(input, 0, i64) as u64;
63 let key = data.memory_read_str(offset)?;
64 let key = unsafe {
65 std::str::from_utf8_unchecked(std::slice::from_raw_parts(key.as_ptr(), key.len()))
66 };
67 let val = data.internal().vars.get(key);
68 let ptr = val.map(|x| (x.len(), x.as_ptr()));
69 let mem = match ptr {
70 Some((len, ptr)) => {
71 let bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
72 data.memory_alloc_bytes(bytes)?
73 }
74 None => {
75 output[0] = Val::I64(0);
76 return Ok(());
77 }
78 };
79 output[0] = Val::I64(mem as i64);
80 Ok(())
81}
82
83pub(crate) fn var_set(
87 mut caller: Caller<Internal>,
88 input: &[Val],
89 _output: &mut [Val],
90) -> Result<(), Error> {
91 let data: &mut Internal = caller.data_mut();
92
93 let mut size = 0;
94 for v in data.vars.values() {
95 size += v.len();
96 }
97
98 let voffset = args!(input, 1, i64) as u64;
99
100 if size > 1024 * 1024 * 100 && voffset != 0 {
102 return Err(Error::msg("Variable store is full"));
103 }
104
105 let key_offs = args!(input, 0, i64) as u64;
106 let key = {
107 let key = data.memory_read_str(key_offs)?;
108 let key_len = key.len();
109 let key_ptr = key.as_ptr();
110 unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(key_ptr, key_len)) }
111 };
112
113 if voffset == 0 {
115 data.vars.remove(key);
116 return Ok(());
117 }
118
119 let vlen = data.memory_length(voffset);
120 let value = data.memory_read(voffset, vlen).to_vec();
121
122 data.vars.insert(key.to_string(), value);
124
125 Ok(())
126}
127
128pub(crate) fn http_request(
132 #[allow(unused_mut)] mut caller: Caller<Internal>,
133 input: &[Val],
134 output: &mut [Val],
135) -> Result<(), Error> {
136 #[cfg(not(feature = "http"))]
137 {
138 let _ = (caller, input);
139
140 output[0] = Val::I64(0);
141 error!("http_request is not enabled");
142 return Ok(());
143 }
144
145 #[cfg(feature = "http")]
146 {
147 use std::io::Read;
148 let data: &mut Internal = caller.data_mut();
149 let http_req_offset = args!(input, 0, i64) as u64;
150
151 let http_req_len = data.memory_length(http_req_offset);
152 let req: extism_manifest::HttpRequest =
153 serde_json::from_slice(data.memory_read(http_req_offset, http_req_len))?;
154
155 let body_offset = args!(input, 1, i64) as u64;
156
157 let url = match url::Url::parse(&req.url) {
158 Ok(u) => u,
159 Err(e) => return Err(Error::msg(format!("Invalid URL: {e:?}"))),
160 };
161 let allowed_hosts = &data.internal().manifest.as_ref().allowed_hosts;
162 let host_str = url.host_str().unwrap_or_default();
163 let host_matches = if let Some(allowed_hosts) = allowed_hosts {
164 allowed_hosts.iter().any(|url| {
165 let pat = match glob::Pattern::new(url) {
166 Ok(x) => x,
167 Err(_) => return url == host_str,
168 };
169
170 pat.matches(host_str)
171 })
172 } else {
173 false
174 };
175
176 if !host_matches {
177 return Err(Error::msg(format!(
178 "HTTP request to {} is not allowed",
179 req.url
180 )));
181 }
182
183 let mut r = ureq::request(req.method.as_deref().unwrap_or("GET"), &req.url);
184
185 for (k, v) in req.headers.iter() {
186 r = r.set(k, v);
187 }
188
189 let res = if body_offset > 0 {
190 let len = data.memory_length(body_offset);
191 let buf = data.memory_read(body_offset, len);
192 r.send_bytes(buf)
193 } else {
194 r.call()
195 };
196
197 let reader = match res {
198 Ok(res) => {
199 data.http_status = res.status();
200 Some(res.into_reader())
201 }
202 Err(e) => {
203 log::error!("Unable to make HTTP request: {:?}", e);
204 if let Some(res) = e.into_response() {
205 data.http_status = res.status();
206 Some(res.into_reader())
207 } else {
208 None
209 }
210 }
211 };
212
213 if let Some(reader) = reader {
214 let mut buf = Vec::new();
215 reader
216 .take(1024 * 1024 * 50) .read_to_end(&mut buf)?;
218
219 let mem = data.memory_alloc_bytes(buf)?;
220 output[0] = Val::I64(mem as i64);
221 } else {
222 output[0] = Val::I64(0);
223 }
224
225 Ok(())
226 }
227}
228
229pub(crate) fn http_status_code(
233 mut caller: Caller<Internal>,
234 _input: &[Val],
235 output: &mut [Val],
236) -> Result<(), Error> {
237 let data: &mut Internal = caller.data_mut();
238 output[0] = Val::I32(data.http_status as i32);
239 Ok(())
240}
241
242pub fn log(
243 level: log::Level,
244 mut caller: Caller<Internal>,
245 input: &[Val],
246 _output: &mut [Val],
247) -> Result<(), Error> {
248 let data: &mut Internal = caller.data_mut();
249 let offset = args!(input, 0, i64) as u64;
250 let buf = data.memory_read_str(offset);
251
252 match buf {
253 Ok(buf) => log::log!(level, "{}", buf),
254 Err(_) => log::log!(level, "{:?}", buf),
255 }
256 Ok(())
257}
258
259pub(crate) fn log_warn(
263 caller: Caller<Internal>,
264 input: &[Val],
265 _output: &mut [Val],
266) -> Result<(), Error> {
267 log(log::Level::Warn, caller, input, _output)
268}
269
270pub(crate) fn log_info(
274 caller: Caller<Internal>,
275 input: &[Val],
276 _output: &mut [Val],
277) -> Result<(), Error> {
278 log(log::Level::Info, caller, input, _output)
279}
280
281pub(crate) fn log_debug(
285 caller: Caller<Internal>,
286 input: &[Val],
287 _output: &mut [Val],
288) -> Result<(), Error> {
289 log(log::Level::Debug, caller, input, _output)
290}
291
292pub(crate) fn log_error(
296 caller: Caller<Internal>,
297 input: &[Val],
298 _output: &mut [Val],
299) -> Result<(), Error> {
300 log(log::Level::Error, caller, input, _output)
301}