use std::os::raw::c_int;
use std::os::raw::c_void;
use std::ptr;
use crate::vcl::ctx::Ctx;
use varnish_sys::{objcore, ssize_t, vdp_ctx, vfp_ctx, vfp_entry};
#[derive(Debug, Copy, Clone)]
pub enum PushAction {
None = varnish_sys::vdp_action_VDP_NULL as isize,
Flush = varnish_sys::vdp_action_VDP_FLUSH as isize,
End = varnish_sys::vdp_action_VDP_END as isize,
}
#[derive(Debug, Copy, Clone)]
pub enum PushResult {
Err,
Ok,
End,
}
#[derive(Debug, Copy, Clone)]
pub enum PullResult {
Err,
Ok(usize),
End(usize),
}
#[derive(Debug)]
pub enum InitResult<T> {
Err(String),
Ok(T),
Pass,
}
pub trait VDP
where
Self: Sized,
{
fn new(vrt_ctx: &Ctx, vdp_ctx: &mut VDPCtx, oc: *mut varnish_sys::objcore) -> InitResult<Self>;
fn push(&mut self, ctx: &mut VDPCtx, act: PushAction, buf: &[u8]) -> PushResult;
fn name() -> &'static str ;
}
pub unsafe extern "C" fn gen_vdp_init<T: VDP>(
vrt_ctx: *const varnish_sys::vrt_ctx,
ctx_raw: *mut vdp_ctx,
priv_: *mut *mut c_void,
oc: *mut objcore,
) -> c_int {
assert_ne!(priv_, ptr::null_mut());
assert_eq!(*priv_, ptr::null_mut());
match T::new(&Ctx::new(vrt_ctx as *mut varnish_sys::vrt_ctx), &mut VDPCtx::new(ctx_raw), oc) {
InitResult::Ok(proc) => {
*priv_ = Box::into_raw(Box::new(proc)) as *mut c_void;
0
}
InitResult::Err(_) => -1, InitResult::Pass => 1,
}
}
pub unsafe extern "C" fn gen_vdp_fini<T: VDP>(
_: *mut vdp_ctx,
priv_: *mut *mut c_void,
) -> std::os::raw::c_int {
if priv_.is_null() {
return 0;
}
assert_ne!(*priv_, ptr::null_mut());
drop(Box::from_raw(*priv_ as *mut T));
*priv_ = ptr::null_mut();
0
}
pub unsafe extern "C" fn gen_vdp_push<T: VDP>(
ctx_raw: *mut vdp_ctx,
act: varnish_sys::vdp_action,
priv_: *mut *mut c_void,
ptr: *const c_void,
len: ssize_t,
) -> c_int {
assert_ne!(priv_, ptr::null_mut());
assert_ne!(*priv_, ptr::null_mut());
let obj = (*priv_ as *mut T).as_mut().unwrap();
let out_action = match act {
varnish_sys::vdp_action_VDP_NULL => PushAction::None,
varnish_sys::vdp_action_VDP_FLUSH => PushAction::Flush,
varnish_sys::vdp_action_VDP_END => PushAction::End,
_ => return 1,
};
let buf = std::slice::from_raw_parts(ptr as *const u8, len as usize);
match obj.push(&mut VDPCtx::new(ctx_raw), out_action, buf) {
PushResult::Err => -1, PushResult::Ok => 0,
PushResult::End => 1,
}
}
pub fn new_vdp<T: VDP>() -> varnish_sys::vdp {
varnish_sys::vdp {
name: T::name().as_ptr() as *const i8,
init: Some(gen_vdp_init::<T>),
bytes: Some(gen_vdp_push::<T>),
fini: Some(gen_vdp_fini::<T>),
}
}
pub struct VDPCtx<'a> {
pub raw: &'a mut varnish_sys::vdp_ctx,
}
impl<'a> VDPCtx<'a> {
pub unsafe fn new(raw: *mut varnish_sys::vdp_ctx) -> Self {
let raw = raw.as_mut().unwrap();
assert_eq!(raw.magic, varnish_sys::VDP_CTX_MAGIC);
VDPCtx { raw }
}
pub fn push(&mut self, act: PushAction, buf: &[u8]) -> PushResult {
match unsafe {
varnish_sys::VDP_bytes(
self.raw,
act as std::os::raw::c_uint,
buf.as_ptr() as *const c_void,
buf.len() as varnish_sys::ssize_t,
)
} {
r if r < 0 => PushResult::Err,
0 => PushResult::Ok,
_ => PushResult::End,
}
}
}
pub trait VFP
where
Self: Sized,
{
fn new(_vrt_ctx: &Ctx, _vfp_ctx: &mut VFPCtx) -> InitResult<Self> { unimplemented!() }
fn pull(&mut self, ctx: &mut VFPCtx, buf: &mut [u8]) -> PullResult;
fn name() -> &'static str { unimplemented!() }
}
unsafe extern "C" fn wrap_vfp_init<T: VFP>(
vrt_ctx: *const varnish_sys::vrt_ctx,
ctxp: *mut varnish_sys::vfp_ctx,
vfep: *mut vfp_entry,
) -> varnish_sys::vfp_status {
let ctx = ctxp.as_mut().unwrap();
assert_eq!(ctx.magic, varnish_sys::VFP_CTX_MAGIC);
let vfe = vfep.as_mut().unwrap();
assert_eq!(vfe.magic, varnish_sys::VFP_ENTRY_MAGIC);
match T::new(&Ctx::new(vrt_ctx as *mut varnish_sys::vrt_ctx), &mut VFPCtx::new(ctx)) {
InitResult::Ok(proc) => {
vfe.priv1 = Box::into_raw(Box::new(proc)) as *mut c_void;
0
}
InitResult::Err(_) => -1, InitResult::Pass => 1,
}
}
pub unsafe extern "C" fn wrap_vfp_pull<T: VFP>(
ctxp: *mut varnish_sys::vfp_ctx,
vfep: *mut varnish_sys::vfp_entry,
ptr: *mut c_void,
len: *mut ssize_t,
) -> varnish_sys::vfp_status {
let ctx = ctxp.as_mut().unwrap();
assert_eq!(ctx.magic, varnish_sys::VFP_CTX_MAGIC);
let vfe = vfep.as_mut().unwrap();
assert_eq!(vfe.magic, varnish_sys::VFP_ENTRY_MAGIC);
let buf = std::slice::from_raw_parts_mut(ptr as *mut u8, *len as usize);
let obj = (vfe.priv1 as *mut T).as_mut().unwrap();
match obj.pull(&mut VFPCtx::new(ctx), buf) {
PullResult::Err => varnish_sys::vfp_status_VFP_ERROR, PullResult::Ok(l) => {
*len = l as ssize_t;
varnish_sys::vfp_status_VFP_OK
}
PullResult::End(l) => {
*len = l as ssize_t;
varnish_sys::vfp_status_VFP_END
}
}
}
pub unsafe extern "C" fn wrap_vfp_fini<T: VFP>(ctxp: *mut vfp_ctx, vfep: *mut vfp_entry) {
let ctx = ctxp.as_mut().unwrap();
assert_eq!(ctx.magic, varnish_sys::VFP_CTX_MAGIC);
let vfe = vfep.as_mut().unwrap();
assert_eq!(vfe.magic, varnish_sys::VFP_ENTRY_MAGIC);
drop(Box::from_raw(vfe.priv1 as *mut T));
vfe.priv1 = ptr::null_mut();
}
pub fn new_vfp<T: VFP>() -> varnish_sys::vfp {
varnish_sys::vfp {
name: T::name().as_ptr() as *const i8,
init: Some(wrap_vfp_init::<T>),
pull: Some(wrap_vfp_pull::<T>),
fini: Some(wrap_vfp_fini::<T>),
priv1: ptr::null(),
}
}
pub struct VFPCtx<'a> {
pub raw: &'a mut varnish_sys::vfp_ctx,
}
impl<'a> VFPCtx<'a> {
pub unsafe fn new(raw: *mut varnish_sys::vfp_ctx) -> Self {
let raw = raw.as_mut().unwrap();
assert_eq!(raw.magic, varnish_sys::VFP_CTX_MAGIC);
VFPCtx { raw }
}
pub fn pull(&mut self, buf: &mut [u8]) -> PullResult {
let mut len = buf.len() as varnish_sys::ssize_t;
let max_len = len;
match unsafe { varnish_sys::VFP_Suck(self.raw, buf.as_ptr() as *mut c_void, &mut len) } {
varnish_sys::vfp_status_VFP_OK => {
assert!(len <= max_len);
assert!(len >= 0);
PullResult::Ok(len as usize)
}
varnish_sys::vfp_status_VFP_END => {
assert!(len <= max_len);
assert!(len >= 0);
PullResult::End(len as usize)
}
varnish_sys::vfp_status_VFP_ERROR => PullResult::Err,
n => panic!("unknown vfp_status: {}", n),
}
}
}