-
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 all commits
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,119 @@ | ||
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!( | ||
"parse: 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!( | ||
"parse: 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!( | ||
"parse: 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!( | ||
"parse: 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()) | ||
} | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn get_attribute<T>(f: &Filter, attr: &str) -> Result<T, String> | ||
Comment on lines
+107
to
+108
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. This is apparently still 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. As an example when I was building some request stuff for auth I was using it like this (providing a default to infer types):
But then again now I think about it, these should probably remain unset if we can't get the attribute and not be a default value. 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. Yeah, that actually makes sense... forgot that in the case of auth, there is a set of attributes (both their name and type) that need to be retrieved no matter what... so yes, that |
||
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 { | ||
|
@@ -168,47 +170,13 @@ impl PatternExpression { | |
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)?), | ||
// todo: Impl support for parsing these two types… Tho List/Map of what? | ||
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 ❤️ |
||
// 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