Skip to content

Add configuration options for Dynamic Content Assembly (DCA) defaults#52

Merged
vagetman merged 7 commits into
mainfrom
dca-config
May 29, 2026
Merged

Add configuration options for Dynamic Content Assembly (DCA) defaults#52
vagetman merged 7 commits into
mainfrom
dca-config

Conversation

@vagetman
Copy link
Copy Markdown
Collaborator

@vagetman vagetman commented May 23, 2026

Problem

There is currently no way to control the default DCA (Dynamic Content Assembly) behaviour for <esi:include> and <esi:eval> tags — either globally across all fragments, or on a per-fragment basis via response headers. Users who want Akamai-style "ESI-by-default" processing must add dca="esi" to every tag. There is also no depth limit enforcement, no Edge-Control header support, and no way for child fragments to inherit a parent's DCA mode.

Fixes #46

Changes

Adds four new configuration options to Configuration:

  • default_dca (DcaMode, default: None) — Sets the global default DCA mode for includes/evals without an explicit dca attribute. Set to DcaMode::Esi to enable Akamai-style behaviour where all fragments are ESI-processed by default.

  • max_include_depth (usize, default: 15) — Enforces a maximum nesting depth for ESI includes/evals. The EdgeSuite spec defaults to 15 levels. When the limit is reached, fragment content is silently omitted.

  • enable_edge_control (bool, default: false) — Enables parsing of Edge-Control response headers for per-fragment DCA directives (e.g. Edge-Control: dca=esi). Matches Akamai's "Enable Through Response Headers" property setting.

  • inherit_parent_dca (bool, default: false) — When enabled, child fragments inside an explicit dca="esi" subtree inherit ESI processing without needing their own attribute. Top-level includes still use default_dca.

Precedence (highest wins): tag attribute → Edge-Control header → inherited parent DCA → default_dca.

Also makes DcaMode a public export and changes the internal dca field from DcaMode to Option<DcaMode> to distinguish "not specified" from "explicitly set to none".

Usage

let config = esi::Configuration::default()
    .with_default_dca(esi::DcaMode::Esi)
    .with_edge_control(true)
    .with_inherit_parent_dca(true)
    .with_max_include_depth(5);

let processor = esi::Processor::new(Some(req), config);

Tests

Comprehensive test suite in dca_tests.rs covering all four features (23 tests total), including precedence interactions between config, tag attributes, Edge-Control headers, and inheritance.

Example

New esi_dca_example demonstrating all four DCA configuration options.

vagetman added 6 commits May 22, 2026 23:36
Add Configuration.default_dca field that controls how <esi:include> and
<esi:eval> tags without an explicit dca attribute are processed.

- Change IncludeAttributes.dca to Option<DcaMode> to distinguish
  'not specified' (None) from explicit 'dca=none' (Some(None))
- Add with_default_dca() builder method on Configuration
- Re-export DcaMode publicly for use in config API
- Resolve effective DCA at evaluation time:
  explicit tag attr > Configuration.default_dca

Addresses #46
Add a safety limit on recursive ESI include/eval nesting depth (default: 15,
per EdgeSuite ESI spec). When the limit is reached, fragments are silently
omitted from output and a warning is logged — matching Akamai behaviour.

- Add max_include_depth field to Configuration (default: 15)
- Add with_max_include_depth() builder method
- Track include_depth in Processor, increment for nested processing
- Enforce limit in process_fragment_body (include dca=esi) and on_eval
  (both dca=esi two-phase and dca=none single-phase paths)
- Log warn! when depth limit is exceeded

Addresses #46
When `enable_edge_control` is true, inspect the `Edge-Control` response header
on fragment responses for `dca=esi` or `dca=noop` directives. This provides
per-fragment control of ESI processing via origin response headers, matching
Akamai's 'Enable Through Response Headers' property setting.

NOTE: No other Edge-Control header directives are supported at this time

- Add `enable_edge_control` config option (default: `false`)
- Change `FragmentMetadata.dca` to `Option<DcaMode>` to defer resolution
- Add `Processor::resolve_dca()` applying precedence:

`ESI tag attribute > Edge-Control header > Configuration.default_dca`

- Add parse_edge_control_dca() per EdgeSuite ESI spec:
  `dca=esi` (process as ESI) and `dca=noop` (do not process)
- Wire into `process_include()` and `on_eval()` response paths

Addresses #46
When enabled, an unspecified <esi:include> inside an explicit dca=esi
subtree resolves to Esi processing instead of falling back to the global
default_dca. Allows users to set default_dca=None globally while still
having dca=esi propagate to its children's subtree.

Precedence: tag attr > Edge-Control > inherited (if enabled & depth>0)
> default_dca.
Cover all four DCA features: default_dca, max_include_depth,
Edge-Control header parsing, and inherit_parent_dca subtree
inheritance. 24 tests verifying precedence rules, edge cases,
and feature interactions.
Demonstrates all four DCA config options: default_dca, edge_control,
inherit_parent_dca, and max_include_depth.
@vagetman vagetman marked this pull request as ready for review May 25, 2026 02:08
kailan
kailan previously approved these changes May 28, 2026
Copy link
Copy Markdown
Member

@kailan kailan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really good. Thanks for the well-defined commits!

Comment thread examples/esi_dca_example/fastly.toml Outdated
Co-authored-by: Kailan Blanks <kblanks@fastly.com>
@vagetman vagetman merged commit a3aac84 into main May 29, 2026
3 checks passed
@vagetman vagetman deleted the dca-config branch May 29, 2026 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Option to configure Dynamic Content Assembly (DCA) defaults?

2 participants