#[non_exhaustive]pub struct MiddlewareHandler {
pub engine: Arc<Engine>,
pub file_path: String,
pub ast: AST,
pub confine_to: Option<PathBuf>,
}Expand description
Handler for a single Rhai middleware script.
§Why the AST is compiled once at startup
Rhai offers both “compile on every evaluation” and “compile once, re-run
the AST” modes. Middleware is invoked on the hot path (every request),
so we keep the compiled AST alongside the Engine and only evaluate
at request time. This trades a small amount of memory for a large
throughput win and keeps parse errors as startup failures instead of
per-request 500s.
The Engine is wrapped in Arc so that MiddlewareHandler can be
cloned cheaply into each request task without deep-cloning the
interpreter state.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.engine: Arc<Engine>§file_path: String§ast: AST§confine_to: Option<PathBuf>The middleware script’s own directory, canonicalised once here
at compile time. A file path the script returns is confined to
this directory the same way a rule’s respond.file_path is
confined to respond_dir — see MiddlewareResponse::file_response
(private to this crate; not linked here since rustdoc’s public
docs can’t resolve a private item, and widening its visibility
is a separate, deliberate decision — not this comment’s to make).
Implementations§
Source§impl MiddlewareHandler
impl MiddlewareHandler
Sourcepub fn new(file_path: &str, max_operations: u64) -> ServerResult<Self>
pub fn new(file_path: &str, max_operations: u64) -> ServerResult<Self>
Compile a middleware script from disk into a reusable handler.
Returns an AppError on either a missing file or a compile-time
Rhai parse error. Callers treat both as startup-time failures —
we deliberately do not try to recover by, say, skipping the offending
script, because silently ignoring a misconfigured middleware would
produce confusing request-time behaviour.
§max_operations (RFC 068 S-03)
Engine::new() used to set no limits at all — not
set_max_operations, not set_max_call_levels, not the
string/array size caps — so a non-terminating script (a while true an operator is actively developing is the ordinary case,
not an attack) ran forever. max_operations bounds a script by
work done; call-depth and string/array/map growth get fixed,
generous ceilings from limits regardless of what’s configured
here, since there’s no legitimate reason a mock middleware needs
more of either. Neither is the whole fix on its own — see
handle’s doc comment for the other half.
Sourcepub async fn handle(
&self,
request_url_path: &str,
request_body_json_value: Option<&Value>,
request_headers: &HeaderMap,
cors_allow_credentials_origins: &[String],
) -> Option<Result<Response<BoxBody>, Error>>
pub async fn handle( &self, request_url_path: &str, request_body_json_value: Option<&Value>, request_headers: &HeaderMap, cors_allow_credentials_origins: &[String], ) -> Option<Result<Response<BoxBody>, Error>>
Evaluate the middleware for one request.
Returns:
Some(Ok(response))— the script decided to handle the request and produced a response.Some(Err(_))— the script tried to handle the request but the response could not be built (e.g. invalid header value).None— the script returned a value that is neither a string nor a map, which is the convention for “let the next layer handle it”.
§Why errors here are logged and converted, not propagated
A Rhai runtime error during per-request evaluation is a script bug,
not a startup config bug. Turning it into an AppError would
force the whole process down, which is the opposite of what an
HTTP server should do. We instead log and fall through to the
next handler, producing an HTTP response rather than aborting.
§Why evaluation runs in spawn_blocking (RFC 068 S-03)
This used to call eval_ast_with_scope directly, synchronously,
on the async runtime’s own worker thread. max_operations
(Self::new) bounds a runaway script by work done, but that is
a value an operator can raise, and it does nothing for a script
blocked on something that isn’t a counted operation. Moving
evaluation into spawn_blocking is what turns the failure mode
from “one fewer tokio worker, permanently” into “one slow
request” — the same reason file reads already go through
spawn_blocking elsewhere in this crate. Rhai’s sync feature
is enabled, so Engine/AST are Send and this is possible
without a dependency change.
Trait Implementations§
Source§impl Clone for MiddlewareHandler
impl Clone for MiddlewareHandler
Source§fn clone(&self) -> MiddlewareHandler
fn clone(&self) -> MiddlewareHandler
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more