Skip to main content

http_acl/
mutation.rs

1//! Contains the [`ModifyRequestFn`], [`ModifyResponseFn`], [`RequestMutation`], and
2//! [`ResponseMutation`] types used to attach request/response mutation hooks to an
3//! [`HttpAcl`](crate::HttpAcl).
4
5use std::sync::Arc;
6
7use bytes::Bytes;
8
9use crate::utils::authority::Authority;
10
11/// An owned, mutable view of an outgoing request's headers and body, handed to a
12/// [`ModifyRequestFn`].
13///
14/// Headers are a `Vec<(String, String)>` rather than a map, so order is preserved
15/// and duplicate header names are kept as separate entries rather than collapsed.
16#[derive(Clone, Debug, Default, PartialEq)]
17pub struct RequestMutation {
18    /// The request's headers, in wire order.
19    pub headers: Vec<(String, String)>,
20    /// The request's body, if any and if readable.
21    ///
22    /// `None` here means there was either no body to begin with, or the body exists
23    /// but couldn't be read without consuming a stream (the same limitation
24    /// [`HttpAcl::is_valid`](crate::HttpAcl::is_valid)'s body parameter already has).
25    /// Leaving this as `None` on the way out never clears an existing body - it is
26    /// only ever an instruction to leave the body untouched, so a [`ModifyRequestFn`]
27    /// that only wants to touch headers can never accidentally truncate a body it was
28    /// never shown. Set it to `Some(bytes)` to replace the body wholesale.
29    pub body: Option<Bytes>,
30}
31
32/// An owned, mutable view of an incoming response's status, headers, and body,
33/// handed to a [`ModifyResponseFn`].
34///
35/// Unlike [`RequestMutation::body`], this is always the full, already-buffered
36/// body - a [`ModifyResponseFn`] is only ever invoked once the whole response has
37/// been read into memory. See
38/// [`HttpAcl::has_modify_response`](crate::HttpAcl::has_modify_response) for the
39/// performance implications of that.
40#[derive(Clone, Debug, Default, PartialEq)]
41pub struct ResponseMutation {
42    /// The response's HTTP status code.
43    pub status: u16,
44    /// The response's headers, in wire order. See [`RequestMutation::headers`].
45    pub headers: Vec<(String, String)>,
46    /// The response's body.
47    pub body: Bytes,
48}
49
50/// A function that mutates an outgoing request's headers and/or body before it is
51/// sent, e.g. to inject a secret or authentication header.
52///
53/// Called with the request's scheme and authority (host and port), the same context
54/// [`ValidateFn`](crate::ValidateFn) gets, so a single [`HttpAcl`](crate::HttpAcl)
55/// shared across multiple hosts can scope what it injects to a specific destination
56/// rather than leaking it to every host the ACL allows.
57///
58/// A `ModifyRequestFn` is attached via
59/// [`HttpAclBuilder::build_full`](crate::HttpAclBuilder::build_full) or
60/// [`HttpAclBuilder::try_build_full`](crate::HttpAclBuilder::try_build_full) (as part
61/// of an [`HttpAclHooks`](crate::HttpAclHooks)) rather than a dedicated builder
62/// setter, for the same reason [`ValidateFn`](crate::ValidateFn) is: it typically
63/// captures state from outside the builder.
64pub type ModifyRequestFn = Arc<dyn Fn(&str, &Authority, &mut RequestMutation) + Send + Sync>;
65
66/// A function that mutates an incoming response's status, headers, and/or body
67/// before the caller sees it, e.g. to redact sensitive fields.
68///
69/// Called with the *request's* scheme and authority (i.e. where the response came
70/// from) and a [`ResponseMutation`] to mutate in place. See [`ModifyRequestFn`] for
71/// why it isn't attached via a dedicated builder setter.
72///
73/// Attaching a `ModifyResponseFn` forces the entire response body to be buffered
74/// into memory and the response rebuilt, for every request the ACL is used with -
75/// there is no way to opt in per-request. See
76/// [`HttpAcl::has_modify_response`](crate::HttpAcl::has_modify_response).
77pub type ModifyResponseFn = Arc<dyn Fn(&str, &Authority, &mut ResponseMutation) + Send + Sync>;