tower_http_cache/
codec.rs

1use bytes::Bytes;
2use http::{StatusCode, Version};
3use serde::{Deserialize, Serialize};
4
5use crate::backend::CacheEntry;
6use crate::error::CacheError;
7
8/// Trait representing a serialization strategy for cached entries.
9pub trait CacheCodec: Send + Sync + Clone + 'static {
10    fn encode(&self, entry: &CacheEntry) -> Result<Vec<u8>, CacheError>;
11    fn decode(&self, bytes: &[u8]) -> Result<CacheEntry, CacheError>;
12}
13
14/// Default [`CacheCodec`] implementation backed by `bincode`.
15#[derive(Clone, Default)]
16pub struct BincodeCodec;
17
18#[derive(Serialize, Deserialize)]
19struct StoredEntry {
20    status: u16,
21    version: u8,
22    headers: Vec<(String, Vec<u8>)>,
23    body: Vec<u8>,
24}
25
26impl CacheCodec for BincodeCodec {
27    fn encode(&self, entry: &CacheEntry) -> Result<Vec<u8>, CacheError> {
28        let stored = StoredEntry {
29            status: entry.status.as_u16(),
30            version: version_to_u8(entry.version),
31            headers: entry.headers.clone(),
32            body: entry.body.to_vec(),
33        };
34
35        bincode::serialize(&stored).map_err(|err| CacheError::Backend(err.to_string()))
36    }
37
38    fn decode(&self, bytes: &[u8]) -> Result<CacheEntry, CacheError> {
39        let stored: StoredEntry =
40            bincode::deserialize(bytes).map_err(|err| CacheError::Backend(err.to_string()))?;
41        let entry = CacheEntry::new(
42            StatusCode::from_u16(stored.status)
43                .map_err(|err| CacheError::Backend(err.to_string()))?,
44            version_from_u8(stored.version)?,
45            stored.headers,
46            Bytes::from(stored.body),
47        );
48        Ok(entry)
49    }
50}
51
52fn version_to_u8(version: Version) -> u8 {
53    match version {
54        Version::HTTP_09 => 0,
55        Version::HTTP_10 => 1,
56        Version::HTTP_11 => 2,
57        Version::HTTP_2 => 3,
58        Version::HTTP_3 => 4,
59        _ => 2,
60    }
61}
62
63fn version_from_u8(value: u8) -> Result<Version, CacheError> {
64    match value {
65        0 => Ok(Version::HTTP_09),
66        1 => Ok(Version::HTTP_10),
67        2 => Ok(Version::HTTP_11),
68        3 => Ok(Version::HTTP_2),
69        4 => Ok(Version::HTTP_3),
70        _ => Err(CacheError::Backend("unknown HTTP version".into())),
71    }
72}