-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move attribute parsing to attribute trait #65
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
use crate::configuration::Path; | ||
use crate::filter::http_context::Filter; | ||
use chrono::{DateTime, FixedOffset}; | ||
use proxy_wasm::traits::Context; | ||
|
||
pub trait Attribute { | ||
fn parse(raw_attribute: Vec<u8>) -> Result<Self, String> | ||
where | ||
Self: Sized; | ||
} | ||
|
||
impl Attribute for String { | ||
fn parse(raw_attribute: Vec<u8>) -> Result<Self, String> { | ||
String::from_utf8(raw_attribute).map_err(|err| { | ||
format!( | ||
"parse: failed to parse selector String value, error: {}", | ||
err | ||
) | ||
}) | ||
} | ||
} | ||
|
||
impl Attribute for i64 { | ||
fn parse(raw_attribute: Vec<u8>) -> Result<Self, String> { | ||
if raw_attribute.len() != 8 { | ||
return Err(format!( | ||
"Int value expected to be 8 bytes, but got {}", | ||
raw_attribute.len() | ||
)); | ||
} | ||
Ok(i64::from_le_bytes( | ||
raw_attribute[..8] | ||
.try_into() | ||
.expect("This has to be 8 bytes long!"), | ||
)) | ||
} | ||
} | ||
|
||
impl Attribute for u64 { | ||
fn parse(raw_attribute: Vec<u8>) -> Result<Self, String> { | ||
if raw_attribute.len() != 8 { | ||
return Err(format!( | ||
"UInt value expected to be 8 bytes, but got {}", | ||
raw_attribute.len() | ||
)); | ||
} | ||
Ok(u64::from_le_bytes( | ||
raw_attribute[..8] | ||
.try_into() | ||
.expect("This has to be 8 bytes long!"), | ||
)) | ||
} | ||
} | ||
|
||
impl Attribute for f64 { | ||
fn parse(raw_attribute: Vec<u8>) -> Result<Self, String> { | ||
if raw_attribute.len() != 8 { | ||
return Err(format!( | ||
"Float value expected to be 8 bytes, but got {}", | ||
raw_attribute.len() | ||
)); | ||
} | ||
Ok(f64::from_le_bytes( | ||
raw_attribute[..8] | ||
.try_into() | ||
.expect("This has to be 8 bytes long!"), | ||
)) | ||
} | ||
} | ||
|
||
impl Attribute for Vec<u8> { | ||
fn parse(raw_attribute: Vec<u8>) -> Result<Self, String> { | ||
Ok(raw_attribute) | ||
} | ||
} | ||
|
||
impl Attribute for bool { | ||
fn parse(raw_attribute: Vec<u8>) -> Result<Self, String> { | ||
if raw_attribute.len() != 1 { | ||
return Err(format!( | ||
"Bool value expected to be 1 byte, but got {}", | ||
raw_attribute.len() | ||
)); | ||
} | ||
Ok(raw_attribute[0] & 1 == 1) | ||
} | ||
} | ||
|
||
impl Attribute for DateTime<FixedOffset> { | ||
fn parse(raw_attribute: Vec<u8>) -> Result<Self, String> { | ||
if raw_attribute.len() != 8 { | ||
return Err(format!( | ||
"parse: Timestamp expected to be 8 bytes, but got {}", | ||
raw_attribute.len() | ||
)); | ||
} | ||
|
||
let nanos = i64::from_le_bytes( | ||
raw_attribute.as_slice()[..8] | ||
.try_into() | ||
.expect("This has to be 8 bytes long!"), | ||
); | ||
Ok(DateTime::from_timestamp_nanos(nanos).into()) | ||
} | ||
} | ||
|
||
pub fn get_attribute<T>(f: &Filter, attr: &str) -> Result<T, String> | ||
where | ||
T: Attribute, | ||
{ | ||
match f.get_property(Path::from(attr).tokens()) { | ||
None => Err(format!( | ||
"#{} get_attribute: not found: {}", | ||
f.context_id, attr | ||
)), | ||
Some(attribute_bytes) => T::parse(attribute_bytes), | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
use crate::policy::Policy; | ||
use crate::policy_index::PolicyIndex; | ||
use std::cell::OnceCell; | ||
use std::fmt::{Debug, Display, Formatter}; | ||
use std::sync::Arc; | ||
|
||
use cel_interpreter::objects::ValueType; | ||
use cel_interpreter::{Context, Expression, Value}; | ||
use cel_parser::{Atom, RelationOp}; | ||
use chrono::{DateTime, FixedOffset}; | ||
use serde::Deserialize; | ||
use std::cell::OnceCell; | ||
use std::fmt::{Debug, Display, Formatter}; | ||
use std::sync::Arc; | ||
|
||
use crate::attribute::Attribute; | ||
use crate::policy::Policy; | ||
use crate::policy_index::PolicyIndex; | ||
|
||
#[derive(Deserialize, Debug, Clone)] | ||
pub struct SelectorItem { | ||
|
@@ -22,7 +24,7 @@ | |
// An optional value to use if the selector is not found in the context. | ||
// If not set and the selector is not found in the context, then no data is generated. | ||
#[serde(default)] | ||
pub default: Option<String>, | ||
Check warning on line 27 in src/configuration.rs GitHub Actions / Test Suite
Check warning on line 27 in src/configuration.rs GitHub Actions / Rustfmt
Check warning on line 27 in src/configuration.rs GitHub Actions / Check
|
||
|
||
#[serde(skip_deserializing)] | ||
path: OnceCell<Path>, | ||
|
@@ -168,47 +170,13 @@ | |
pub fn eval(&self, raw_attribute: Vec<u8>) -> Result<bool, String> { | ||
let cel_type = &self.compiled.get().unwrap().cel_type; | ||
let value = match cel_type { | ||
ValueType::String => | ||
Value::String(String::from_utf8(raw_attribute).map_err(|err| format!( | ||
"pattern_expression_applies: failed to parse selector String value: {}, error: {}", | ||
self.selector, err))?.into()), | ||
ValueType::Int => { | ||
if raw_attribute.len() != 8 { | ||
return Err(format!("Int value expected to be 8 bytes, but got {}", raw_attribute.len())); | ||
} | ||
Value::Int(i64::from_le_bytes(raw_attribute[..8].try_into().expect("This has to be 8 bytes long!"))) | ||
}, | ||
ValueType::UInt => { | ||
{ | ||
if raw_attribute.len() != 8 { | ||
return Err(format!("UInt value expected to be 8 bytes, but got {}", raw_attribute.len())); | ||
} | ||
Value::UInt(u64::from_le_bytes(raw_attribute[..8].try_into().expect("This has to be 8 bytes long!"))) | ||
} | ||
}, | ||
ValueType::Float => { | ||
if raw_attribute.len() != 8 { | ||
return Err(format!("Float value expected to be 8 bytes, but got {}", raw_attribute.len())); | ||
} | ||
Value::Float(f64::from_le_bytes(raw_attribute[..8].try_into().expect("This has to be 8 bytes long!"))) | ||
}, | ||
ValueType::Bytes => Value::Bytes(raw_attribute.into()), | ||
ValueType::Bool => { | ||
if raw_attribute.len() != 1 { | ||
return Err(format!("Bool value expected to be 1 byte, but got {}", raw_attribute.len())); | ||
} | ||
Value::Bool(raw_attribute[0] & 1 == 1) | ||
} | ||
ValueType::Timestamp => { | ||
{ | ||
if raw_attribute.len() != 8 { | ||
return Err(format!("Timestamp expected to be 8 bytes, but got {}", raw_attribute.len())); | ||
} | ||
let nanos = i64::from_le_bytes(raw_attribute[..8].try_into().expect("This has to be 8 bytes long!")); | ||
let time: DateTime<FixedOffset> = DateTime::from_timestamp_nanos(nanos).into(); | ||
Value::Timestamp(time) | ||
} | ||
} | ||
ValueType::String => Value::String(Arc::new(Attribute::parse(raw_attribute)?)), | ||
ValueType::Int => Value::Int(Attribute::parse(raw_attribute)?), | ||
ValueType::UInt => Value::UInt(Attribute::parse(raw_attribute)?), | ||
ValueType::Float => Value::Float(Attribute::parse(raw_attribute)?), | ||
ValueType::Bytes => Value::Bytes(Arc::new(Attribute::parse(raw_attribute)?)), | ||
ValueType::Bool => Value::Bool(Attribute::parse(raw_attribute)?), | ||
ValueType::Timestamp => Value::Timestamp(Attribute::parse(raw_attribute)?), | ||
Comment on lines
+173
to
+179
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice ❤️ |
||
// todo: Impl support for parsing these two types… Tho List/Map of what? | ||
// ValueType::List => {} | ||
// ValueType::Map => {} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
mod attribute; | ||
mod configuration; | ||
mod envoy; | ||
mod filter; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could "just" be the
TryInto
trait, but it is that against the orphan rules