actix_security_core/http/security/expression/
parser.rs1use std::fmt;
6use std::iter::Peekable;
7use std::str::Chars;
8
9use super::ast::{BinaryOp, Expression, UnaryOp};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum ParseError {
14 UnexpectedEof,
16 UnexpectedChar(char),
18 UnexpectedToken(String),
20 UnclosedParen,
22 UnclosedString,
24 EmptyExpression,
26 InvalidFunction(String),
28}
29
30impl fmt::Display for ParseError {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 match self {
33 ParseError::UnexpectedEof => write!(f, "unexpected end of expression"),
34 ParseError::UnexpectedChar(c) => write!(f, "unexpected character: '{}'", c),
35 ParseError::UnexpectedToken(t) => write!(f, "unexpected token: '{}'", t),
36 ParseError::UnclosedParen => write!(f, "unclosed parenthesis"),
37 ParseError::UnclosedString => write!(f, "unclosed string literal"),
38 ParseError::EmptyExpression => write!(f, "empty expression"),
39 ParseError::InvalidFunction(name) => write!(f, "invalid function: '{}'", name),
40 }
41 }
42}
43
44impl std::error::Error for ParseError {}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
48enum Token {
49 Ident(String),
51 String(String),
53 LParen,
55 RParen,
57 Comma,
59 And,
61 Or,
63 Not,
65 True,
67 False,
69}
70
71#[derive(Debug, Clone)]
81pub struct SecurityExpression {
82 source: String,
84 ast: Expression,
86}
87
88impl SecurityExpression {
89 pub fn parse(expr: &str) -> Result<Self, ParseError> {
102 let tokens = tokenize(expr)?;
103 if tokens.is_empty() {
104 return Err(ParseError::EmptyExpression);
105 }
106
107 let ast = Parser::new(tokens).parse()?;
108
109 Ok(SecurityExpression {
110 source: expr.to_string(),
111 ast,
112 })
113 }
114
115 pub fn source(&self) -> &str {
117 &self.source
118 }
119
120 pub fn ast(&self) -> &Expression {
122 &self.ast
123 }
124
125 pub fn into_ast(self) -> Expression {
127 self.ast
128 }
129}
130
131fn tokenize(expr: &str) -> Result<Vec<Token>, ParseError> {
133 let mut tokens = Vec::new();
134 let mut chars = expr.chars().peekable();
135
136 while let Some(&c) = chars.peek() {
137 match c {
138 ' ' | '\t' | '\n' | '\r' => {
140 chars.next();
141 }
142
143 '(' => {
145 chars.next();
146 tokens.push(Token::LParen);
147 }
148 ')' => {
149 chars.next();
150 tokens.push(Token::RParen);
151 }
152
153 ',' => {
155 chars.next();
156 tokens.push(Token::Comma);
157 }
158
159 '\'' | '"' => {
161 tokens.push(parse_string(&mut chars)?);
162 }
163
164 '&' => {
166 chars.next();
167 if chars.peek() == Some(&'&') {
168 chars.next();
169 tokens.push(Token::And);
170 } else {
171 return Err(ParseError::UnexpectedChar('&'));
172 }
173 }
174 '|' => {
175 chars.next();
176 if chars.peek() == Some(&'|') {
177 chars.next();
178 tokens.push(Token::Or);
179 } else {
180 return Err(ParseError::UnexpectedChar('|'));
181 }
182 }
183 '!' => {
184 chars.next();
185 tokens.push(Token::Not);
186 }
187
188 'a'..='z' | 'A'..='Z' | '_' => {
190 tokens.push(parse_identifier(&mut chars));
191 }
192
193 _ => {
195 return Err(ParseError::UnexpectedChar(c));
196 }
197 }
198 }
199
200 Ok(tokens)
201}
202
203fn parse_string(chars: &mut Peekable<Chars>) -> Result<Token, ParseError> {
205 let quote = chars.next().unwrap(); let mut value = String::new();
207
208 loop {
209 match chars.next() {
210 Some(c) if c == quote => {
211 return Ok(Token::String(value));
212 }
213 Some('\\') => {
214 if let Some(escaped) = chars.next() {
216 value.push(escaped);
217 } else {
218 return Err(ParseError::UnclosedString);
219 }
220 }
221 Some(c) => {
222 value.push(c);
223 }
224 None => {
225 return Err(ParseError::UnclosedString);
226 }
227 }
228 }
229}
230
231fn parse_identifier(chars: &mut Peekable<Chars>) -> Token {
233 let mut ident = String::new();
234
235 while let Some(&c) = chars.peek() {
236 if c.is_alphanumeric() || c == '_' {
237 ident.push(c);
238 chars.next();
239 } else {
240 break;
241 }
242 }
243
244 match ident.to_lowercase().as_str() {
246 "and" => Token::And,
247 "or" => Token::Or,
248 "not" => Token::Not,
249 "true" => Token::True,
250 "false" => Token::False,
251 _ => Token::Ident(ident),
252 }
253}
254
255struct Parser {
257 tokens: Vec<Token>,
258 pos: usize,
259}
260
261impl Parser {
262 fn new(tokens: Vec<Token>) -> Self {
263 Parser { tokens, pos: 0 }
264 }
265
266 fn parse(&mut self) -> Result<Expression, ParseError> {
267 let expr = self.parse_or()?;
268
269 if self.pos < self.tokens.len() {
270 return Err(ParseError::UnexpectedToken(format!(
271 "{:?}",
272 self.tokens[self.pos]
273 )));
274 }
275
276 Ok(expr)
277 }
278
279 fn peek(&self) -> Option<&Token> {
280 self.tokens.get(self.pos)
281 }
282
283 fn advance(&mut self) -> Option<&Token> {
284 let token = self.tokens.get(self.pos);
285 self.pos += 1;
286 token
287 }
288
289 fn parse_or(&mut self) -> Result<Expression, ParseError> {
291 let mut left = self.parse_and()?;
292
293 while matches!(self.peek(), Some(Token::Or)) {
294 self.advance();
295 let right = self.parse_and()?;
296 left = Expression::Binary {
297 left: Box::new(left),
298 op: BinaryOp::Or,
299 right: Box::new(right),
300 };
301 }
302
303 Ok(left)
304 }
305
306 fn parse_and(&mut self) -> Result<Expression, ParseError> {
308 let mut left = self.parse_unary()?;
309
310 while matches!(self.peek(), Some(Token::And)) {
311 self.advance();
312 let right = self.parse_unary()?;
313 left = Expression::Binary {
314 left: Box::new(left),
315 op: BinaryOp::And,
316 right: Box::new(right),
317 };
318 }
319
320 Ok(left)
321 }
322
323 fn parse_unary(&mut self) -> Result<Expression, ParseError> {
325 if matches!(self.peek(), Some(Token::Not)) {
326 self.advance();
327 let expr = self.parse_unary()?;
328 return Ok(Expression::Unary {
329 op: UnaryOp::Not,
330 expr: Box::new(expr),
331 });
332 }
333
334 self.parse_primary()
335 }
336
337 fn parse_primary(&mut self) -> Result<Expression, ParseError> {
339 match self.peek().cloned() {
340 Some(Token::True) => {
341 self.advance();
342 Ok(Expression::Boolean(true))
343 }
344 Some(Token::False) => {
345 self.advance();
346 Ok(Expression::Boolean(false))
347 }
348 Some(Token::LParen) => {
349 self.advance();
350 let expr = self.parse_or()?;
351 if !matches!(self.peek(), Some(Token::RParen)) {
352 return Err(ParseError::UnclosedParen);
353 }
354 self.advance();
355 Ok(Expression::Group(Box::new(expr)))
356 }
357 Some(Token::Ident(name)) => {
358 self.advance();
359 self.parse_function_call(name)
360 }
361 Some(token) => Err(ParseError::UnexpectedToken(format!("{:?}", token))),
362 None => Err(ParseError::UnexpectedEof),
363 }
364 }
365
366 fn parse_function_call(&mut self, name: String) -> Result<Expression, ParseError> {
368 if !matches!(self.peek(), Some(Token::LParen)) {
370 return Err(ParseError::InvalidFunction(name));
371 }
372 self.advance();
373
374 let mut args = Vec::new();
375
376 if !matches!(self.peek(), Some(Token::RParen)) {
378 loop {
379 match self.peek().cloned() {
380 Some(Token::String(s)) => {
381 self.advance();
382 args.push(s);
383 }
384 Some(Token::Ident(s)) => {
385 self.advance();
387 args.push(s);
388 }
389 Some(token) => {
390 return Err(ParseError::UnexpectedToken(format!("{:?}", token)));
391 }
392 None => {
393 return Err(ParseError::UnclosedParen);
394 }
395 }
396
397 match self.peek() {
399 Some(Token::Comma) => {
400 self.advance();
401 }
402 Some(Token::RParen) => break,
403 Some(token) => {
404 return Err(ParseError::UnexpectedToken(format!("{:?}", token)));
405 }
406 None => {
407 return Err(ParseError::UnclosedParen);
408 }
409 }
410 }
411 }
412
413 if !matches!(self.peek(), Some(Token::RParen)) {
415 return Err(ParseError::UnclosedParen);
416 }
417 self.advance();
418
419 Ok(Expression::Function { name, args })
420 }
421}