Skip to main content

Ctx

Struct Ctx 

Source
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>

Source

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

Source

pub fn from_ref(raw: &'a mut vrt_ctx) -> Self

Instantiate from a mutable reference to a vrt_ctx.

Source

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.

Source

pub fn log(&mut self, tag: LogTag, msg: impl AsRef<str>)

Log a message, attached to the current context

Source

pub fn acl_match(&self, acl: &Acl, addr: SocketAddr) -> bool

Match an ACL against a provided address.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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).

Source

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.

Source

pub fn req_body<W: Write>(&mut self, writer: &mut W) -> VclResult<bool>

Copy the request body into writerbereq’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.

Source

pub fn req(&self) -> Option<&Req<'_>>

Return a shared reference to the client request object, if present.

Returns None outside of client-facing VCL contexts (e.g. in backend subroutines).

Source

pub fn req_mut(&mut self) -> Option<&mut Req<'a>>

Return a mutable reference to the client request object, if present.

Returns None outside of client-facing VCL contexts (e.g. in backend subroutines).

Trait Implementations§

Source§

impl<'a> Debug for Ctx<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> !Send for Ctx<'a>

§

impl<'a> !Sync for Ctx<'a>

§

impl<'a> !UnwindSafe for Ctx<'a>

§

impl<'a> Freeze for Ctx<'a>

§

impl<'a> RefUnwindSafe for Ctx<'a>

§

impl<'a> Unpin for Ctx<'a>

§

impl<'a> UnsafeUnpin for Ctx<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.