varnish_sys/
extensions.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use std::ffi::c_void;
use std::ptr;
use std::ptr::null;

use crate::ffi::{vmod_priv, vmod_priv_methods, vrt_ctx};
use crate::validate_vrt_ctx;
use crate::vcl::PerVclState;

/// SAFETY: ensured by Varnish itself
unsafe impl Sync for vmod_priv_methods {}

impl vmod_priv {
    /// Transfer ownership of the object to the caller, cleaning up the internal state.
    ///
    /// SAFETY: `priv_` must reference a valid `T` object pointer or `NULL`
    pub unsafe fn take<T>(&mut self) -> Option<Box<T>> {
        // methods does not need to be dropped because `put` always sets it to a static reference
        self.methods = null();
        get_owned_bbox(&mut self.priv_)
    }

    pub unsafe fn take_per_vcl<T>(&mut self) -> Box<PerVclState<T>> {
        if let Some(v) = self.take::<PerVclState<T>>() {
            v
        } else {
            let o = PerVclState::<T>::default();
            Box::new(o)
        }
    }

    /// Set the object and methods for the `vmod_priv`, and the corresponding static methods.
    ///
    /// SAFETY: The type of `obj` must match the type of the function pointers in `methods`.
    pub unsafe fn put<T>(&mut self, obj: Box<T>, methods: &'static vmod_priv_methods) {
        self.priv_ = Box::into_raw(obj).cast();
        self.methods = methods;
    }

    /// Use the object as a reference, without taking ownership.
    ///
    /// SAFETY:
    /// * `priv_` must reference a valid `T` object pointer or `NULL`
    /// * `take()` must not be called on the same `vmod_priv` object until the returned reference is dropped
    /// * cleanup must not be done on the object until the returned reference is dropped
    /// * assumes `Box<T>` is equivalent to `&T` when used as a readonly reference, i.e. a box is just a pointer
    pub unsafe fn get_ref<T>(&self) -> Option<&T> {
        self.priv_.cast::<T>().as_ref()
    }

    /// A Varnish callback function to free a `vmod_priv` object.
    /// Here we take the ownership and immediately drop the object of type `T`.
    /// Note that here we get `*priv_` directly, not the `*vmod_priv`
    ///
    /// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
    pub unsafe extern "C" fn on_fini<T>(_ctx: *const vrt_ctx, mut priv_: *mut c_void) {
        drop(get_owned_bbox::<T>(&mut priv_));
    }

    /// A Varnish callback function to clean up the `PerVclState` object.
    /// Similar to `on_fini`, but also unregisters filters.
    ///
    /// SAFETY: `priv_` must be a valid pointer to a `T` object or `NULL`.
    pub unsafe extern "C" fn on_fini_per_vcl<T>(ctx: *const vrt_ctx, mut priv_: *mut c_void) {
        if let Some(obj) = get_owned_bbox::<PerVclState<T>>(&mut priv_) {
            let PerVclState {
                mut fetch_filters,
                mut delivery_filters,
                user_data,
            } = *obj;
            let ctx = validate_vrt_ctx(ctx);
            ctx.fetch_filters(&mut fetch_filters).unregister_all();
            ctx.delivery_filters(&mut delivery_filters).unregister_all();
            drop(user_data);
        }
    }
}

/// Take ownership of the object of type `T` and return it as a `Box<T>`.
/// The original pointer is set to null.
///
/// SAFETY: `priv_` must reference a valid `T` object pointer or `NULL`
unsafe fn get_owned_bbox<T>(priv_: &mut *mut c_void) -> Option<Box<T>> {
    let obj = ptr::replace(priv_, ptr::null_mut());
    if obj.is_null() {
        None
    } else {
        Some(Box::from_raw(obj.cast::<T>()))
    }
}