use std::ffi::CString;
use std::os::raw::{c_uint, c_void};
use crate::vcl::http::HTTP;
use crate::vcl::ws::{TestWS, WS};
use std::ptr;
use varnish_sys::{
busyobj, req, sess, vrt_ctx, vsb, vsl_log, ws, VSL_tag_e_SLT_Debug, VSL_tag_e_SLT_Error,
VSL_tag_e_SLT_VCL_Error, VSL_tag_e_SLT_Backend_health, VSL_tag_e_SLT_FetchError, VCL_HTTP, VCL_VCL, VRT_CTX_MAGIC,
VRT_fail,
};
pub enum LogTag {
Debug,
Error,
VclError,
FetchError,
BackendHealth,
Any(u32),
}
impl LogTag {
pub fn into_u32(&self) -> u32 {
match self {
LogTag::Debug => VSL_tag_e_SLT_Debug,
LogTag::Error => VSL_tag_e_SLT_Error,
LogTag::VclError => VSL_tag_e_SLT_VCL_Error,
LogTag::FetchError => VSL_tag_e_SLT_FetchError,
LogTag::BackendHealth => VSL_tag_e_SLT_Backend_health,
LogTag::Any(n) => *n,
}
}
}
pub struct Ctx<'a> {
pub raw: &'a mut varnish_sys::vrt_ctx,
pub http_req: Option<HTTP<'a>>,
pub http_req_top: Option<HTTP<'a>>,
pub http_resp: Option<HTTP<'a>>,
pub http_bereq: Option<HTTP<'a>>,
pub http_beresp: Option<HTTP<'a>>,
pub ws: WS<'a>,
}
impl<'a> Ctx<'a> {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn new(raw: *mut varnish_sys::vrt_ctx) -> Self {
let raw = unsafe { raw.as_mut().unwrap() };
assert_eq!(raw.magic, varnish_sys::VRT_CTX_MAGIC);
let http_req = HTTP::new(raw.http_req);
let http_req_top = HTTP::new(raw.http_req_top);
let http_resp = HTTP::new(raw.http_resp);
let http_bereq = HTTP::new(raw.http_bereq);
let http_beresp = HTTP::new(raw.http_beresp);
let ws = WS::new(raw.ws);
Ctx {
raw,
http_req,
http_req_top,
http_resp,
http_bereq,
http_beresp,
ws,
}
}
pub fn fail(&mut self, msg: &str) -> u8 {
let c_cstring = CString::new(msg).unwrap();
unsafe {
VRT_fail(self.raw, "%s\0".as_ptr() as *const i8, c_cstring.as_ptr());
}
0
}
pub fn log(&mut self, logtag: LogTag, msg: &str) {
unsafe {
let p = *self.raw;
if p.vsl.is_null() {
log(logtag, msg);
} else {
let t = varnish_sys::txt {
b: msg.as_ptr() as *const i8,
e: msg.as_ptr().add(msg.len()) as *const i8,
};
varnish_sys::VSLbt(p.vsl, logtag.into_u32(), t);
}
}
}
pub fn cached_req_body(&mut self) -> Result<Vec<&'a [u8]>, String> {
unsafe extern "C" fn chunk_collector<'a>(
priv_: *mut c_void,
_flush: c_uint,
ptr: *const c_void,
len: std::os::raw::c_long,
) -> std::os::raw::c_int {
let v = (priv_ as *mut Vec<&'a [u8]>).as_mut().unwrap();
let buf = std::slice::from_raw_parts(ptr as *const u8, len as usize);
v.push(buf);
0
}
let req = unsafe {
self.raw
.req
.as_mut()
.ok_or("req object isn't available".to_owned())?
};
unsafe {
if req.req_body_status != varnish_sys::BS_CACHED.as_ptr() {
return Err("request body hasn't been previously cached".to_owned());
}
}
let mut v: Box<Vec<&'a [u8]>> = Box::new(Vec::new());
let p: *mut Vec<&'a [u8]> = &mut *v;
match unsafe {
varnish_sys::VRB_Iterate(
req.wrk,
req.vsl.as_mut_ptr(),
req,
Some(chunk_collector),
p as *mut c_void,
)
} {
0 => Ok(*v),
_ => Err("req.body iteration failed".to_owned()),
}
}
}
pub struct TestCtx {
vrt_ctx: vrt_ctx,
test_ws: TestWS,
}
impl TestCtx {
pub fn new(sz: usize) -> Self {
let mut test_ctx = TestCtx {
vrt_ctx: vrt_ctx {
magic: VRT_CTX_MAGIC,
syntax: 0,
method: 0,
vclver: 0,
msg: ptr::null::<vsb>() as *mut vsb,
vsl: ptr::null::<vsl_log>() as *mut vsl_log,
vcl: ptr::null::<VCL_VCL>() as VCL_VCL,
ws: std::ptr::null_mut::<ws>(),
sp: ptr::null::<sess>() as *mut sess,
req: ptr::null::<req>() as *mut req,
http_req: ptr::null::<VCL_HTTP>() as VCL_HTTP,
http_req_top: ptr::null::<VCL_HTTP>() as VCL_HTTP,
http_resp: ptr::null::<VCL_HTTP>() as VCL_HTTP,
bo: ptr::null::<VCL_HTTP>() as *mut busyobj,
http_bereq: ptr::null::<VCL_HTTP>() as VCL_HTTP,
http_beresp: ptr::null::<VCL_HTTP>() as VCL_HTTP,
now: 0.0,
specific: ptr::null::<VCL_HTTP>() as *mut c_void,
called: ptr::null::<vsb>() as *mut c_void,
vpi: ptr::null::<vsb>() as *mut varnish_sys::wrk_vpi,
},
test_ws: TestWS::new(sz),
};
test_ctx.vrt_ctx.ws = test_ctx.test_ws.as_ptr();
test_ctx
}
pub fn ctx(&mut self) -> Ctx {
Ctx::new(&mut self.vrt_ctx)
}
}
#[test]
fn ctx_test() {
let mut test_ctx = TestCtx::new(100);
test_ctx.ctx();
}
#[derive(Debug)]
pub enum Event {
Load,
Warm,
Cold,
Discard,
}
impl Event {
pub fn new(event: varnish_sys::vcl_event_e) -> Self {
match event {
varnish_sys::vcl_event_e_VCL_EVENT_LOAD => Event::Load,
varnish_sys::vcl_event_e_VCL_EVENT_WARM => Event::Warm,
varnish_sys::vcl_event_e_VCL_EVENT_COLD => Event::Cold,
varnish_sys::vcl_event_e_VCL_EVENT_DISCARD => Event::Discard,
_ => panic!("invalid event number"),
}
}
}
pub fn log(logtag: LogTag, msg: &str) {
unsafe {
let c_cstring = CString::new(msg).unwrap();
varnish_sys::VSL(logtag.into_u32(), 0, b"%s\0".as_ptr() as *const i8, c_cstring.as_ptr() as *const u8);
}
}