tower_http_cache/codec/
mod.rs1pub mod envelope;
16#[cfg(feature = "legacy-bincode1-read")]
17pub mod legacy;
18
19use bytes::Bytes;
20use http::{StatusCode, Version};
21use serde::{Deserialize, Serialize};
22
23use crate::backend::CacheEntry;
24use crate::error::CacheError;
25
26pub trait CacheCodec: Send + Sync + Clone + 'static {
32 const CODEC_ID: u8 = envelope::CODEC_USER;
42
43 fn encode(&self, entry: &CacheEntry) -> Result<Vec<u8>, CacheError>;
44 fn decode(&self, bytes: &[u8]) -> Result<CacheEntry, CacheError>;
45}
46
47#[derive(Clone, Default)]
52pub struct PostcardCodec;
53
54#[deprecated(
56 since = "0.6.0",
57 note = "renamed to PostcardCodec; the default wire format is now postcard inside a versioned envelope, not bare bincode"
58)]
59pub type BincodeCodec = PostcardCodec;
60
61#[derive(Serialize, Deserialize)]
62struct StoredEntry {
63 status: u16,
64 version: u8,
65 headers: Vec<(String, Vec<u8>)>,
66 body: Vec<u8>,
67 tags: Option<Vec<String>>,
68}
69
70impl CacheCodec for PostcardCodec {
71 const CODEC_ID: u8 = envelope::CODEC_POSTCARD;
72
73 fn encode(&self, entry: &CacheEntry) -> Result<Vec<u8>, CacheError> {
74 let stored = StoredEntry {
75 status: entry.status.as_u16(),
76 version: version_to_u8(entry.version),
77 headers: entry.headers.clone(),
78 body: entry.body.to_vec(),
79 tags: entry.tags.clone(),
80 };
81
82 postcard::to_allocvec(&stored).map_err(|err| CacheError::Backend(err.to_string()))
83 }
84
85 fn decode(&self, bytes: &[u8]) -> Result<CacheEntry, CacheError> {
86 let stored: StoredEntry =
87 postcard::from_bytes(bytes).map_err(|err| CacheError::Backend(err.to_string()))?;
88 Ok(CacheEntry {
92 status: StatusCode::from_u16(stored.status)
93 .map_err(|err| CacheError::Backend(err.to_string()))?,
94 version: version_from_u8(stored.version)?,
95 headers: stored.headers,
96 body: Bytes::from(stored.body),
97 tags: stored.tags,
98 })
99 }
100}
101
102pub(crate) fn version_to_u8(version: Version) -> u8 {
103 match version {
104 Version::HTTP_09 => 0,
105 Version::HTTP_10 => 1,
106 Version::HTTP_11 => 2,
107 Version::HTTP_2 => 3,
108 Version::HTTP_3 => 4,
109 _ => 2,
110 }
111}
112
113pub(crate) fn version_from_u8(value: u8) -> Result<Version, CacheError> {
114 match value {
115 0 => Ok(Version::HTTP_09),
116 1 => Ok(Version::HTTP_10),
117 2 => Ok(Version::HTTP_11),
118 3 => Ok(Version::HTTP_2),
119 4 => Ok(Version::HTTP_3),
120 _ => Err(CacheError::Backend("unknown HTTP version".into())),
121 }
122}