Skip to content

Commit

Permalink
Add is_match function to conditionally expand esi:include
Browse files Browse the repository at this point in the history
  • Loading branch information
andersjanmyr committed Jun 20, 2022
1 parent 2cbbfbd commit e9f641c
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 10 deletions.
28 changes: 24 additions & 4 deletions esi/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::fmt;
/// This struct is used to configure optional behaviour within the ESI processor.
///
/// ## Usage Example
Expand All @@ -8,25 +9,38 @@
///
/// let processor = esi::Processor::new(config);
/// ```
#[derive(Clone, Debug)]
pub struct Configuration {
#[derive(Clone)]
pub struct Configuration<'a> {
/// The XML namespace to use when scanning for ESI tags. Defaults to `esi`.
pub namespace: String,

/// Whether or not to execute nested ESI tags within fetched fragments. Defaults to `false`.
pub recursive: bool,

/// Returns true if the esi:include with 'src' should be expanded, false to leave alone.
pub is_match: &'a dyn Fn(&str) -> bool,
}

impl Default for Configuration {
impl<'a> Default for Configuration<'a> {
fn default() -> Self {
Self {
namespace: String::from("esi"),
recursive: false,
is_match: &|_| true,
}
}
}

impl Configuration {
impl<'a> fmt::Debug for Configuration<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Configuration")
.field("namespace", &self.namespace)
.field("recursive", &self.recursive)
.finish()
}
}

impl<'a> Configuration<'a> {
/// Sets an alternative ESI namespace, which is used to identify ESI instructions.
///
/// For example, setting this to `test` would cause the processor to only match tags like `<test:include>`.
Expand All @@ -40,4 +54,10 @@ impl Configuration {
self.recursive = true;
self
}

/// Sets a matcher to control what esi:includes are expanded, true to include, false to leave alone.
pub fn with_matcher(mut self, matcher: &'a dyn Fn(&str) -> bool) -> Self {
self.is_match = matcher;
self
}
}
33 changes: 27 additions & 6 deletions esi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,18 @@ pub use crate::error::ExecutionError;

/// An instance of the ESI processor with a given configuration.
#[derive(Default)]
pub struct Processor {
configuration: Configuration,
pub struct Processor<'a> {
configuration: Configuration<'a>,
}

impl Processor {
impl<'a> Processor<'a> {
/// Construct a new ESI processor with the given configuration.
pub fn new(configuration: Configuration) -> Self {
pub fn new(configuration: Configuration<'a>) -> Self {
Self { configuration }
}
}

impl Processor {
impl<'a> Processor<'a> {
/// Execute the ESI document (`document`) using the provided client request (`original_request`) as context,
/// and stream the resulting output to the client.
///
Expand Down Expand Up @@ -131,7 +131,7 @@ impl Processor {
src,
alt,
continue_on_error,
}) => {
}) if (self.configuration.is_match)(&src) => {
let resp = match self.send_esi_fragment_request(
&original_request,
&src,
Expand Down Expand Up @@ -186,6 +186,27 @@ impl Processor {
error!("No content for fragment");
}
}
Event::ESI(Tag::Include {
src,
alt,
continue_on_error,
}) => {
let continue_str = if continue_on_error {
"onerror=\"continue\""
} else {
""
};
let alt_str = match alt {
Some(alt) => format!("alt=\"{}\"", alt),
None => "".to_string(),
};
let message = format!(
r#"<esi:include src="{}" {} {}></esi:include>"#,
src, alt_str, continue_str
);
xml_writer.write(message.as_bytes())?;
xml_writer.inner().flush().expect("failed to flush output");
}
Event::XML(event) => {
xml_writer.write_event(event)?;
xml_writer.inner().flush().expect("failed to flush output");
Expand Down

0 comments on commit e9f641c

Please sign in to comment.