Skip to content

Commit b04ea81

Browse files
committed
Short form esi:vars processing works. Added an example for testing.
1 parent 96dfe51 commit b04ea81

File tree

7 files changed

+151
-3
lines changed

7 files changed

+151
-3
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ members = [
55
"examples/esi_example_minimal",
66
"examples/esi_example_advanced_error_handling",
77
"examples/esi_try_example",
8+
"examples/esi_vars_example",
89
]
910

1011
[workspace.package]

esi/src/lib.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use fastly::http::request::PendingRequest;
1010
use fastly::http::{header, Method, StatusCode, Url};
1111
use fastly::{mime, Body, Request, Response};
1212
use log::{debug, error, trace};
13-
use std::collections::VecDeque;
13+
use std::collections::{HashMap, VecDeque};
1414
use std::io::{BufRead, Write};
1515

1616
pub use crate::document::{Element, Fragment};
@@ -142,6 +142,9 @@ impl Processor {
142142
// `root_task` is the root task that will be used to fetch tags in recursive manner
143143
let root_task = &mut Task::new();
144144

145+
// variables
146+
let mut variables = HashMap::new();
147+
145148
let is_escaped = self.configuration.is_escaped_content;
146149
// Call the library to parse fn `parse_tags` which will call the callback function
147150
// on each tag / event it finds in the document.
@@ -156,6 +159,7 @@ impl Processor {
156159
is_escaped,
157160
&original_request_metadata,
158161
dispatch_fragment_request,
162+
&mut variables,
159163
)
160164
},
161165
)?;
@@ -393,6 +397,7 @@ fn event_receiver(
393397
is_escaped: bool,
394398
original_request_metadata: &Request,
395399
dispatch_fragment_request: &FragmentRequestDispatcher,
400+
variables: &mut HashMap<String, String>,
396401
) -> Result<()> {
397402
debug!("got {:?}", event);
398403

@@ -430,12 +435,14 @@ fn event_receiver(
430435
is_escaped,
431436
original_request_metadata,
432437
dispatch_fragment_request,
438+
variables,
433439
)?;
434440
let except_task = task_handler(
435441
except_events,
436442
is_escaped,
437443
original_request_metadata,
438444
dispatch_fragment_request,
445+
variables,
439446
)?;
440447

441448
trace!(
@@ -450,10 +457,17 @@ fn event_receiver(
450457
});
451458
}
452459
Event::ESI(Tag::Assign { name, value }) => {
453-
// process assignment
460+
variables.insert(name, value);
454461
}
455462
Event::ESI(Tag::Vars { name }) => {
456-
// process vars
463+
if let Some(name) = name {
464+
if let Some(value) = variables.get(&name) {
465+
let value = value.to_owned();
466+
queue.push_back(Element::Raw(value.into_bytes()));
467+
}
468+
} else {
469+
// TODO: long form
470+
}
457471
}
458472
Event::XML(event) => {
459473
debug!("pushing content to buffer, len: {}", queue.len());
@@ -473,6 +487,7 @@ fn task_handler(
473487
is_escaped: bool,
474488
original_request_metadata: &Request,
475489
dispatch_fragment_request: &FragmentRequestDispatcher,
490+
variables: &mut HashMap<String, String>,
476491
) -> Result<Task> {
477492
let mut task = Task::new();
478493
for event in events {
@@ -482,6 +497,7 @@ fn task_handler(
482497
is_escaped,
483498
original_request_metadata,
484499
dispatch_fragment_request,
500+
variables,
485501
)?;
486502
}
487503
Ok(task)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[target.wasm32-wasi]
2+
rustflags = ["-C", "debuginfo=2"]
3+
runner = "viceroy run -C fastly.toml -- "
4+
5+
[build]
6+
target = "wasm32-wasi"

examples/esi_vars_example/Cargo.toml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "esi_vars_example"
3+
version.workspace = true
4+
authors.workspace = true
5+
license.workspace = true
6+
edition.workspace = true
7+
publish = false
8+
9+
[dependencies]
10+
fastly = "^0.11"
11+
esi = { path = "../../esi" }
12+
log = "^0.4"
13+
env_logger = "^0.11"

examples/esi_vars_example/fastly.toml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# This file describes a Fastly Compute package. To learn more visit:
2+
# https://developer.fastly.com/reference/fastly-toml/
3+
4+
authors = ["[email protected]"]
5+
description = ""
6+
language = "rust"
7+
manifest_version = 2
8+
name = "esi_example_minimal"
9+
service_id = ""
10+
11+
[local_server]
12+
13+
[local_server.backends]
14+
15+
[local_server.backends.mock-s3]
16+
url = "https://mock-s3.edgecompute.app"
17+
override_host = "mock-s3.edgecompute.app"
18+
19+
[scripts]
20+
build = "cargo build --bin esi_example_minimal --release --target wasm32-wasi --color always"
21+
22+
[setup]
23+
24+
[setup.backends]
25+
26+
[setup.backends.mock-s3]
27+
address = "mock-s3.edgecompute.app"
28+
port = 443
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>My Variable Website</title>
5+
</head>
6+
<body>
7+
<header style="background: #f1f1f1; padding: 16px">
8+
<h1>My Variable Website</h1>
9+
</header>
10+
<div class="layout" style="display: flex">
11+
Assigning "YES" to variable...<br>
12+
<esi:assign name="test" value="YES" />
13+
Check (short form): YES=<esi:vars name="test" /><br>
14+
Check (long form): YES=<esi:vars>$(test)</esi:vars><br>
15+
16+
Updating variable to "PERHAPS"...<br>
17+
<esi:assign name="test" value="PERHAPS" />
18+
Check (short form): PERHAPS=<esi:vars name="test" /><br>
19+
Check (long form): PERHAPS=<esi:vars>$(test)</esi:vars><br>
20+
</div>
21+
</body>
22+
</html>

examples/esi_vars_example/src/main.rs

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use fastly::{http::StatusCode, mime, Error, Request, Response};
2+
use log::info;
3+
4+
fn main() {
5+
env_logger::builder()
6+
.filter(None, log::LevelFilter::Trace)
7+
.init();
8+
9+
if let Err(err) = handle_request(Request::from_client()) {
10+
println!("returning error response");
11+
12+
Response::from_status(StatusCode::INTERNAL_SERVER_ERROR)
13+
.with_body(err.to_string())
14+
.send_to_client();
15+
}
16+
}
17+
18+
fn handle_request(req: Request) -> Result<(), Error> {
19+
if req.get_path() != "/" {
20+
Response::from_status(StatusCode::NOT_FOUND).send_to_client();
21+
return Ok(());
22+
}
23+
24+
// Generate synthetic test response from "index.html" file.
25+
// You probably want replace this with a backend call, e.g. `req.clone_without_body().send("origin_0")`
26+
let mut beresp =
27+
Response::from_body(include_str!("index.html")).with_content_type(mime::TEXT_HTML);
28+
29+
// If the response is HTML, we can parse it for ESI tags.
30+
if beresp
31+
.get_content_type()
32+
.is_some_and(|c| c.subtype() == mime::HTML)
33+
{
34+
let processor = esi::Processor::new(Some(req), esi::Configuration::default());
35+
36+
processor.process_response(
37+
&mut beresp,
38+
None,
39+
Some(&|req| {
40+
info!("Sending request {} {}", req.get_method(), req.get_path());
41+
Ok(req.with_ttl(120).send_async("mock-s3")?.into())
42+
}),
43+
Some(&|req, mut resp| {
44+
info!(
45+
"Received response for {} {}",
46+
req.get_method(),
47+
req.get_path()
48+
);
49+
if !resp.get_status().is_success() {
50+
// Override status so we still insert errors.
51+
resp.set_status(StatusCode::OK);
52+
}
53+
Ok(resp)
54+
}),
55+
)?;
56+
} else {
57+
// Otherwise, we can just return the response.
58+
beresp.send_to_client();
59+
}
60+
61+
Ok(())
62+
}

0 commit comments

Comments
 (0)