Skip to content

Commit 54587af

Browse files
committed
Store and expose regex captures
1 parent 88c4265 commit 54587af

File tree

2 files changed

+71
-24
lines changed

2 files changed

+71
-24
lines changed

esi/src/expression.rs

+68-21
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::str::Chars;
55

66
use crate::{BoolValue, ExecutionError, Result, Value, Variables};
77

8-
pub fn evaluate_expression(raw_expr: String, ctx: EvalContext) -> Result<Value> {
8+
pub fn evaluate_expression(raw_expr: String, mut ctx: EvalContext) -> Result<Value> {
99
// TODO: this got real ugly, figure out some better way to do this
1010
let tokens = match lex_expr(raw_expr) {
1111
Ok(r) => r,
@@ -17,43 +17,62 @@ pub fn evaluate_expression(raw_expr: String, ctx: EvalContext) -> Result<Value>
1717
Err(ExecutionError::ExpressionParseError(s)) => return Ok(Value::Error(s)),
1818
Err(e) => return Err(e),
1919
};
20-
match eval_expr(expr, &ctx) {
20+
match eval_expr(expr, &mut ctx) {
2121
Ok(r) => Ok(r),
2222
Err(ExecutionError::ExpressionParseError(s)) => return Ok(Value::Error(s)),
2323
Err(e) => return Err(e),
2424
}
2525
}
2626

2727
pub struct EvalContext<'a> {
28-
variables: &'a Variables,
28+
variables: &'a mut Variables,
2929
// request content for metadata
3030
}
3131
impl EvalContext<'_> {
32-
pub fn new(variables: &Variables) -> EvalContext {
32+
pub fn new(variables: &mut Variables) -> EvalContext {
3333
EvalContext { variables }
3434
}
35-
pub fn get_variable(&self, key: &str, _subkey: Option<String>) -> Value {
35+
pub fn get_variable(&self, key: &str, subkey: Option<String>) -> Value {
3636
match key {
3737
"HTTP_HOST" => Value::Null,
3838
"QUERY_STRING" => Value::Null,
39-
s => self.variables.get(&s).clone(),
39+
_ => self.variables.get(&format_key(key, subkey)).clone(),
4040
}
4141
}
42+
43+
pub fn set_variable(&mut self, key: &str, subkey: Option<String>, value: Value) {
44+
self.variables.insert(format_key(key, subkey), value);
45+
}
4246
}
4347

44-
fn eval_expr(expr: Expr, ctx: &EvalContext) -> Result<Value> {
48+
fn format_key(key: &str, subkey: Option<String>) -> String {
49+
match subkey {
50+
Some(subkey) => format!("{}[{}]", key, subkey),
51+
None => format!("{}", key),
52+
}
53+
}
54+
55+
fn eval_expr(expr: Expr, ctx: &mut EvalContext) -> Result<Value> {
4556
let result = match expr {
4657
Expr::Integer(i) => Value::Integer(i),
4758
Expr::String(s) => Value::String(s),
48-
Expr::Variable(s, _) => ctx.get_variable(&s, None).clone(),
59+
Expr::Variable(key, subkey) => ctx.get_variable(&key, subkey).clone(),
4960
Expr::Comparison(c) => {
5061
let left = eval_expr(c.left, ctx)?;
5162
let right = eval_expr(c.right, ctx)?;
5263
match c.operator {
5364
Operator::Matches => match (left, right) {
5465
(Value::String(test), Value::String(pattern)) => {
5566
let re = Regex::new(&pattern)?;
56-
if re.is_match(&test) {
67+
if let Some(captures) = re.captures(&test) {
68+
for (i, cap) in captures.iter().enumerate() {
69+
let capval = match cap {
70+
Some(s) => Value::String(s.as_str().to_string()),
71+
None => Value::Null,
72+
};
73+
ctx.set_variable("MATCHES", Some(i.to_string()), capval);
74+
}
75+
5776
Value::Boolean(BoolValue::True)
5877
} else {
5978
Value::Boolean(BoolValue::False)
@@ -276,8 +295,6 @@ enum Token {
276295
Identifier(String),
277296
OpenParen,
278297
CloseParen,
279-
OpenBracket,
280-
CloseBracket,
281298
Comma,
282299
}
283300

@@ -767,7 +784,7 @@ mod tests {
767784
#[test]
768785
fn test_eval_string() -> Result<()> {
769786
let expr = Expr::String("hello".to_string());
770-
let result = eval_expr(expr, &EvalContext::new(&Variables::new()))?;
787+
let result = eval_expr(expr, &mut EvalContext::new(&mut Variables::new()))?;
771788
assert_eq!(result, Value::String("hello".to_string()));
772789
Ok(())
773790
}
@@ -777,7 +794,7 @@ mod tests {
777794
let expr = Expr::Variable("hello".to_string(), None);
778795
let result = eval_expr(
779796
expr,
780-
&EvalContext::new(&Variables::from([(
797+
&mut EvalContext::new(&mut Variables::from([(
781798
"hello".to_string(),
782799
Value::String("goodbye".to_string()),
783800
)])),
@@ -786,10 +803,23 @@ mod tests {
786803
Ok(())
787804
}
788805
#[test]
806+
fn test_eval_subscripted_variable() -> Result<()> {
807+
let expr = Expr::Variable("hello".to_string(), Some("abc".to_string()));
808+
let result = eval_expr(
809+
expr,
810+
&mut EvalContext::new(&mut Variables::from([(
811+
"hello[abc]".to_string(),
812+
Value::String("goodbye".to_string()),
813+
)])),
814+
)?;
815+
assert_eq!(result, Value::String("goodbye".to_string()));
816+
Ok(())
817+
}
818+
#[test]
789819
fn test_eval_matches_comparison() -> Result<()> {
790820
let result = evaluate_expression(
791821
"$(hello) matches '^foo'".to_string(),
792-
EvalContext::new(&Variables::from([(
822+
EvalContext::new(&mut Variables::from([(
793823
"hello".to_string(),
794824
Value::String("foobar".to_string()),
795825
)])),
@@ -798,10 +828,25 @@ mod tests {
798828
Ok(())
799829
}
800830
#[test]
831+
fn test_eval_matches_with_captures() -> Result<()> {
832+
let mut vars =
833+
Variables::from([("hello".to_string(), Value::String("foobar".to_string()))]);
834+
835+
let result = evaluate_expression(
836+
"$(hello) matches '^(fo)o'".to_string(),
837+
EvalContext::new(&mut vars),
838+
)?;
839+
assert_eq!(result, Value::Boolean(BoolValue::True));
840+
841+
let result = evaluate_expression("$(MATCHES{1})".to_string(), EvalContext::new(&mut vars))?;
842+
assert_eq!(result, Value::String("fo".to_string()));
843+
Ok(())
844+
}
845+
#[test]
801846
fn test_eval_matches_comparison_negative() -> Result<()> {
802847
let result = evaluate_expression(
803848
"$(hello) matches '^foo'".to_string(),
804-
EvalContext::new(&Variables::from([(
849+
EvalContext::new(&mut Variables::from([(
805850
"hello".to_string(),
806851
Value::String("nope".to_string()),
807852
)])),
@@ -811,16 +856,18 @@ mod tests {
811856
}
812857
#[test]
813858
fn test_eval_function_call() -> Result<()> {
814-
let result =
815-
evaluate_expression("$ping()".to_string(), EvalContext::new(&Variables::new()))?;
859+
let result = evaluate_expression(
860+
"$ping()".to_string(),
861+
EvalContext::new(&mut Variables::new()),
862+
)?;
816863
assert_eq!(result, Value::String("pong".to_string()));
817864
Ok(())
818865
}
819866
#[test]
820867
fn test_eval_lower_call() -> Result<()> {
821868
let result = evaluate_expression(
822869
"$lower('FOO')".to_string(),
823-
EvalContext::new(&Variables::new()),
870+
EvalContext::new(&mut Variables::new()),
824871
)?;
825872
assert_eq!(result, Value::String("foo".to_string()));
826873
Ok(())
@@ -829,7 +876,7 @@ mod tests {
829876
fn test_eval_html_encode_call() -> Result<()> {
830877
let result = evaluate_expression(
831878
"$html_encode('a > b < c')".to_string(),
832-
EvalContext::new(&Variables::new()),
879+
EvalContext::new(&mut Variables::new()),
833880
)?;
834881
assert_eq!(result, Value::String("a &gt; b &lt; c".to_string()));
835882
Ok(())
@@ -838,7 +885,7 @@ mod tests {
838885
fn test_eval_replace_call() -> Result<()> {
839886
let result = evaluate_expression(
840887
"$replace('abc-def-ghi-', '-', '==')".to_string(),
841-
EvalContext::new(&Variables::new()),
888+
EvalContext::new(&mut Variables::new()),
842889
)?;
843890
assert_eq!(result, Value::String("abc==def==ghi==".to_string()));
844891
Ok(())
@@ -848,7 +895,7 @@ mod tests {
848895
fn test_eval_replace_call_with_count() -> Result<()> {
849896
let result = evaluate_expression(
850897
"$replace('abc-def-ghi-', '-', '==', 2)".to_string(),
851-
EvalContext::new(&Variables::new()),
898+
EvalContext::new(&mut Variables::new()),
852899
)?;
853900
assert_eq!(result, Value::String("abc==def==ghi-".to_string()));
854901
Ok(())

esi/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ fn event_receiver(
402402
is_escaped: bool,
403403
original_request_metadata: &Request,
404404
dispatch_fragment_request: &FragmentRequestDispatcher,
405-
variables: &mut Variables,
405+
mut variables: &mut Variables,
406406
) -> Result<()> {
407407
debug!("got {:?}", event);
408408

@@ -466,7 +466,7 @@ fn event_receiver(
466466
// Hmm... that might not work actually. I need a way to collect the events for
467467
// each branch and then ... ugh
468468
Event::ESI(Tag::Assign { name, value }) => {
469-
let result = evaluate_expression(value, EvalContext::new(&variables))?;
469+
let result = evaluate_expression(value, EvalContext::new(&mut variables))?;
470470
variables.insert(name, result);
471471
}
472472
Event::ESI(Tag::Vars { name }) => {
@@ -491,7 +491,7 @@ fn event_receiver(
491491
match_name: _,
492492
} = when
493493
{
494-
let result = evaluate_expression(test, EvalContext::new(&variables))?;
494+
let result = evaluate_expression(test, EvalContext::new(&mut variables))?;
495495
if result.to_bool() {
496496
chose_branch = true;
497497
for event in events {

0 commit comments

Comments
 (0)