use std::{
fmt,
net::SocketAddr,
time::{Duration, SystemTime},
};
use log::warn;
use crate::property::all::AllAttributes;
use super::{get_property_bool, get_property_decode, get_property_int, get_property_string};
mod attributes_proto {
include!(concat!(env!("OUT_DIR"), "/proxywasm.attributes.rs"));
}
pub use attributes_proto::*;
pub struct Attributes {
pub request: RequestAttributes,
pub response: ResponseAttributes,
pub connection: ConnectionAttributes,
pub upstream: UpstreamAttributes,
pub metadata: MetadataAttributes,
pub configuration: ConfigurationAttributes,
pub wasm: WasmAttributes,
}
impl Attributes {
pub(crate) fn get() -> Self {
Self {
request: RequestAttributes(()),
response: ResponseAttributes(()),
connection: ConnectionAttributes(()),
upstream: UpstreamAttributes(()),
metadata: MetadataAttributes(()),
configuration: ConfigurationAttributes(()),
wasm: WasmAttributes(()),
}
}
}
impl fmt::Debug for Attributes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:#?}", AllAttributes::get(self))
}
}
pub struct RequestAttributes(());
impl RequestAttributes {
pub fn path(&self) -> Option<String> {
get_property_string("request.path")
}
pub fn url_path(&self) -> Option<String> {
get_property_string("request.url_path")
}
pub fn host(&self) -> Option<String> {
get_property_string("request.host")
}
pub fn scheme(&self) -> Option<String> {
get_property_string("request.scheme")
}
pub fn method(&self) -> Option<String> {
get_property_string("request.scheme")
}
pub fn headers(&self) -> Option<Vec<(String, Vec<u8>)>> {
let headers = get_property_decode::<attributes_proto::StringMap>("request.headers")?;
Some(headers.map.into_iter().map(|x| (x.key, x.value)).collect())
}
pub fn referer(&self) -> Option<String> {
get_property_string("request.referer")
}
pub fn useragent(&self) -> Option<String> {
get_property_string("request.useragent")
}
pub fn time(&self) -> Option<SystemTime> {
let raw = get_property_decode::<prost_types::Timestamp>("request.time")?;
if raw.seconds < 0 || raw.nanos < 0 {
warn!("request.time returned a negative timestamp, skipped");
None
} else {
Some(SystemTime::UNIX_EPOCH + Duration::new(raw.seconds as u64, raw.nanos as u32))
}
}
pub fn id(&self) -> Option<String> {
get_property_string("request.id")
}
pub fn protocol(&self) -> Option<String> {
get_property_string("request.protocol")
}
pub fn query(&self) -> Option<String> {
get_property_string("request.query")
}
pub fn duration(&self) -> Option<Duration> {
let raw = get_property_decode::<prost_types::Duration>("request.duration")?;
if raw.seconds < 0 || raw.nanos < 0 {
warn!("request.duration returned a negative duration, skipped");
None
} else {
Some(Duration::new(raw.seconds as u64, raw.nanos as u32))
}
}
pub fn size(&self) -> Option<usize> {
get_property_int("request.size").map(|x| x as usize)
}
pub fn total_size(&self) -> Option<usize> {
get_property_int("request.total_size").map(|x| x as usize)
}
}
pub struct ResponseAttributes(());
impl ResponseAttributes {
pub fn code(&self) -> Option<u32> {
get_property_int("response.code").map(|x| x as u32)
}
pub fn code_details(&self) -> Option<String> {
get_property_string("response.code_details")
}
pub fn flags(&self) -> Option<u64> {
get_property_int("response.flags").map(|x| x as u64)
}
pub fn grpc_status(&self) -> Option<u32> {
get_property_int("response.grpc_status").map(|x| x as u32)
}
pub fn headers(&self) -> Option<Vec<(String, Vec<u8>)>> {
let headers = get_property_decode::<attributes_proto::StringMap>("response.headers")?;
Some(headers.map.into_iter().map(|x| (x.key, x.value)).collect())
}
pub fn trailers(&self) -> Option<Vec<(String, Vec<u8>)>> {
let headers = get_property_decode::<attributes_proto::StringMap>("response.trailers")?;
Some(headers.map.into_iter().map(|x| (x.key, x.value)).collect())
}
pub fn size(&self) -> Option<usize> {
get_property_int("response.size").map(|x| x as usize)
}
pub fn total_size(&self) -> Option<usize> {
get_property_int("response.total_size").map(|x| x as usize)
}
}
pub struct ConnectionAttributes(());
impl ConnectionAttributes {
pub fn source_address(&self) -> Option<SocketAddr> {
get_property_string("source.address").and_then(|x| x.parse().ok())
}
pub fn source_port(&self) -> Option<u16> {
get_property_int("source.port").map(|x| x as u16)
}
pub fn destination_address(&self) -> Option<SocketAddr> {
get_property_string("destination.address").and_then(|x| x.parse().ok())
}
pub fn destination_port(&self) -> Option<u16> {
get_property_int("destination.port").map(|x| x as u16)
}
pub fn id(&self) -> Option<u64> {
get_property_int("connection.id").map(|x| x as u64)
}
pub fn mtls(&self) -> Option<bool> {
get_property_bool("connection.mtls")
}
pub fn requested_server_name(&self) -> Option<String> {
get_property_string("connection.requested_server_name")
}
pub fn tls_version(&self) -> Option<String> {
get_property_string("connection.tls_version")
}
pub fn subject_local_certificate(&self) -> Option<String> {
get_property_string("connection.subject_local_certificate")
}
pub fn subject_peer_certificate(&self) -> Option<String> {
get_property_string("connection.subject_peer_certificate")
}
pub fn dns_san_local_certificate(&self) -> Option<String> {
get_property_string("connection.dns_san_local_certificate")
}
pub fn dns_san_peer_certificate(&self) -> Option<String> {
get_property_string("connection.dns_san_peer_certificate")
}
pub fn uri_san_local_certificate(&self) -> Option<String> {
get_property_string("connection.uri_san_local_certificate")
}
pub fn uri_san_peer_certificate(&self) -> Option<String> {
get_property_string("connection.uri_san_peer_certificate")
}
pub fn sha256_peer_certificate_digest(&self) -> Option<String> {
get_property_string("connection.sha256_peer_certificate_digest")
}
pub fn termination_details(&self) -> Option<String> {
get_property_string("connection.termination_details")
}
}
pub struct UpstreamAttributes(());
impl UpstreamAttributes {
pub fn address(&self) -> Option<SocketAddr> {
get_property_string("upstream.address").and_then(|x| x.parse().ok())
}
pub fn port(&self) -> Option<u16> {
get_property_int("upstream.port").map(|x| x as u16)
}
pub fn tls_version(&self) -> Option<String> {
get_property_string("upstream.tls_version")
}
pub fn subject_local_certificate(&self) -> Option<String> {
get_property_string("upstream.subject_local_certificate")
}
pub fn subject_peer_certificate(&self) -> Option<String> {
get_property_string("upstream.subject_peer_certificate")
}
pub fn dns_san_local_certificate(&self) -> Option<String> {
get_property_string("upstream.dns_san_local_certificate")
}
pub fn dns_san_peer_certificate(&self) -> Option<String> {
get_property_string("upstream.dns_san_peer_certificate")
}
pub fn uri_san_local_certificate(&self) -> Option<String> {
get_property_string("upstream.uri_san_local_certificate")
}
pub fn uri_san_peer_certificate(&self) -> Option<String> {
get_property_string("upstream.uri_san_peer_certificate")
}
pub fn sha256_peer_certificate_digest(&self) -> Option<String> {
get_property_string("upstream.sha256_peer_certificate_digest")
}
pub fn local_address(&self) -> Option<String> {
get_property_string("upstream.local_address")
}
pub fn transport_failure_reason(&self) -> Option<String> {
get_property_string("upstream.transport_failure_reason")
}
}
pub struct MetadataAttributes(());
impl MetadataAttributes {
pub fn metadata(&self) -> Option<Metadata> {
get_property_decode("metadata")
}
pub fn filter_state(&self) -> Option<Vec<(String, Vec<u8>)>> {
let headers = get_property_decode::<attributes_proto::StringMap>("filter_state")?;
Some(headers.map.into_iter().map(|x| (x.key, x.value)).collect())
}
}
pub struct ConfigurationAttributes(());
impl ConfigurationAttributes {
pub fn cluster_name(&self) -> Option<String> {
get_property_string("xds.cluster_name")
}
pub fn cluster_metadata(&self) -> Option<Metadata> {
get_property_decode("xds.cluster_metadata")
}
pub fn route_name(&self) -> Option<String> {
get_property_string("xds.route_name")
}
pub fn route_metadata(&self) -> Option<Metadata> {
get_property_decode("xds.route_metadata")
}
pub fn upstream_host_metadata(&self) -> Option<Metadata> {
get_property_decode("xds.upstream_host_metadata")
}
pub fn filter_chain_name(&self) -> Option<String> {
get_property_string("xds.filter_chain_name")
}
}
#[repr(i64)]
#[derive(Debug)]
pub enum ListenerDirection {
Unspecified = 0,
Inbound = 1,
Outbound = 2,
}
impl ListenerDirection {
pub fn from_i64(v: i64) -> Option<Self> {
match v {
0 => Some(ListenerDirection::Unspecified),
1 => Some(ListenerDirection::Inbound),
2 => Some(ListenerDirection::Outbound),
_ => None,
}
}
}
pub struct WasmAttributes(());
impl WasmAttributes {
pub fn get() -> Self {
Self(())
}
pub fn plugin_name(&self) -> Option<String> {
get_property_string("plugin_name")
}
pub fn plugin_root_id(&self) -> Option<String> {
get_property_string("plugin_root_id")
}
pub fn plugin_vm_id(&self) -> Option<String> {
get_property_string("plugin_vm_id")
}
pub fn node(&self) -> Option<Node> {
get_property_decode("node")
}
pub fn cluster_name(&self) -> Option<String> {
get_property_string("cluster_name")
}
pub fn cluster_metadata(&self) -> Option<Metadata> {
get_property_decode("cluster_metadata")
}
pub fn listener_direction(&self) -> Option<ListenerDirection> {
get_property_int("listener_direction").and_then(ListenerDirection::from_i64)
}
pub fn listener_metadata(&self) -> Option<Metadata> {
get_property_decode("listener_metadata")
}
pub fn route_name(&self) -> Option<String> {
get_property_string("route_name")
}
pub fn route_metadata(&self) -> Option<Metadata> {
get_property_decode("route_metadata")
}
pub fn upstream_host_metadata(&self) -> Option<Metadata> {
get_property_decode("upstream_host_metadata")
}
}