### Shell: Install Viceroy for Testing Source: https://github.com/fastly/esi/blob/main/esi/README.md This shell command installs the `viceroy` tool, which is required to run the test suite for the ESI project. `viceroy` is a tool that simulates Fastly Compute environments. ```shell cargo install viceroy ``` -------------------------------- ### ESI Conditional Processing with Source: https://context7.com/fastly/esi/llms.txt Demonstrates conditional content rendering using , , and tags. Supports direct comparisons, regex pattern matching (case-sensitive and insensitive), capture groups, comparison operators, logical operators, and negation. ```html

User ID:

Page

``` -------------------------------- ### Rust ESI Processing with Fastly Compute Source: https://context7.com/fastly/esi/llms.txt Demonstrates a complete Fastly Compute service in Rust that integrates with the ESI library. It handles incoming requests, fetches ESI documents from an origin, processes them with custom logic for fragment dispatching and response transformation, and sends the final response to the client. It specifically handles HTML content types and includes error handling for the overall request. ```rust use fastly::{http::StatusCode, mime, Error, Request, Response}; use esi::{Processor, Configuration, PendingFragmentContent}; fn main() { if let Err(err) = handle_request(Request::from_client()) { Response::from_status(StatusCode::INTERNAL_SERVER_ERROR) .with_body(err.to_string()) .send_to_client(); } } fn handle_request(req: Request) -> Result<(), Error> { // Fetch ESI document from origin let mut beresp = req.clone_without_body().send("origin_0")?; // Only process HTML responses if !beresp.get_content_type().is_some_and(|c| c.subtype() == mime::HTML) { beresp.send_to_client(); return Ok(()); } let processor = Processor::new( Some(req), Configuration::default() ); processor.process_response( &mut beresp, Some(Response::from_status(StatusCode::OK) .with_content_type(mime::TEXT_HTML) .with_header("X-ESI-Processed", "true")), Some(&|req| { // Route fragment requests to appropriate backends let backend = if req.get_url().host_str() == Some("api.internal") { "api-backend" } else { "content-backend" }; Ok(req.with_ttl(300).send_async(backend)?.into()) }), Some(&|req, mut resp| { // Log and optionally transform fragment responses println!("Fragment {} -> {}", req.get_path(), resp.get_status()); // Treat 404s as empty content instead of errors if resp.get_status() == StatusCode::NOT_FOUND { resp = Response::from_body(""); resp.set_status(StatusCode::OK); } Ok(resp) }), )?; Ok(()) } ``` -------------------------------- ### Create ESI Processor Instance - Rust Source: https://context7.com/fastly/esi/llms.txt Creates a new ESI processor instance with optional original request metadata and configuration settings. The processor maintains state for processing ESI directives in HTML/XML content. Supports default configuration, original client request, and custom namespaces. ```rust use esi::{Processor, Configuration}; use fastly::Request; // Create processor with default configuration let processor = Processor::new(None, Configuration::default()); // Create processor with original client request for fragment requests let req = Request::from_client(); let processor = Processor::new(Some(req), Configuration::default()); // Create processor with custom namespace (matches instead of ) let config = Configuration::default().with_namespace("app"); let processor = Processor::new(None, config); ``` -------------------------------- ### Rust: Process ESI Document for Fastly Compute Source: https://github.com/fastly/esi/blob/main/esi/README.md This Rust code snippet demonstrates how to use the `fastly-esi` crate to process an ESI document fetched from a backend. It checks the content type, initializes an ESI processor, and handles the response, including sending fragment requests and processing fragment responses. It requires the `fastly` crate and `esi` crate. ```rust use fastly::{http::StatusCode, mime, Error, Request, Response}; fn main() { if let Err(err) = handle_request(Request::from_client()) { println!("returning error response"); Response::from_status(StatusCode::INTERNAL_SERVER_ERROR) .with_body(err.to_string()) .send_to_client(); } } fn handle_request(req: Request) -> Result<(), Error> { // Fetch ESI document from backend. let mut beresp = req.clone_without_body().send("origin_0")?; // If the response is HTML, we can parse it for ESI tags. if beresp .get_content_type() .map(|c| c.subtype() == mime::HTML) .unwrap_or(false) { let processor = esi::Processor::new( // The original client request. Some(req), // Use the default ESI configuration. esi::Configuration::default() ); processor.process_response( // The ESI source document. Note that the body will be consumed. &mut beresp, // Optionally provide a template for the client response. Some(Response::from_status(StatusCode::OK).with_content_type(mime::TEXT_HTML)), // Provide logic for sending fragment requests, otherwise the hostname // of the request URL will be used as the backend name. Some(&|req| { println!("Sending request {} {}", req.get_method(), req.get_path()); Ok(req.with_ttl(120).send_async("mock-s3")?.into()) }), // Optionally provide a method to process fragment responses before they // are streamed to the client. Some(&|req, resp| { println!( "Received response for {} {}", req.get_method(), req.get_path() ); Ok(resp) }), )?; } else { // Otherwise, we can just return the response. beresp.send_to_client(); } Ok(()) } ``` -------------------------------- ### ESI Try/Attempt/Except Error Handling (HTML) Source: https://context7.com/fastly/esi/llms.txt Implements error handling for ESI includes using the ``, ``, and `` tags. The content within `` is processed first, and if any include within it fails, the content in `` is rendered as a fallback. ```html
Content temporarily unavailable
``` -------------------------------- ### Configure ESI Processor Behavior (Rust) Source: https://context7.com/fastly/esi/llms.txt Customize ESI processor settings such as namespace and URL escaping. The default configuration uses the 'esi' namespace and enables URL escaping. You can modify these settings using methods like `with_namespace` and `with_escaped`. ```rust use esi::Configuration; // Default configuration (namespace: "esi", escaped content: true) let config = Configuration::default(); // Custom namespace - matches instead of let config = Configuration::default().with_namespace("app"); // Disable URL unescaping for non-HTML templates (e.g., JSON) let config = Configuration::default().with_escaped(false); // Combined configuration let config = Configuration::default() .with_namespace("custom") .with_escaped(false); ``` -------------------------------- ### Processor::new - Create ESI Processor Source: https://context7.com/fastly/esi/llms.txt Creates a new ESI processor instance. You can optionally provide original request metadata and configuration settings. The processor maintains the state required for processing ESI directives within HTML/XML content. ```APIDOC ## Processor::new - Create ESI Processor ### Description Creates a new ESI processor instance with optional original request metadata and configuration settings. The processor maintains state for processing ESI directives in HTML/XML content. ### Method `new` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use esi::{Processor, Configuration}; use fastly::Request; // Create processor with default configuration let processor = Processor::new(None, Configuration::default()); // Create processor with original client request for fragment requests let req = Request::from_client(); let processor = Processor::new(Some(req), Configuration::default()); // Create processor with custom namespace (matches instead of ) let config = Configuration::default().with_namespace("app"); let processor = Processor::new(None, config); ``` ### Response #### Success Response (200) An instance of the `Processor` struct. #### Response Example ```rust // Example response is implicit in the creation of the Processor object ``` ``` -------------------------------- ### ESI Include Tag Usage (HTML) Source: https://context7.com/fastly/esi/llms.txt Fetches and embeds content from a specified URL using the `` tag. It supports fallback URLs via the `alt` attribute and error handling with `onerror="continue"` to allow processing to proceed even if the primary source fails. ```html ``` -------------------------------- ### Handle Fragment Request Results (Rust) Source: https://context7.com/fastly/esi/llms.txt Manage the state of fragment requests using the `PendingFragmentContent` enum. This is useful for custom fragment dispatchers to control content fetching, allowing for asynchronous requests, pre-computed responses, or skipping fragments. ```rust use esi::{PendingFragmentContent, Result}; use fastly::{Request, Response}; // Return an async pending request (most common) fn async_dispatcher(req: Request) -> Result { Ok(req.send_async("backend")?.into()) } // Return a pre-computed response (for caching or synthetic content) fn synthetic_dispatcher(req: Request) -> Result { if req.get_path() == "/cached" { Ok(PendingFragmentContent::CompletedRequest( Response::from_body("Cached content") )) } else { Ok(req.send_async("backend")?.into()) } } // Skip fragment entirely (return no content) fn conditional_dispatcher(req: Request) -> Result { if req.get_path().starts_with("/optional") { Ok(PendingFragmentContent::NoContent) } else { Ok(req.send_async("backend")?.into()) } } ``` -------------------------------- ### ESI Variables and Assignment (HTML) Source: https://context7.com/fastly/esi/llms.txt Utilizes `` to display dynamic content and `` to set custom variables. These tags can access request metadata, headers, and query parameters, enabling personalized content delivery and logic. ```html

Request method:

Request path:

Client IP:

Full query:

Specific param:

Host:

Cookie value:

Hello, !

Welcome to $(HTTP_HOST), your IP is $(REMOTE_ADDR) ``` -------------------------------- ### Parse ESI Tags from XML/HTML (Rust) Source: https://context7.com/fastly/esi/llms.txt Low-level parsing of XML/HTML documents to identify ESI tags. This function invokes a callback for each detected ESI event, enabling custom processing pipelines or analysis of ESI directives within content. ```rust use esi::{Reader, parse_tags, Event, Tag}; let xml = r#" $(HTTP_HOST) "#; let mut reader = Reader::from_str(xml); let mut includes = Vec::new(); parse_tags("esi", &mut reader, &mut |event| { match event { Event::ESI(Tag::Include { src, alt, continue_on_error }) => { println!("Found include: src={}, alt={:?}, onerror={}", src, alt, continue_on_error); includes.push(src); } Event::ESI(Tag::Vars { name }) => { println!("Found vars: {:?}", name); } Event::Content(xml_event) => { // Regular XML content } _ => {} } Ok(()) })?; // includes = ["http://example.com/header.html"] ``` -------------------------------- ### Processor::process_document - Process ESI with Custom Writer Source: https://context7.com/fastly/esi/llms.txt Processes ESI directives from a Reader source and writes the output to a custom Writer. This method offers greater control over output handling, suitable for advanced error handling scenarios where you manage the output stream. ```APIDOC ## Processor::process_document - Process ESI with Custom Writer ### Description Processes ESI directives from a Reader source, writing to a custom Writer. This method provides more control over output handling, enabling advanced error handling scenarios where you maintain ownership of the output stream. ### Method `process_document` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use std::io::Write; use esi::{Processor, Configuration, Reader, Writer, PendingFragmentContent}; use fastly::{http::StatusCode, mime, Request, Response}; fn handle_with_error_recovery(req: Request) -> Result<(), fastly::Error> { let mut beresp = Response::from_body("Content") .with_content_type(mime::TEXT_HTML); let processor = Processor::new(Some(req), Configuration::default()); // Create client response and get output stream let resp = Response::from_status(StatusCode::OK).with_content_type(mime::TEXT_HTML); let output_writer = resp.stream_to_client(); let mut xml_writer = Writer::new(output_writer); // Process with custom reader let result = processor.process_document( Reader::from_reader(beresp.take_body()), &mut xml_writer, Some(&|req| Ok(req.send_async("backend")?.into())), None, ); match result { Ok(()) => { xml_writer.into_inner().finish()?; } Err(err) => { // Write error fragment on failure let _ = xml_writer.get_mut().write(b"
Error loading content
"); xml_writer.into_inner().finish()?; } } Ok(()) } ``` ### Response #### Success Response (200) Indicates successful processing of the ESI document. The output is written to the provided `Writer`. #### Response Example ```rust // Output is written to the custom Writer. The `finish()` method on the writer should be called to finalize the output stream. ``` ``` -------------------------------- ### Process ESI with Custom Writer and Error Recovery - Rust Source: https://context7.com/fastly/esi/llms.txt Processes ESI directives from a Reader source, writing to a custom Writer. This method provides more control over output handling, enabling advanced error handling scenarios where you maintain ownership of the output stream. It demonstrates handling processing errors by writing an error fragment. ```rust use std::io::Write; use esi::{Processor, Configuration, Reader, Writer, PendingFragmentContent}; use fastly::{http::StatusCode, mime, Request, Response}; fn handle_with_error_recovery(req: Request) -> Result<(), fastly::Error> { let mut beresp = Response::from_body("Content") .with_content_type(mime::TEXT_HTML); let processor = Processor::new(Some(req), Configuration::default()); // Create client response and get output stream let resp = Response::from_status(StatusCode::OK).with_content_type(mime::TEXT_HTML); let output_writer = resp.stream_to_client(); let mut xml_writer = Writer::new(output_writer); // Process with custom reader let result = processor.process_document( Reader::from_reader(beresp.take_body()), &mut xml_writer, Some(&|req| Ok(req.send_async("backend")?.into())), None, ); match result { Ok(()) => { xml_writer.into_inner().finish()?; } Err(err) => { // Write error fragment on failure let _ = xml_writer.get_mut().write(b"
Error loading content
"); xml_writer.into_inner().finish()?; } } Ok(()) } ``` -------------------------------- ### Process ESI Response with Streaming - Rust Source: https://context7.com/fastly/esi/llms.txt Processes ESI directives in a response body while streaming output directly to the client. This is the primary method for handling ESI documents in a Fastly Compute service, automatically managing the client response stream. It supports custom fragment request dispatchers and fragment response processing. ```rust use fastly::{http::StatusCode, mime, Request, Response}; use esi::{Processor, Configuration, PendingFragmentContent}; fn handle_request(req: Request) -> Result<(), fastly::Error> { // Fetch document from backend let mut beresp = req.clone_without_body().send("origin_0")?; // Check if response is HTML if beresp.get_content_type().is_some_and(|c| c.subtype() == mime::HTML) { let processor = Processor::new(Some(req), Configuration::default()); processor.process_response( &mut beresp, // Source document (body will be consumed) Some(Response::from_status(StatusCode::OK).with_content_type(mime::TEXT_HTML)), // Client response template Some(&|req| { // Custom fragment request dispatcher println!("Fetching fragment: {}", req.get_url()); Ok(req.with_ttl(120).send_async("mock-s3")?.into()) }), Some(&|req, resp| { // Process fragment response before streaming println!("Fragment {} returned {}", req.get_path(), resp.get_status()); Ok(resp) }), )?; } else { beresp.send_to_client(); } Ok(()) } ``` -------------------------------- ### ESI Comment and Remove Tags for Content Management Source: https://context7.com/fastly/esi/llms.txt Provides tags for managing content during ESI processing. completely removes text from the output, useful for developer notes, while strips content that should not be processed by ESI. ```html ``` -------------------------------- ### ESI Built-in Functions for String Manipulation Source: https://context7.com/fastly/esi/llms.txt Utilizes ESI expression functions for transforming strings within variables and conditional statements. Includes functions for lowercasing, HTML encoding, and replacing substrings, with options for limiting replacements. ```html ``` -------------------------------- ### Processor::process_response - Process ESI Response Source: https://context7.com/fastly/esi/llms.txt Processes ESI directives within a response body, streaming the output directly to the client. This is the main method for handling ESI documents in a Fastly Compute service, automatically managing the client response stream. ```APIDOC ## Processor::process_response - Process ESI Response ### Description Processes ESI directives in a response body while streaming output directly to the client. This is the primary method for handling ESI documents in a Fastly Compute service, automatically managing the client response stream. ### Method `process_response` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use fastly::{http::StatusCode, mime, Request, Response}; use esi::{Processor, Configuration, PendingFragmentContent}; fn handle_request(req: Request) -> Result<(), fastly::Error> { // Fetch document from backend let mut beresp = req.clone_without_body().send("origin_0")?; // Check if response is HTML if beresp.get_content_type().is_some_and(|c| c.subtype() == mime::HTML) { let processor = Processor::new(Some(req), Configuration::default()); processor.process_response( &mut beresp, // Source document (body will be consumed) Some(Response::from_status(StatusCode::OK).with_content_type(mime::TEXT_HTML)), // Client response template Some(&|req| { // Custom fragment request dispatcher println!("Fetching fragment: {}", req.get_url()); Ok(req.with_ttl(120).send_async("mock-s3")?.into()) }), Some(&|req, resp| { // Process fragment response before streaming println!("Fragment {} returned {}", req.get_path(), resp.get_status()); Ok(resp) }), )?; } else { beresp.send_to_client(); } Ok(()) } ``` ### Response #### Success Response (200) Indicates successful processing of the ESI response. The output is streamed directly to the client. #### Response Example ```rust // Output is streamed directly to the client, no explicit response body is returned here. ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.