1use std::ffi::{c_int, c_void, CStr};
9use std::ptr;
10
11use crate::ffi::{vdp_ctx, vfp_ctx, vfp_entry, vrt_ctx, VdpAction, VfpStatus};
12use crate::vcl::{Ctx, VclError};
13use crate::{ffi, validate_vfp_ctx, validate_vfp_entry};
14
15#[derive(Debug, Copy, Clone)]
17pub enum PushResult {
18 Err,
20 Ok,
22 End,
24}
25
26#[derive(Debug, Copy, Clone)]
28pub enum PullResult {
29 Err,
31 Ok(usize),
34 End(usize),
36}
37
38#[derive(Debug)]
40pub enum InitResult<T> {
41 Err(VclError),
42 Ok(T),
43 Pass,
44}
45
46pub trait DeliveryProcessor: Sized {
48 fn name() -> &'static CStr;
50 fn new(vrt_ctx: &mut Ctx, vdp_ctx: &mut DeliveryProcCtx) -> InitResult<Self>;
53 fn push(&mut self, ctx: &mut DeliveryProcCtx, act: VdpAction, buf: &[u8]) -> PushResult;
56}
57
58pub unsafe extern "C" fn gen_vdp_init<T: DeliveryProcessor>(
59 vrt_ctx: *const vrt_ctx,
60 ctx_raw: *mut vdp_ctx,
61 priv_: *mut *mut c_void,
62 #[cfg(varnishsys_7_5_objcore_init)] _oc: *mut ffi::objcore,
63) -> c_int {
64 assert_ne!(priv_, ptr::null_mut());
65 assert_eq!(*priv_, ptr::null_mut());
66 match T::new(
67 &mut Ctx::from_ptr(vrt_ctx),
68 &mut DeliveryProcCtx::from_ptr(ctx_raw),
69 ) {
70 InitResult::Ok(proc) => {
71 *priv_ = Box::into_raw(Box::new(proc)).cast::<c_void>();
72 0
73 }
74 InitResult::Err(_) => -1, InitResult::Pass => 1,
76 }
77}
78
79pub unsafe extern "C" fn gen_vdp_fini<T: DeliveryProcessor>(
80 _: *mut vdp_ctx,
81 priv_: *mut *mut c_void,
82) -> c_int {
83 if !priv_.is_null() {
84 assert_ne!(*priv_, ptr::null_mut());
85 drop(Box::from_raw((*priv_).cast::<T>()));
86 *priv_ = ptr::null_mut();
87 }
88
89 0
90}
91
92pub unsafe extern "C" fn gen_vdp_push<T: DeliveryProcessor>(
93 ctx_raw: *mut vdp_ctx,
94 act: VdpAction,
95 priv_: *mut *mut c_void,
96 ptr: *const c_void,
97 len: isize,
98) -> c_int {
99 assert_ne!(priv_, ptr::null_mut());
100 assert_ne!(*priv_, ptr::null_mut());
101 if !matches!(act, VdpAction::Null | VdpAction::Flush | VdpAction::End) {
102 return 1; }
104
105 let buf = if ptr.is_null() {
106 &[0; 0]
107 } else {
108 std::slice::from_raw_parts(ptr.cast::<u8>(), len as usize)
109 };
110
111 match (*(*priv_).cast::<T>()).push(&mut DeliveryProcCtx::from_ptr(ctx_raw), act, buf) {
112 PushResult::Err => -1, PushResult::Ok => 0,
114 PushResult::End => 1,
115 }
116}
117
118pub fn new_vdp<T: DeliveryProcessor>() -> ffi::vdp {
120 ffi::vdp {
121 name: T::name().as_ptr(),
122 init: Some(gen_vdp_init::<T>),
123 bytes: Some(gen_vdp_push::<T>),
124 fini: Some(gen_vdp_fini::<T>),
125 priv1: ptr::null(),
126 }
127}
128
129#[derive(Debug)]
131pub struct DeliveryProcCtx<'a> {
132 pub raw: &'a mut vdp_ctx,
133}
134
135impl DeliveryProcCtx<'_> {
136 pub(crate) unsafe fn from_ptr(raw: *mut vdp_ctx) -> Self {
142 let raw = raw.as_mut().unwrap();
143 assert_eq!(raw.magic, ffi::VDP_CTX_MAGIC);
144 Self { raw }
145 }
146
147 pub fn push(&mut self, act: VdpAction, buf: &[u8]) -> PushResult {
149 match unsafe {
150 ffi::VDP_bytes(
151 self.raw,
152 act,
153 buf.as_ptr().cast::<c_void>(),
154 buf.len() as isize,
155 )
156 } {
157 r if r < 0 => PushResult::Err,
158 0 => PushResult::Ok,
159 _ => PushResult::End,
160 }
161 }
162}
163
164pub trait FetchProcessor: Sized {
166 fn name() -> &'static CStr;
168 fn new(vrt_ctx: &mut Ctx, vfp_ctx: &mut FetchProcCtx) -> InitResult<Self>;
170 fn pull(&mut self, ctx: &mut FetchProcCtx, buf: &mut [u8]) -> PullResult;
173}
174
175unsafe extern "C" fn wrap_vfp_init<T: FetchProcessor>(
176 vrt_ctx: *const vrt_ctx,
177 ctxp: *mut vfp_ctx,
178 vfep: *mut vfp_entry,
179) -> VfpStatus {
180 let ctx = validate_vfp_ctx(ctxp);
181 let vfe = validate_vfp_entry(vfep);
182 match T::new(
183 &mut Ctx::from_ptr(vrt_ctx),
184 &mut FetchProcCtx::from_ptr(ctx),
185 ) {
186 InitResult::Ok(proc) => {
187 vfe.priv1 = Box::into_raw(Box::new(proc)).cast::<c_void>();
188 VfpStatus::Ok
189 }
190 InitResult::Err(_) => VfpStatus::Error, InitResult::Pass => VfpStatus::End,
192 }
193}
194
195pub unsafe extern "C" fn wrap_vfp_pull<T: FetchProcessor>(
196 ctxp: *mut vfp_ctx,
197 vfep: *mut vfp_entry,
198 ptr: *mut c_void,
199 len: *mut isize,
200) -> VfpStatus {
201 let ctx = validate_vfp_ctx(ctxp);
202 let vfe = validate_vfp_entry(vfep);
203 let buf = if ptr.is_null() {
204 [0; 0].as_mut()
205 } else {
206 std::slice::from_raw_parts_mut(ptr.cast::<u8>(), *len as usize)
207 };
208 let obj = vfe.priv1.cast::<T>().as_mut().unwrap();
209 match obj.pull(&mut FetchProcCtx::from_ptr(ctx), buf) {
210 PullResult::Err => VfpStatus::Error, PullResult::Ok(l) => {
212 *len = l as isize;
213 VfpStatus::Ok
214 }
215 PullResult::End(l) => {
216 *len = l as isize;
217 VfpStatus::End
218 }
219 }
220}
221
222pub unsafe extern "C" fn wrap_vfp_fini<T: FetchProcessor>(
223 ctxp: *mut vfp_ctx,
224 vfep: *mut vfp_entry,
225) {
226 validate_vfp_ctx(ctxp);
227 let vfe = validate_vfp_entry(vfep);
228 if !vfe.priv1.is_null() {
229 let p = ptr::replace(&mut vfe.priv1, ptr::null_mut());
230 drop(Box::from_raw(p.cast::<T>()));
231 }
232}
233
234pub fn new_vfp<T: FetchProcessor>() -> ffi::vfp {
236 ffi::vfp {
237 name: T::name().as_ptr(),
238 init: Some(wrap_vfp_init::<T>),
239 pull: Some(wrap_vfp_pull::<T>),
240 fini: Some(wrap_vfp_fini::<T>),
241 priv1: ptr::null(),
242 }
243}
244
245#[derive(Debug)]
247pub struct FetchProcCtx<'a> {
248 pub raw: &'a mut vfp_ctx,
249}
250
251impl FetchProcCtx<'_> {
252 pub(crate) unsafe fn from_ptr(raw: *mut vfp_ctx) -> Self {
258 Self {
259 raw: validate_vfp_ctx(raw),
260 }
261 }
262
263 pub fn pull(&mut self, buf: &mut [u8]) -> PullResult {
265 let mut len = buf.len() as isize;
266 let max_len = len;
267
268 match unsafe { ffi::VFP_Suck(self.raw, buf.as_ptr() as *mut c_void, &mut len) } {
269 VfpStatus::Ok => {
270 assert!(len <= max_len);
271 assert!(len >= 0);
272 PullResult::Ok(len as usize)
273 }
274 VfpStatus::End => {
275 assert!(len <= max_len);
276 assert!(len >= 0);
277 PullResult::End(len as usize)
278 }
279 VfpStatus::Error => PullResult::Err,
280 VfpStatus::Null => panic!("VFP_Suck() was never supposed to return VFP_NULL!"),
281 #[expect(unreachable_patterns)]
284 n => panic!("unknown VfpStatus {n:?}"),
285 }
286 }
287}
288
289#[derive(Debug)]
290pub struct FetchFilters<'c, 'f> {
291 ctx: &'c vrt_ctx,
292 #[expect(clippy::vec_box)]
295 filters: &'f mut Vec<Box<ffi::vfp>>,
296}
297
298impl<'c, 'f> FetchFilters<'c, 'f> {
299 #[expect(clippy::vec_box)]
300 pub(crate) fn new(ctx: &'c vrt_ctx, filters: &'f mut Vec<Box<ffi::vfp>>) -> Self {
301 Self { ctx, filters }
302 }
303
304 fn find_position<T: FetchProcessor>(&self) -> Option<usize> {
305 let name = T::name().as_ptr();
306 self.filters.iter().position(|f| f.name == name)
307 }
308
309 pub fn register<T: FetchProcessor>(&mut self) -> bool {
310 if self.find_position::<T>().is_none() {
311 let instance = Box::new(new_vfp::<T>());
312 unsafe {
313 ffi::VRT_AddVFP(self.ctx, instance.as_ref());
314 }
315 self.filters.push(instance);
316 true
317 } else {
318 false
319 }
320 }
321
322 pub fn unregister<T: FetchProcessor>(&mut self) -> bool {
323 if let Some(pos) = self.find_position::<T>() {
324 let filter = self.filters.swap_remove(pos);
325 unsafe {
326 ffi::VRT_RemoveVFP(self.ctx, filter.as_ref());
327 }
328 true
329 } else {
330 false
331 }
332 }
333
334 pub fn unregister_all(&mut self) {
335 for filter in self.filters.drain(..) {
336 unsafe { ffi::VRT_RemoveVFP(self.ctx, filter.as_ref()) }
337 }
338 }
339}
340
341#[derive(Debug)]
342pub struct DeliveryFilters<'c, 'f> {
343 ctx: &'c vrt_ctx,
344 #[expect(clippy::vec_box)]
347 filters: &'f mut Vec<Box<ffi::vdp>>,
348}
349
350impl<'c, 'f> DeliveryFilters<'c, 'f> {
351 #[expect(clippy::vec_box)]
352 pub(crate) fn new(ctx: &'c vrt_ctx, filters: &'f mut Vec<Box<ffi::vdp>>) -> Self {
353 Self { ctx, filters }
354 }
355
356 fn find_position<T: DeliveryProcessor>(&self) -> Option<usize> {
357 let name = T::name().as_ptr();
358 self.filters.iter().position(|f| f.name == name)
359 }
360
361 pub fn register<T: DeliveryProcessor>(&mut self) -> bool {
362 if self.find_position::<T>().is_none() {
363 let instance = Box::new(new_vdp::<T>());
364 unsafe {
365 ffi::VRT_AddVDP(self.ctx, instance.as_ref());
366 }
367 self.filters.push(instance);
368 true
369 } else {
370 false
371 }
372 }
373
374 pub fn unregister<T: DeliveryProcessor>(&mut self) -> bool {
375 if let Some(pos) = self.find_position::<T>() {
376 let filter = self.filters.swap_remove(pos);
377 unsafe {
378 ffi::VRT_RemoveVDP(self.ctx, filter.as_ref());
379 }
380 true
381 } else {
382 false
383 }
384 }
385
386 pub fn unregister_all(&mut self) {
387 for filter in self.filters.drain(..) {
388 unsafe { ffi::VRT_RemoveVDP(self.ctx, filter.as_ref()) }
389 }
390 }
391}