1#[cfg(not(varnishsys_6))]
4use std::ffi::{c_int, c_uint, c_void};
5
6use crate::ffi;
7use crate::ffi::{vrt_ctx, VRT_fail, VRT_CTX_MAGIC};
8use crate::vcl::{HttpHeaders, LogTag, TestWS, VclError, Workspace};
9
10#[derive(Debug)]
34pub struct Ctx<'a> {
35 pub raw: &'a mut vrt_ctx,
36 pub http_req: Option<HttpHeaders<'a>>,
37 pub http_req_top: Option<HttpHeaders<'a>>,
38 pub http_resp: Option<HttpHeaders<'a>>,
39 pub http_bereq: Option<HttpHeaders<'a>>,
40 pub http_beresp: Option<HttpHeaders<'a>>,
41 pub ws: Workspace<'a>,
42}
43
44impl<'a> Ctx<'a> {
45 pub unsafe fn from_ptr(ptr: *const vrt_ctx) -> Self {
49 Self::from_ref(ptr.cast_mut().as_mut().unwrap())
50 }
51
52 #[cfg_attr(not(varnishsys_6), expect(clippy::useless_conversion))] pub fn from_ref(raw: &'a mut vrt_ctx) -> Self {
55 assert_eq!(raw.magic, VRT_CTX_MAGIC);
56 Self {
57 http_req: HttpHeaders::from_ptr(raw.http_req.into()),
58 http_req_top: HttpHeaders::from_ptr(raw.http_req_top.into()),
59 http_resp: HttpHeaders::from_ptr(raw.http_resp.into()),
60 http_bereq: HttpHeaders::from_ptr(raw.http_bereq.into()),
61 http_beresp: HttpHeaders::from_ptr(raw.http_beresp.into()),
62 ws: Workspace::from_ptr(raw.ws),
63 raw,
64 }
65 }
66
67 pub fn fail(&mut self, msg: impl Into<VclError>) {
72 let msg = msg.into();
73 let msg = msg.as_str();
74 unsafe {
75 VRT_fail(self.raw, c"%.*s".as_ptr(), msg.len(), msg.as_ptr());
76 }
77 }
78
79 pub fn log(&mut self, tag: LogTag, msg: impl AsRef<str>) {
81 unsafe {
82 let vsl = self.raw.vsl;
83 if vsl.is_null() {
84 log(tag, msg);
85 } else {
86 let msg = ffi::txt::from_str(msg.as_ref());
87 ffi::VSLbt(vsl, tag, msg);
88 }
89 }
90 }
91 #[cfg(not(varnishsys_6))]
92 pub fn cached_req_body(&mut self) -> Result<Vec<&'a [u8]>, VclError> {
93 unsafe extern "C" fn chunk_collector(
94 priv_: *mut c_void,
95 _flush: c_uint,
96 ptr: *const c_void,
97 len: isize,
98 ) -> c_int {
99 let v = priv_.cast::<Vec<&[u8]>>().as_mut().unwrap();
100 let buf = std::slice::from_raw_parts(ptr.cast::<u8>(), len as usize);
101 v.push(buf);
102 0
103 }
104
105 let req = unsafe { self.raw.req.as_mut().ok_or("req object isn't available")? };
106 unsafe {
107 if req.req_body_status != ffi::BS_CACHED.as_ptr() {
108 return Err("request body hasn't been previously cached".into());
109 }
110 }
111 let mut v: Box<Vec<&'a [u8]>> = Box::default();
112 let p: *mut Vec<&'a [u8]> = &raw mut *v;
113 match unsafe {
114 ffi::VRB_Iterate(
115 req.wrk,
116 req.vsl.as_mut_ptr(),
117 req,
118 Some(chunk_collector),
119 p.cast::<c_void>(),
120 )
121 } {
122 0 => Ok(*v),
123 _ => Err("req.body iteration failed".into()),
124 }
125 }
126}
127
128#[derive(Debug)]
133pub struct TestCtx {
134 vrt_ctx: vrt_ctx,
135 test_ws: TestWS,
136}
137
138impl TestCtx {
139 pub fn new(sz: usize) -> Self {
141 let mut test_ctx = Self {
142 vrt_ctx: vrt_ctx {
143 magic: VRT_CTX_MAGIC,
144 ..vrt_ctx::default()
145 },
146 test_ws: TestWS::new(sz),
147 };
148 test_ctx.vrt_ctx.ws = test_ctx.test_ws.as_ptr();
149 test_ctx
150 }
151
152 pub fn ctx(&mut self) -> Ctx<'_> {
153 Ctx::from_ref(&mut self.vrt_ctx)
154 }
155}
156
157pub fn log(tag: LogTag, msg: impl AsRef<str>) {
158 let msg = msg.as_ref();
159 #[cfg(not(varnishsys_6))]
160 unsafe {
161 let vxids = ffi::vxids::default();
162 ffi::VSL(tag, vxids, c"%.*s".as_ptr(), msg.len(), msg.as_ptr());
163 }
164 #[cfg(varnishsys_6)]
165 unsafe {
166 ffi::VSL(tag, 0, c"%.*s".as_ptr(), msg.len(), msg.as_ptr());
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn ctx_test() {
176 let mut test_ctx = TestCtx::new(100);
177 test_ctx.ctx();
178 }
179}
180
181#[doc(hidden)]
184#[derive(Debug)]
185pub struct PerVclState<T> {
186 #[cfg(not(varnishsys_6))]
187 #[expect(clippy::vec_box)] pub fetch_filters: Vec<Box<ffi::vfp>>,
189 #[cfg(not(varnishsys_6))]
190 #[expect(clippy::vec_box)] pub delivery_filters: Vec<Box<ffi::vdp>>,
192 pub user_data: Option<Box<T>>,
193}
194
195impl<T> Default for PerVclState<T> {
197 fn default() -> Self {
198 Self {
199 #[cfg(not(varnishsys_6))]
200 fetch_filters: Vec::default(),
201 #[cfg(not(varnishsys_6))]
202 delivery_filters: Vec::default(),
203 user_data: None,
204 }
205 }
206}
207
208impl<T> PerVclState<T> {
209 pub fn get_user_data(&self) -> Option<&T> {
210 self.user_data.as_ref().map(AsRef::as_ref)
211 }
212}