Skip to main content

varnish_sys/
extensions.rs

1use std::ffi::c_void;
2use std::ptr;
3
4use crate::ffi::{vmod_data, vmod_priv, vmod_priv_methods, vrt_ctx};
5use crate::validate_vrt_ctx;
6use crate::vcl::PerVclState;
7
8/// SAFETY: ensured by Varnish itself
9unsafe impl Sync for vmod_data {}
10
11/// Take ownership of the object of type `T` and return it as a `Box<T>`.
12/// The original pointer is set to null.
13///
14/// SAFETY: `priv_` must reference a valid `T` object pointer or `NULL`
15unsafe fn get_owned_bbox<T>(priv_: &mut *mut c_void) -> Option<Box<T>> {
16    let obj = ptr::replace(priv_, ptr::null_mut());
17    if obj.is_null() {
18        None
19    } else {
20        Some(Box::from_raw(obj.cast::<T>()))
21    }
22}
23
24impl vmod_priv {
25    /// Transfer ownership of the object to the caller, cleaning up the internal state.
26    ///
27    /// SAFETY: `priv_` must reference a valid `T` object pointer or `NULL`
28    pub unsafe fn take<T>(&mut self) -> Option<Box<T>> {
29        // methods does not need to be dropped because `put` always sets it to a static reference
30        self.methods = ptr::null();
31        get_owned_bbox(&mut self.priv_)
32    }
33
34    #[expect(clippy::unnecessary_box_returns)]
35    pub unsafe fn take_per_vcl<T>(&mut self) -> Box<PerVclState<T>> {
36        if let Some(v) = self.take::<PerVclState<T>>() {
37            v
38        } else {
39            let o = PerVclState::<T>::default();
40            Box::new(o)
41        }
42    }
43
44    /// Use the object as a reference, without taking ownership.
45    ///
46    /// SAFETY:
47    /// * `priv_` must reference a valid `T` object pointer or `NULL`
48    /// * `take()` must not be called on the same `vmod_priv` object until the returned reference is dropped
49    /// * cleanup must not be done on the object until the returned reference is dropped
50    /// * assumes `Box<T>` is equivalent to `&T` when used as a readonly reference, i.e. a box is just a pointer
51    pub unsafe fn get_ref<T>(&self) -> Option<&T> {
52        self.priv_.cast::<T>().as_ref()
53    }
54}
55
56/// SAFETY: ensured by Varnish itself
57unsafe impl Sync for vmod_priv_methods {}
58
59impl vmod_priv {
60    /// Set the object and methods for the `vmod_priv`, and the corresponding static methods.
61    ///
62    /// SAFETY: The type of `obj` must match the type of the function pointers in `methods`.
63    pub unsafe fn put<T>(&mut self, obj: Box<T>, methods: &'static vmod_priv_methods) {
64        self.priv_ = Box::into_raw(obj).cast();
65        self.methods = methods;
66    }
67
68    /// A Varnish callback function to free a `vmod_priv` object.
69    /// Here we take the ownership and immediately drop the object of type `T`.
70    /// Note that here we get `*priv_` directly, not the `*vmod_priv`
71    ///
72    /// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
73    pub unsafe extern "C" fn on_fini<T>(_ctx: *const vrt_ctx, mut priv_: *mut c_void) {
74        drop(get_owned_bbox::<T>(&mut priv_));
75    }
76
77    /// A Varnish callback function to clean up the `PerVclState` object.
78    /// Similar to `on_fini`, but also unregisters filters.
79    ///
80    /// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
81    pub unsafe extern "C" fn on_fini_per_vcl<T>(ctx: *const vrt_ctx, mut priv_: *mut c_void) {
82        if let Some(obj) = get_owned_bbox::<PerVclState<T>>(&mut priv_) {
83            let PerVclState {
84                mut fetch_filters,
85                mut delivery_filters,
86                user_data,
87            } = *obj;
88            let ctx = validate_vrt_ctx(ctx);
89            ctx.fetch_filters(&mut fetch_filters).unregister_all();
90            ctx.delivery_filters(&mut delivery_filters).unregister_all();
91            drop(user_data);
92        }
93    }
94}