kutil_http/cache/middleware/
request.rs

1use super::{
2    super::super::{cache::*, headers::*},
3    configuration::*,
4    hooks::*,
5};
6
7use {http::*, kutil_transcoding::*};
8
9//
10// CacheableEncodableRequest
11//
12
13/// Cacheable and/or encodable request.
14pub trait CacheableEncodableRequest<RequestBodyT> {
15    /// May call `cacheable_by_request` hook.
16    fn should_skip_cache<CacheT, CacheKeyT>(
17        &self,
18        configuration: &MiddlewareCachingConfiguration<RequestBodyT, CacheT, CacheKeyT>,
19    ) -> bool;
20
21    /// May call `cache_key` hook.
22    fn cache_key_with_hook<CacheT, CacheKeyT>(
23        &self,
24        configuration: &MiddlewareCachingConfiguration<RequestBodyT, CacheT, CacheKeyT>,
25    ) -> CacheKeyT
26    where
27        CacheKeyT: CacheKey;
28
29    /// May call `encodable_by_request` hook.
30    fn select_encoding(&self, configuration: &MiddlewareEncodingConfiguration) -> Encoding;
31}
32
33impl<RequestBodyT> CacheableEncodableRequest<RequestBodyT> for Request<RequestBodyT> {
34    fn should_skip_cache<CacheT, CacheKeyT>(
35        &self,
36        configuration: &MiddlewareCachingConfiguration<RequestBodyT, CacheT, CacheKeyT>,
37    ) -> bool {
38        let mut skip_cache = if !configuration.cache.is_none() {
39            let method = self.method();
40            if method.is_idempotent() {
41                false
42            } else {
43                tracing::debug!("skip (non-idempotent {})", method);
44                true
45            }
46        } else {
47            tracing::debug!("skip (disabled)");
48            true
49        };
50
51        if !skip_cache {
52            if let Some(cacheable) = &configuration.cacheable_by_request {
53                if !cacheable(CacheableHookContext::new(self.uri(), self.headers())) {
54                    tracing::debug!("skip (cacheable_by_request=false)");
55                    skip_cache = true;
56                }
57            }
58        }
59
60        skip_cache
61    }
62
63    fn cache_key_with_hook<CacheT, CacheKeyT>(
64        &self,
65        configuration: &MiddlewareCachingConfiguration<RequestBodyT, CacheT, CacheKeyT>,
66    ) -> CacheKeyT
67    where
68        CacheKeyT: CacheKey,
69    {
70        let mut cache_key = self.cache_key();
71
72        if let Some(cache_key_hook) = &configuration.cache_key {
73            cache_key_hook(CacheKeyHookContext::new(&mut cache_key, self));
74        }
75
76        cache_key
77    }
78
79    fn select_encoding(&self, configuration: &MiddlewareEncodingConfiguration) -> Encoding {
80        let encoding = match &configuration.enabled_encodings_by_preference {
81            Some(enabled_encodings) => {
82                if !enabled_encodings.is_empty() {
83                    self.headers().accept_encoding().best(enabled_encodings).cloned().unwrap_or_default().into()
84                } else {
85                    return Encoding::Identity;
86                }
87            }
88
89            None => return Encoding::Identity,
90        };
91
92        if encoding != Encoding::Identity {
93            if let Some(encodable) = &configuration.encodable_by_request {
94                if !encodable(EncodableHookContext::new(&encoding, self.uri(), self.headers())) {
95                    tracing::debug!("not encoding to {} (encodable_by_request=false)", encoding);
96                    return Encoding::Identity;
97                }
98            }
99        }
100
101        encoding
102    }
103}