Skip to main content

hive_router_plan_executor/execution/
client_request_details.rs

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