kutil_http/cache/key/
common.rs

1use super::{
2    super::{
3        super::{headers::*, uri::*},
4        weight::*,
5    },
6    key::*,
7};
8
9use {
10    bytes::*,
11    bytestring::*,
12    http::{header::*, uri::*, *},
13    std::{collections::*, fmt, hash::*},
14};
15
16//
17// CommonCacheKey
18//
19
20/// [CacheKey] implementation designed for common use cases.
21#[derive(Clone, Debug, Eq, Hash, PartialEq)]
22pub struct CommonCacheKey {
23    /// Method.
24    pub method: Method,
25
26    /// Optional path.
27    pub path: Option<ByteString>,
28
29    /// Optional query (sorted by key).
30    pub query: Option<BTreeMap<ByteString, ByteString>>,
31
32    /// Optional scheme.
33    ///
34    /// Not set by default but reserved for custom use.
35    pub scheme: Option<Scheme>,
36
37    /// Optional host.
38    ///
39    /// Not set by default but reserved for custom use.
40    pub host: Option<ByteString>,
41
42    /// Optional port.
43    ///
44    /// Not set by default but reserved for custom use.
45    pub port: Option<u16>,
46
47    /// Optional media type.
48    ///
49    /// Not set by default but reserved for custom use.
50    pub media_type: Option<MediaType>,
51
52    /// Optional languages (sorted).
53    ///
54    /// Not set by default but reserved for custom use.
55    pub languages: Option<BTreeSet<Language>>,
56
57    /// Optional extensions (sorted by key).
58    ///
59    /// Not set by default but reserved for custom use.
60    pub extensions: Option<BTreeMap<Bytes, Bytes>>,
61}
62
63impl CommonCacheKey {
64    /// Constructor.
65    pub fn new(
66        method: Method,
67        path: Option<ByteString>,
68        query: Option<BTreeMap<ByteString, ByteString>>,
69        scheme: Option<Scheme>,
70        host: Option<ByteString>,
71        port: Option<u16>,
72        media_type: Option<MediaType>,
73        languages: Option<BTreeSet<Language>>,
74        extensions: Option<BTreeMap<Bytes, Bytes>>,
75    ) -> Self {
76        Self { method, scheme, host, port, path, query, media_type, languages, extensions }
77    }
78}
79
80impl CacheKey for CommonCacheKey {
81    fn for_request(method: &Method, uri: &Uri, _headers: &HeaderMap) -> Self {
82        let (path, query) = match uri.path_and_query() {
83            Some(path_and_query) => (Some(path_and_query.path().into()), path_and_query.decoded_query_map()),
84            None => (None, None),
85        };
86
87        Self::new(method.clone(), path, query, None, None, None, None, None, None)
88    }
89}
90
91impl CacheWeight for CommonCacheKey {
92    fn cache_weight(&self) -> usize {
93        const SELF_SIZE: usize = size_of::<CommonCacheKey>();
94
95        let mut size = SELF_SIZE;
96
97        if let Some(host) = &self.host {
98            size += host.len();
99        }
100
101        if let Some(path) = &self.path {
102            size += path.len();
103        }
104
105        if let Some(query) = &self.query {
106            for (k, v) in query {
107                size += k.len() + v.len();
108            }
109        }
110
111        if let Some(media_type) = &self.media_type {
112            size += media_type.cache_weight();
113        }
114
115        if let Some(languages) = &self.languages {
116            for language in languages {
117                size += language.cache_weight();
118            }
119        }
120
121        if let Some(extensions) = &self.extensions {
122            for (k, v) in extensions {
123                size += k.len() + v.len();
124            }
125        }
126
127        size
128    }
129}
130
131impl fmt::Display for CommonCacheKey {
132    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
133        let scheme = self.scheme.as_ref().map(|scheme| scheme.as_str()).unwrap_or_default();
134        let host = self.host.as_ref().map(|host| AsRef::<str>::as_ref(host)).unwrap_or_default();
135        let port = self.port.map(|port| port.to_string()).unwrap_or_default();
136        let path = self.path.as_ref().map(|path| AsRef::<str>::as_ref(path)).unwrap_or_default();
137
138        let query = self
139            .query
140            .as_ref()
141            .map(|parameter| {
142                let mut string = String::new();
143                for (k, v) in parameter {
144                    if !string.is_empty() {
145                        string += "&"
146                    }
147                    string += &format!("{}={}", k, v);
148                }
149                string
150            })
151            .unwrap_or_default();
152
153        let media_type = self.media_type.as_ref().map(|media_type| media_type.to_string()).unwrap_or_default();
154
155        let languages = self
156            .languages
157            .as_ref()
158            .map(|languages| {
159                let languages: Vec<_> = languages.iter().map(|language| language.to_string()).collect();
160                languages.join(",")
161            })
162            .unwrap_or_default();
163
164        let extensions = self
165            .extensions
166            .as_ref()
167            .map(|extension| {
168                let mut string = String::new();
169                for (k, v) in extension {
170                    if !string.is_empty() {
171                        string += "&"
172                    }
173                    // We only display the length
174                    string += &format!("{}={}", k.len(), v.len());
175                }
176                string
177            })
178            .unwrap_or_default();
179
180        write!(
181            formatter,
182            "{}|{}|{}|{}|{}|{}|{}|{}|{}",
183            self.method, scheme, host, port, path, query, media_type, languages, extensions
184        )
185    }
186}