pub struct Processor { /* private fields */ }Expand description
A processor for handling ESI responses
The Processor maintains state and configuration for processing ESI directives in HTML/XML content. It handles fragment inclusion, variable substitution, and conditional processing according to the ESI specification.
§Fields
ctx- Evaluation context containing variables and request metadataconfiguration- Configuration settings controlling ESI processing behavior
§Example
use esi::{Processor, Configuration};
use fastly::Request;
// Create a configuration (assuming Configuration implements Default)
let config = Configuration::default();
// Optionally, create a Request (assuming Request can be constructed or mocked)
let request = Request::get("http://example.com/");
// Initialize the Processor with optional request metadata
let processor = Processor::new(Some(request), config);Implementations§
Source§impl Processor
Implementation of the main Processor methods driving ESI processing
impl Processor
Implementation of the main Processor methods driving ESI processing
This impl block contains the core logic for processing ESI documents, including the main streaming loop, fragment dispatching, and queue management. The DocumentHandler implementation above delegates to these methods for the actual processing work, allowing the handler to focus on interfacing with the streaming architecture and the evaluation context.
pub fn new( original_request_metadata: Option<Request>, configuration: Configuration, ) -> Self
Sourcepub const fn context(&self) -> &EvalContext
pub const fn context(&self) -> &EvalContext
Get the evaluation context (for testing)
Provides access to the processor’s internal state including variables, response headers, status code, and body overrides set by ESI functions.
Sourcepub fn process_response(
self,
src_stream: &mut Response,
client_response_metadata: Option<Response>,
dispatch_fragment_request: Option<&dyn Fn(Request, Option<u32>) -> Result<PendingFragmentContent>>,
process_fragment_response: Option<&dyn Fn(&mut Request, Response) -> Result<Response>>,
) -> Result<()>
pub fn process_response( self, src_stream: &mut Response, client_response_metadata: Option<Response>, dispatch_fragment_request: Option<&dyn Fn(Request, Option<u32>) -> Result<PendingFragmentContent>>, process_fragment_response: Option<&dyn Fn(&mut Request, Response) -> Result<Response>>, ) -> Result<()>
Process a response body as an ESI document. Consumes the response body.
This method processes ESI directives in the response body while streaming the output to the client, minimizing memory usage for large responses. It handles ESI includes, conditionals, and variable substitution according to the ESI specification.
§Response Manipulation Functions
ESI functions can modify the response that gets sent to the client:
§$add_header(name, value)
Adds a custom header to the response:
<esi:vars>$add_header('X-Custom-Header', 'my-value')</esi:vars>§$set_response_code(code [, body])
Sets the HTTP status code and optionally replaces the response body:
<esi:vars>$set_response_code(404, 'Page not found')</esi:vars>§$set_redirect(url [, code])
Sets up an HTTP redirect (default 302):
<esi:vars>$set_redirect('https://example.com/new-page')</esi:vars>
<esi:vars>$set_redirect('https://example.com/moved', 301)</esi:vars>Note: These functions modify the response metadata that process_response will use
when sending the response to the client. The headers, status code, and body override are
buffered during processing and applied when the response is sent.
§Arguments
src_stream- Source HTTP response containing ESI markup to processclient_response_metadata- Optional response metadata (headers, status) to send to clientdispatch_fragment_request- Optional callback for customizing fragment request handlingprocess_fragment_response- Optional callback for processing fragment responses
§Returns
Result<()>- Ok if processing completed successfully, Error if processing failed
§Example
use fastly::Response;
use esi::{Processor, Configuration};
// Create a processor
let processor = Processor::new(None, Configuration::default());
// Create a response with ESI markup
let mut response = Response::new();
response.set_body("<esi:include src='http://example.com/header.html'/>");
// Define a simple fragment dispatcher
fn default_fragment_dispatcher(req: fastly::Request, maxwait: Option<u32>) -> esi::Result<esi::PendingFragmentContent> {
Ok(esi::PendingFragmentContent::CompletedRequest(
Box::new(fastly::Response::from_body("Fragment content"))
))
}
// Process the response, streaming the resulting document directly to the client
processor.process_response(
&mut response,
None,
Some(&default_fragment_dispatcher),
None
)?;§Errors
Returns error if:
- ESI processing fails
- Stream writing fails
- Fragment requests fail
Sourcepub fn process_stream(
&mut self,
src_stream: impl BufRead,
output_writer: &mut impl Write,
dispatch_fragment_request: Option<&dyn Fn(Request, Option<u32>) -> Result<PendingFragmentContent>>,
process_fragment_response: Option<&dyn Fn(&mut Request, Response) -> Result<Response>>,
) -> Result<()>
pub fn process_stream( &mut self, src_stream: impl BufRead, output_writer: &mut impl Write, dispatch_fragment_request: Option<&dyn Fn(Request, Option<u32>) -> Result<PendingFragmentContent>>, process_fragment_response: Option<&dyn Fn(&mut Request, Response) -> Result<Response>>, ) -> Result<()>
Process an ESI stream from any BufRead into a Write.
- Reads in 8 KB chunks, buffering only what the parser needs
- Parses incrementally; writes content as soon as it’s parsed
- Dispatches includes immediately; waits for them later in document order
- Uses
select()to harvest in-flight includes while preserving output order
For Fastly Response bodies, prefer [process_response], which wires up
cache headers and response metadata for you.
§Arguments
src_stream-BufReadsource containing ESI markup (streams in chunks)output_writer- Writer to stream processed output to (writes immediately)dispatch_fragment_request- Optional handler for fragment requestsprocess_fragment_response- Optional processor for fragment responses
§Returns
Result<()>- Ok if processing completed successfully
§Errors
Returns error if:
- ESI markup parsing fails or document is malformed
- Fragment requests fail (unless
continue_on_erroris set) - Input reading or output writing fails
- Invalid UTF-8 encoding encountered
Auto Trait Implementations§
impl !Freeze for Processor
impl !RefUnwindSafe for Processor
impl !Send for Processor
impl !Sync for Processor
impl Unpin for Processor
impl UnsafeUnpin for Processor
impl !UnwindSafe for Processor
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more