Expand description
§ESI for Fastly
This crate provides a streaming Edge Side Includes parser and executor designed for Fastly Compute.
The implementation is a subset of the ESI Language Specification 1.0 supporting the following tags:
<esi:include>
(+alt
,onerror="continue"
)<esi:try>
|<esi:attempt>
|<esi:except>
<esi:vars>
|<esi:assign>
<esi:choose>
|<esi:when>
|<esi:otherwise>
<esi:comment>
<esi:remove>
Other tags will be ignored and served to the client as-is.
This implementation also includes an expression interpreter and library of functions that can be used. Current functions include:
$lower(string)
$html_encode(string)
$replace(haystack, needle, replacement [, count])
§Example Usage
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(())
}
See example applications in the examples
subdirectory or read the hosted documentation at docs.rs/esi. Due to the fact that this processor streams fragments to the client as soon as they are available, it is not possible to return a relevant status code for later errors once we have started streaming the response to the client. For this reason, it is recommended that you refer to the esi_example_advanced_error_handling
application, which allows you to handle errors gracefully by maintaining ownership of the output stream.
§Testing
In order to run the test suite for the packages in this repository, viceroy
must be available in your PATH. You can install the latest version of viceroy
by running the following command:
cargo install viceroy
§License
The source and documentation for this project are released under the MIT License.
Re-exports§
pub use crate::parse::Tag::Try;
Structs§
- Configuration
- This struct is used to configure optional behaviour within the ESI processor.
- Fragment
- Include
- Representation of an ESI tag from a source response.
- Processor
- An instance of the ESI processor with a given configuration.
- Reader
- A low level encoding-agnostic XML event reader.
- Writer
- XML writer. Writes XML
Event
s to astd::io::Write
implementor.
Enums§
- Element
- A section of the pending response, either raw XML data or a pending fragment request.
- Event
- Representation of either XML data or a parsed ESI tag.
- Execution
Error - Describes an error encountered during ESI parsing or execution.
- Pending
Fragment Content - Representation of a fragment that is either being fetched, has already been fetched (or generated synthetically), or skipped.
- Tag
Functions§
- parse_
tags - Parses the ESI document from the given
reader
and calls thecallback
closure upon each successfully parsed ESI tag.