cratestack_axum/idempotency/
headers.rs1const HEADERS_NEVER_REPLAYED: &[&str] =
11 &["content-length", "connection", "transfer-encoding", "date"];
12
13fn is_replayable_header(name: &http::HeaderName) -> bool {
14 !HEADERS_NEVER_REPLAYED.contains(&name.as_str())
15}
16
17pub fn encode_headers(headers: &http::HeaderMap) -> Vec<u8> {
25 let mut iter = headers
26 .iter()
27 .filter(|(name, _)| is_replayable_header(name));
28 let pairs: Vec<_> = iter.by_ref().collect();
31 let mut blob = Vec::with_capacity(4 + pairs.len() * 16);
32 let count = pairs.len() as u32;
33 blob.extend_from_slice(&count.to_le_bytes());
34 for (name, value) in pairs {
35 let name_bytes = name.as_str().as_bytes();
36 let value_bytes = value.as_bytes();
37 blob.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
38 blob.extend_from_slice(name_bytes);
39 blob.extend_from_slice(&(value_bytes.len() as u32).to_le_bytes());
40 blob.extend_from_slice(value_bytes);
41 }
42 blob
43}
44
45pub fn decode_headers(blob: &[u8]) -> http::HeaderMap {
51 let mut headers = http::HeaderMap::new();
52 if blob.is_empty() {
53 return headers;
54 }
55 let mut cursor = 0;
56 let read_u32 = |bytes: &[u8], offset: usize| -> Option<usize> {
57 bytes
58 .get(offset..offset + 4)
59 .map(|b| u32::from_le_bytes(b.try_into().expect("4-byte slice")) as usize)
60 };
61 let Some(count) = read_u32(blob, cursor) else {
62 return headers;
63 };
64 cursor += 4;
65 for _ in 0..count {
66 let Some(name_len) = read_u32(blob, cursor) else {
67 return headers;
68 };
69 cursor += 4;
70 let Some(name_bytes) = blob.get(cursor..cursor + name_len) else {
71 return headers;
72 };
73 cursor += name_len;
74 let Some(value_len) = read_u32(blob, cursor) else {
75 return headers;
76 };
77 cursor += 4;
78 let Some(value_bytes) = blob.get(cursor..cursor + value_len) else {
79 return headers;
80 };
81 cursor += value_len;
82 let Ok(name) = http::HeaderName::from_bytes(name_bytes) else {
83 continue;
84 };
85 let Ok(value) = http::HeaderValue::from_bytes(value_bytes) else {
86 continue;
87 };
88 headers.append(name, value);
91 }
92 headers
93}