Skip to content
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

Typing2 #45

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 19 additions & 18 deletions src/configuration.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::glob::GlobPattern;
use crate::policy_index::PolicyIndex;
use crate::typing::TypedProperty;
use log::warn;
use serde::Deserialize;

Expand Down Expand Up @@ -54,36 +55,36 @@ pub enum WhenConditionOperator {
Matches,
}

impl WhenConditionOperator {
pub fn eval(&self, value: &str, attr_value: &str) -> bool {
match *self {
WhenConditionOperator::Equal => value.eq(attr_value),
WhenConditionOperator::NotEqual => !value.eq(attr_value),
WhenConditionOperator::StartsWith => attr_value.starts_with(value),
WhenConditionOperator::EndsWith => attr_value.ends_with(value),
WhenConditionOperator::Matches => match GlobPattern::try_from(value) {
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PatternExpression {
pub selector: String,
pub operator: WhenConditionOperator,
pub value: String,
}

impl PatternExpression {
pub fn eval(&self, value: &TypedProperty) -> bool {
match self.operator {
WhenConditionOperator::Equal => value.eq(&self.value),
WhenConditionOperator::NotEqual => value.ne(&self.value),
WhenConditionOperator::StartsWith => value.as_string().starts_with(&self.value),
WhenConditionOperator::EndsWith => value.as_string().ends_with(&self.value),
WhenConditionOperator::Matches => match GlobPattern::try_from(self.value.as_str()) {
// TODO(eastizle): regexp being compiled and validated at request time.
// Validations and possibly regexp compilation should happen at boot time instead.
// In addition, if the regexp is not valid, the only consequence is that
// the current condition would not apply
Ok(glob_pattern) => glob_pattern.is_match(attr_value),
Ok(glob_pattern) => glob_pattern.is_match(&value.as_string()),
Err(e) => {
warn!("failed to parse regexp: {value}, error: {e:?}");
warn!("failed to parse regexp: {}, error: {e:?}", self.value);
false
}
},
}
}
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PatternExpression {
pub selector: String,
pub operator: WhenConditionOperator,
pub value: String,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Condition {
Expand Down
22 changes: 5 additions & 17 deletions src/envoy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,12 @@ mod timestamp;
mod token_bucket;
mod value;

pub mod properties;

pub use {
address::{
Address, Address_oneof_address, SocketAddress, SocketAddress_Protocol,
SocketAddress_oneof_port_specifier as SocketAddress_port,
},
attribute_context::{
AttributeContext, AttributeContext_HttpRequest, AttributeContext_Peer,
AttributeContext_Request,
},
base::HeaderValue,
base::Metadata,
external_auth::{CheckRequest, CheckResponse},
ratelimit::{RateLimitDescriptor, RateLimitDescriptor_Entry},
rls::{RateLimitRequest, RateLimitResponse, RateLimitResponse_Code},
route_components::{
HeaderMatcher, HeaderMatcher_oneof_header_match_specifier as HeaderMatcher_specifier,
RateLimit_Action, RateLimit_Action_oneof_action_specifier as RLA_action_specifier,
},
string::StringMatcher_oneof_match_pattern as StringMatcher_pattern,
timestamp::Timestamp,
};

#[cfg(test)]
pub use base::HeaderValue;
201 changes: 201 additions & 0 deletions src/envoy/properties.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
use crate::typing::TypedProperty;
use std::collections::BTreeMap;

type MapperFn = dyn Fn(Vec<u8>) -> TypedProperty;

pub struct EnvoyTypeMapper {
known_properties: BTreeMap<String, Box<MapperFn>>,
}

impl EnvoyTypeMapper {
pub fn new() -> Self {
let mut properties: BTreeMap<String, Box<MapperFn>> = BTreeMap::new();
properties.insert(
"request.time".to_string(),
Box::new(TypedProperty::timestamp),
);

properties.insert("request.id".to_string(), Box::new(TypedProperty::string));
properties.insert(
"request.protocol".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"request.scheme".to_string(),
Box::new(TypedProperty::string),
);
properties.insert("request.host".to_string(), Box::new(TypedProperty::string));
properties.insert(
"request.method".to_string(),
Box::new(TypedProperty::string),
);
properties.insert("request.path".to_string(), Box::new(TypedProperty::string));
properties.insert(
"request.url_path".to_string(),
Box::new(TypedProperty::string),
);
properties.insert("request.query".to_string(), Box::new(TypedProperty::string));
properties.insert(
"request.referer".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"request.useragent".to_string(),
Box::new(TypedProperty::string),
);
properties.insert("request.body".to_string(), Box::new(TypedProperty::string));
properties.insert(
"source.address".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"source.service".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"source.principal".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"source.certificate".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"destination.address".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"destination.service".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"destination.principal".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"destination.certificate".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.requested_server_name".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.tls_session.sni".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.tls_version".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.subject_local_certificate".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.subject_peer_certificate".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.dns_san_local_certificate".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.dns_san_peer_certificate".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.uri_san_local_certificate".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.uri_san_peer_certificate".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"connection.sha256_peer_certificate_digest".to_string(),
Box::new(TypedProperty::string),
);
properties.insert(
"ratelimit.domain".to_string(),
Box::new(TypedProperty::string),
);

properties.insert("request.size".to_string(), Box::new(TypedProperty::integer));
properties.insert("source.port".to_string(), Box::new(TypedProperty::integer));
properties.insert(
"destination.port".to_string(),
Box::new(TypedProperty::integer),
);
properties.insert(
"connection.id".to_string(),
Box::new(TypedProperty::integer),
);
properties.insert(
"ratelimit.hits_addend".to_string(),
Box::new(TypedProperty::integer),
);

properties.insert("metadata".to_string(), Box::new(TypedProperty::metadata));

properties.insert(
"request.headers".to_string(),
Box::new(TypedProperty::string_map),
);
properties.insert(
"request.context_extensions".to_string(),
Box::new(TypedProperty::string_map),
);
properties.insert(
"source.labels".to_string(),
Box::new(TypedProperty::string_map),
);
properties.insert(
"destination.labels".to_string(),
Box::new(TypedProperty::string_map),
);
properties.insert(
"filter_state".to_string(),
Box::new(TypedProperty::string_map),
);

properties.insert(
"auth.metadata".to_string(),
Box::new(TypedProperty::complex_map),
);
properties.insert(
"auth.authorization".to_string(),
Box::new(TypedProperty::complex_map),
);
properties.insert(
"auth.response".to_string(),
Box::new(TypedProperty::complex_map),
);
properties.insert(
"auth.callbacks".to_string(),
Box::new(TypedProperty::complex_map),
);

properties.insert(
"connection.mtls".to_string(),
Box::new(TypedProperty::boolean),
);

properties.insert(
"request.raw_body".to_string(),
Box::new(TypedProperty::bytes),
);
properties.insert("auth.identity".to_string(), Box::new(TypedProperty::bytes));

Self {
known_properties: properties,
}
}

pub fn typed(&self, path: &str, raw: Vec<u8>) -> Result<TypedProperty, Vec<u8>> {
match self.known_properties.get(path) {
None => Err(raw),
Some(mapper) => Ok(mapper(raw)),
}
}
}
3 changes: 3 additions & 0 deletions src/filter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::envoy::properties::EnvoyTypeMapper;

mod http_context;
mod root_context;

Expand Down Expand Up @@ -35,6 +37,7 @@ extern "C" fn start() {
Box::new(FilterRoot {
context_id,
config: Rc::new(FilterConfig::new()),
property_mapper: Rc::new(EnvoyTypeMapper::new()),
})
});
}
Loading
Loading