pub struct Ctx<'a> {
pub raw: &'a mut vrt_ctx,
pub http_req: Option<HttpHeaders<'a>>,
pub http_req_top: Option<HttpHeaders<'a>>,
pub http_resp: Option<HttpHeaders<'a>>,
pub http_bereq: Option<HttpHeaders<'a>>,
pub http_beresp: Option<HttpHeaders<'a>>,
pub ws: Workspace<'a>,
/* private fields */
}Expand description
VCL context
A mutable reference to this structure is always passed to vmod functions and provides access to the available HTTP objects, as well as the workspace.
This struct is a pure Rust structure, mirroring some of the C fields, so you should always use
the provided methods to interact with them. If they are not enough, the raw field is actually
the C original pointer that can be used to directly, and unsafely, act on the structure.
Which http_* are present will depend on which VCL sub routine the function is called from.
use varnish::vcl::Ctx;
fn foo(ctx: &Ctx) {
if let Some(ref req) = ctx.http_req {
for (name, value) in req {
println!("header {name} has value {value:?}");
}
}
}Fields§
§raw: &'a mut vrt_ctx§http_req: Option<HttpHeaders<'a>>§http_req_top: Option<HttpHeaders<'a>>§http_resp: Option<HttpHeaders<'a>>§http_bereq: Option<HttpHeaders<'a>>§http_beresp: Option<HttpHeaders<'a>>§ws: Workspace<'a>Implementations§
Source§impl<'a> Ctx<'a>
impl<'a> Ctx<'a>
Sourcepub unsafe fn from_ptr(ptr: *const vrt_ctx) -> Self
pub unsafe fn from_ptr(ptr: *const vrt_ctx) -> Self
Wrap a raw pointer into an object we can use.
The pointer must be non-null, and the magic must match
Sourcepub fn from_ref(raw: &'a mut vrt_ctx) -> Self
pub fn from_ref(raw: &'a mut vrt_ctx) -> Self
Instantiate from a mutable reference to a vrt_ctx.
Sourcepub fn fail(&mut self, msg: impl Into<VclError>)
pub fn fail(&mut self, msg: impl Into<VclError>)
Log an error message and fail the current VSL task.
Once the control goes back to Varnish, it will see that the transaction was marked as fail and will return a synthetic error to the client.
Sourcepub fn log(&mut self, tag: LogTag, msg: impl AsRef<str>)
pub fn log(&mut self, tag: LogTag, msg: impl AsRef<str>)
Log a message, attached to the current context
Sourcepub fn acl_match(&self, acl: &Acl, addr: SocketAddr) -> bool
pub fn acl_match(&self, acl: &Acl, addr: SocketAddr) -> bool
Match an ACL against a provided address.
Sourcepub fn local_socket(&self) -> Result<&'a str, VclError>
pub fn local_socket(&self) -> Result<&'a str, VclError>
Return the name of the listener socket that received the current request.
This corresponds to the VCL variable local.socket and returns the -a socket
name (e.g., "a0", "http-80"). Returns an Err in backend context where the
session isn’t available, or if the name is non-UTF-8.
Sourcepub fn local_endpoint(&self) -> Result<&'a str, VclError>
pub fn local_endpoint(&self) -> Result<&'a str, VclError>
Return the address of the local endpoint that received the current request.
This corresponds to the VCL variable local.endpoint and returns the address
string (e.g., "127.0.0.1:8080", "/var/run/varnish.sock"). Returns an Err in
backend context where the session isn’t available, or if the value is non-UTF-8.
Sourcepub fn call_sub(&mut self, sub: Subroutine) -> Result<bool, VclError>
pub fn call_sub(&mut self, sub: Subroutine) -> Result<bool, VclError>
Call a VCL subroutine.
Returns Ok(true) if the request was handled after the call, Ok(false) otherwise.
Returns Err if the subroutine cannot be called in the current context (e.g. wrong VCL
state or incompatible subroutine type).
If Ok(true) was returned, no other subroutine can be called, and doing so will result
in a VCL error.
Sourcepub fn check_call_sub(&self, sub: Subroutine) -> Result<(), VclError>
pub fn check_call_sub(&self, sub: Subroutine) -> Result<(), VclError>
Check whether a VCL subroutine can be called in the current context.
Returns Ok(()) if the call is valid, or Err with the reason otherwise.
Sourcepub fn is_handled(&self) -> bool
pub fn is_handled(&self) -> bool
Returns true if the current request has already been handled.
If true, no other subroutine can be called, and doing so will result
in a VCL error.
Sourcepub fn cached_req_body(&mut self) -> Result<Vec<&'a [u8]>, VclError>
pub fn cached_req_body(&mut self) -> Result<Vec<&'a [u8]>, VclError>
Retrieve the cached request body as a list of byte slices.
Returns slices pointing into the workspace; each slice is a contiguous chunk of the body.
Fails if the body has not been cached (i.e. std.cache_req_body() was not called in VCL
before this subroutine ran).
Sourcepub fn req_body_state(&self) -> VclResult<BodyState>
pub fn req_body_state(&self) -> VclResult<BodyState>
Return the current state of the request body — bereq’s body from a
backend context, or the client req’s body directly if called earlier
(vcl_recv and later, before any backend is involved).
From backend context (busyobj set - typically
VclBackend::get_response): if
the body has already been cached as an object (e.g. after
std.cache_req_body(), or on a fetch retry), returns
BodyState::Cached; otherwise reflects the live client body’s state,
or BodyState::None if there is no client request to read from.
From client context (no busyobj yet, e.g. vcl_recv/vcl_hash): reflects
req’s own state directly - BodyState::Cached after
std.cache_req_body(), otherwise whatever the live, not-yet-consumed
client body’s state is.
Sourcepub fn req_body<W: Write>(&mut self, writer: &mut W) -> VclResult<bool>
pub fn req_body<W: Write>(&mut self, writer: &mut W) -> VclResult<bool>
Copy the request body into writer — bereq’s body from a backend
context, or the client req’s body directly if called earlier
(vcl_recv and later, before any backend is involved).
From backend context (busyobj set - typically
VclBackend::get_response):
transparently handles both a body already cached as an object (e.g.
after std.cache_req_body(), or on a fetch retry) and a body streamed
live from the client, hiding the underlying ObjIterate/VRB_Iterate
choice and bookkeeping.
From client context (no busyobj yet, e.g. vcl_recv/vcl_hash): reads
req’s body directly, same ObjIterate/VRB_Iterate machinery, minus
the busyobj-specific no_retry/doclose bookkeeping (there’s no fetch
yet to retry or close).
Read-once tradeoff: per Varnish’s own rule, an uncached body can be
read exactly once - either by you here, or later by whatever backend
ends up handling this request (a custom
VclBackend::get_response,
or a plain upstream backend forwarding it). Read it once in vcl_recv
without caching first, and that later read fails
(BodyState::Taken/an error), not this one. Call std.cache_req_body()
before reading if the body needs to survive for a backend (or a retry)
to read too - check first if you’re not sure:
match ctx.req_body_state()? {
BodyState::Cached => {
// safe: a cached body can be read here and still be read again
// later (by a backend, or after a retry).
let mut buf = Vec::new();
ctx.req_body(&mut buf)?;
}
BodyState::None => {
// no body at all - nothing to read, nothing to worry about.
}
BodyState::Length | BodyState::Chunked | BodyState::Eof => {
// live and not cached: reading now consumes it. Only do this if
// you're sure no backend/retry downstream also needs it, or call
// `std.cache_req_body()` first if they might.
}
BodyState::Taken | BodyState::Error => {
// already gone (consumed elsewhere) or failed - nothing left to read.
}
}To consume the body without keeping it, pass std::io::sink() as writer.
writer is only ever fed non-empty chunks — a custom Write impl
doesn’t need to handle a zero-length buf in its write.
Returns Ok(false) without touching writer if there is no body at all.
Returns Ok(true) once the full body has been copied into writer.
Returns Err(_) if called outside both a backend and a client context,
if the body stream itself failed to read, or if writer errors (the
io::Error is captured and turned into a VclError). Mirroring
upstream’s V1F_SendReq, a failure while iterating an already-cached
body is not treated as fatal on its own (only a writer error is).
Side effect (backend context only): if the body isn’t already cached,
reading it marks the fetch as non-retryable (bo.no_retry), mirroring
V1F_SendReq — call std.cache_req_body() in vcl_recv first if the
backend may need to retry after reading the body.