hive_router_plan_executor/execution/
client_request_details.rs

1use std::collections::BTreeMap;
2
3use bytes::Bytes;
4use http::Method;
5use ntex_http::HeaderMap as NtexHeaderMap;
6use vrl::core::Value;
7
8use crate::utils::vrl::sonic_value_to_vrl_value;
9
10pub struct OperationDetails<'exec> {
11    pub name: Option<&'exec str>,
12    pub query: &'exec str,
13    pub kind: &'static str,
14}
15
16pub struct ClientRequestDetails<'exec, 'req> {
17    pub method: &'req Method,
18    pub url: &'req http::Uri,
19    pub headers: &'req NtexHeaderMap,
20    pub operation: OperationDetails<'exec>,
21    pub jwt: &'exec JwtRequestDetails<'req>,
22}
23
24pub enum JwtRequestDetails<'exec> {
25    Authenticated {
26        token: &'exec str,
27        prefix: Option<&'exec str>,
28        claims: &'exec sonic_rs::Value,
29        scopes: Option<Vec<String>>,
30    },
31    Unauthenticated,
32}
33
34impl From<&ClientRequestDetails<'_, '_>> for Value {
35    fn from(details: &ClientRequestDetails) -> Self {
36        // .request.headers
37        let headers_value = client_header_map_to_vrl_value(details.headers);
38
39        // .request.url
40        let url_value = Self::Object(BTreeMap::from([
41            (
42                "host".into(),
43                details.url.host().unwrap_or("unknown").into(),
44            ),
45            ("path".into(), details.url.path().into()),
46            (
47                "port".into(),
48                details
49                    .url
50                    .port_u16()
51                    .unwrap_or_else(|| {
52                        if details.url.scheme() == Some(&http::uri::Scheme::HTTPS) {
53                            443
54                        } else {
55                            80
56                        }
57                    })
58                    .into(),
59            ),
60        ]));
61
62        // .request.operation
63        let operation_value = Self::Object(BTreeMap::from([
64            ("name".into(), details.operation.name.into()),
65            ("type".into(), details.operation.kind.into()),
66            ("query".into(), details.operation.query.into()),
67        ]));
68
69        // .request.jwt
70        let jwt_value = match details.jwt {
71            JwtRequestDetails::Authenticated {
72                token,
73                prefix,
74                claims,
75                scopes,
76            } => Self::Object(BTreeMap::from([
77                ("authenticated".into(), Value::Boolean(true)),
78                ("token".into(), token.to_string().into()),
79                (
80                    "prefix".into(),
81                    prefix.unwrap_or_default().to_string().into(),
82                ),
83                ("claims".into(), sonic_value_to_vrl_value(claims)),
84                (
85                    "scopes".into(),
86                    match scopes {
87                        Some(scopes) => Value::Array(
88                            scopes
89                                .iter()
90                                .map(|v| Value::Bytes(Bytes::from(v.clone())))
91                                .collect(),
92                        ),
93                        None => Value::Array(vec![]),
94                    },
95                ),
96            ])),
97            JwtRequestDetails::Unauthenticated => Self::Object(BTreeMap::from([
98                ("authenticated".into(), Value::Boolean(false)),
99                ("token".into(), Value::Null),
100                ("prefix".into(), Value::Null),
101                ("claims".into(), Value::Object(BTreeMap::new())),
102                ("scopes".into(), Value::Array(vec![])),
103            ])),
104        };
105
106        Self::Object(BTreeMap::from([
107            ("method".into(), details.method.as_str().into()),
108            ("headers".into(), headers_value),
109            ("url".into(), url_value),
110            ("operation".into(), operation_value),
111            ("jwt".into(), jwt_value),
112        ]))
113    }
114}
115
116fn client_header_map_to_vrl_value(headers: &ntex_http::HeaderMap) -> Value {
117    let mut obj = BTreeMap::new();
118    for (header_name, header_value) in headers.iter() {
119        if let Ok(value) = header_value.to_str() {
120            obj.insert(
121                header_name.as_str().into(),
122                Value::Bytes(Bytes::from(value.to_owned())),
123            );
124        }
125    }
126    Value::Object(obj)
127}