1pub struct HttpAttributes<'a> {
11 pub method: &'a str,
12 pub path: &'a str,
14 pub host: &'a str,
15 pub scheme: &'a str,
16 pub headers: &'a [(String, String)],
18 pub body: &'a [u8],
19 pub source_ip: &'a str,
20}
21
22fn varint(out: &mut Vec<u8>, mut value: u64) {
23 while value >= 0x80 {
24 out.push((value as u8) | 0x80);
25 value >>= 7;
26 }
27 out.push(value as u8);
28}
29
30fn bytes_field(out: &mut Vec<u8>, field: u32, value: &[u8]) {
31 varint(out, ((field as u64) << 3) | 2);
32 varint(out, value.len() as u64);
33 out.extend_from_slice(value);
34}
35
36fn string_field(out: &mut Vec<u8>, field: u32, value: &str) {
37 if !value.is_empty() {
38 bytes_field(out, field, value.as_bytes());
39 }
40}
41
42fn varint_field(out: &mut Vec<u8>, field: u32, value: u64) {
43 varint(out, (field as u64) << 3);
44 varint(out, value);
45}
46
47pub fn check_request(a: &HttpAttributes) -> Vec<u8> {
49 let mut http = Vec::new();
51 string_field(&mut http, 2, a.method);
52 for (name, value) in a.headers {
53 let mut entry = Vec::new();
54 string_field(&mut entry, 1, name);
55 string_field(&mut entry, 2, value);
56 bytes_field(&mut http, 3, &entry);
57 }
58 string_field(&mut http, 4, a.path);
59 string_field(&mut http, 5, a.host);
60 string_field(&mut http, 6, a.scheme);
61 if let Some((_, query)) = a.path.split_once('?') {
62 string_field(&mut http, 7, query);
63 }
64 varint_field(&mut http, 9, a.body.len() as u64);
65 string_field(&mut http, 10, "HTTP/1.1");
66 if !a.body.is_empty() {
67 bytes_field(&mut http, 12, a.body);
68 }
69 let mut request = Vec::new();
71 bytes_field(&mut request, 2, &http);
72 let mut socket_address = Vec::new();
74 string_field(&mut socket_address, 2, a.source_ip);
75 let mut address = Vec::new();
76 bytes_field(&mut address, 1, &socket_address);
77 let mut source = Vec::new();
78 bytes_field(&mut source, 1, &address);
79 let mut context = Vec::new();
81 bytes_field(&mut context, 1, &source);
82 bytes_field(&mut context, 4, &request);
83 let mut out = Vec::new();
84 bytes_field(&mut out, 1, &context);
85 out
86}
87
88enum Value<'a> {
90 Varint(u64),
91 Bytes(&'a [u8]),
92}
93
94fn read_varint(input: &[u8], at: &mut usize) -> Result<u64, String> {
95 let mut value = 0u64;
96 for shift in (0..64).step_by(7) {
97 let byte = *input.get(*at).ok_or("truncated varint")?;
98 *at += 1;
99 value |= u64::from(byte & 0x7f) << shift;
100 if byte < 0x80 {
101 return Ok(value);
102 }
103 }
104 Err("varint too long".to_string())
105}
106
107fn fields(input: &[u8]) -> Result<Vec<(u64, Value<'_>)>, String> {
109 let mut at = 0;
110 let mut out = Vec::new();
111 while at < input.len() {
112 let key = read_varint(input, &mut at)?;
113 let (field, wire) = (key >> 3, key & 7);
114 match wire {
115 0 => out.push((field, Value::Varint(read_varint(input, &mut at)?))),
116 2 => {
117 let len = read_varint(input, &mut at)? as usize;
118 let end = at.checked_add(len).filter(|e| *e <= input.len()).ok_or("truncated field")?;
119 out.push((field, Value::Bytes(&input[at..end])));
120 at = end;
121 }
122 1 => at = at.checked_add(8).filter(|e| *e <= input.len()).ok_or("truncated field")?,
123 5 => at = at.checked_add(4).filter(|e| *e <= input.len()).ok_or("truncated field")?,
124 other => return Err(format!("unsupported wire type {other}")),
125 }
126 }
127 Ok(out)
128}
129
130fn text(bytes: &[u8]) -> String {
131 String::from_utf8_lossy(bytes).into_owned()
132}
133
134#[derive(Debug, Default, PartialEq)]
136pub struct Verdict {
137 pub code: i32,
139 pub headers: Vec<(String, String)>,
141 pub headers_to_remove: Vec<String>,
143 pub denied_status: i32,
145 pub denied_body: String,
147}
148
149fn header_option(bytes: &[u8]) -> Result<Option<(String, String)>, String> {
151 for (field, value) in fields(bytes)? {
152 if let (1, Value::Bytes(header)) = (field, value) {
153 let (mut key, mut text_value, mut raw) = (String::new(), String::new(), None);
154 for (f, v) in fields(header)? {
155 match (f, v) {
156 (1, Value::Bytes(b)) => key = text(b),
157 (2, Value::Bytes(b)) => text_value = text(b),
158 (3, Value::Bytes(b)) => raw = Some(text(b)),
159 _ => {}
160 }
161 }
162 return Ok(Some((key, raw.unwrap_or(text_value))));
163 }
164 }
165 Ok(None)
166}
167
168pub fn check_response(message: &[u8]) -> Result<Verdict, String> {
170 let mut verdict = Verdict::default();
171 for (field, value) in fields(message)? {
172 match (field, value) {
173 (1, Value::Bytes(status)) => {
175 for (f, v) in fields(status)? {
176 if let (1, Value::Varint(code)) = (f, v) {
177 verdict.code = code as i32;
178 }
179 }
180 }
181 (2, Value::Bytes(denied)) => {
183 for (f, v) in fields(denied)? {
184 match (f, v) {
185 (1, Value::Bytes(status)) => {
186 for (sf, sv) in fields(status)? {
187 if let (1, Value::Varint(code)) = (sf, sv) {
188 verdict.denied_status = code as i32;
189 }
190 }
191 }
192 (2, Value::Bytes(option)) => verdict.headers.extend(header_option(option)?),
193 (3, Value::Bytes(body)) => verdict.denied_body = text(body),
194 _ => {}
195 }
196 }
197 }
198 (3, Value::Bytes(ok)) => {
200 for (f, v) in fields(ok)? {
201 match (f, v) {
202 (2, Value::Bytes(option)) => verdict.headers.extend(header_option(option)?),
203 (5, Value::Bytes(name)) => verdict.headers_to_remove.push(text(name)),
204 _ => {}
205 }
206 }
207 }
208 _ => {}
209 }
210 }
211 Ok(verdict)
212}
213
214#[doc(hidden)]
216pub fn encode_check_response(verdict: &Verdict) -> Vec<u8> {
217 let header = |name: &str, value: &str| {
218 let mut h = Vec::new();
219 string_field(&mut h, 1, name);
220 string_field(&mut h, 2, value);
221 let mut option = Vec::new();
222 bytes_field(&mut option, 1, &h);
223 option
224 };
225 let mut status = Vec::new();
226 if verdict.code != 0 {
227 varint_field(&mut status, 1, verdict.code as u64);
228 }
229 let mut out = Vec::new();
230 bytes_field(&mut out, 1, &status);
231 if verdict.code == 0 {
232 let mut ok = Vec::new();
233 for (name, value) in &verdict.headers {
234 bytes_field(&mut ok, 2, &header(name, value));
235 }
236 for name in &verdict.headers_to_remove {
237 string_field(&mut ok, 5, name);
238 }
239 bytes_field(&mut out, 3, &ok);
240 } else {
241 let mut denied = Vec::new();
242 let mut http_status = Vec::new();
243 if verdict.denied_status != 0 {
244 varint_field(&mut http_status, 1, verdict.denied_status as u64);
245 }
246 bytes_field(&mut denied, 1, &http_status);
247 for (name, value) in &verdict.headers {
248 bytes_field(&mut denied, 2, &header(name, value));
249 }
250 string_field(&mut denied, 3, &verdict.denied_body);
251 bytes_field(&mut out, 2, &denied);
252 }
253 out
254}
255
256#[doc(hidden)]
258pub fn decode_check_request(message: &[u8]) -> Result<(String, String, String, Vec<(String, String)>), String> {
259 let field = |bytes: &[u8], wanted: u64| -> Result<Vec<u8>, String> {
260 fields(bytes)?.into_iter().find_map(|(f, v)| match v {
261 Value::Bytes(b) if f == wanted => Some(b.to_vec()),
262 _ => None,
263 }).ok_or_else(|| format!("no field {wanted}"))
264 };
265 let context = field(message, 1)?;
266 let request = field(&context, 4)?;
267 let http = field(&request, 2)?;
268 let (mut method, mut path, mut host, mut headers) = (String::new(), String::new(), String::new(), Vec::new());
269 for (f, v) in fields(&http)? {
270 match (f, v) {
271 (2, Value::Bytes(b)) => method = text(b),
272 (3, Value::Bytes(entry)) => {
273 let (mut k, mut val) = (String::new(), String::new());
274 for (ef, ev) in fields(entry)? {
275 match (ef, ev) {
276 (1, Value::Bytes(b)) => k = text(b),
277 (2, Value::Bytes(b)) => val = text(b),
278 _ => {}
279 }
280 }
281 headers.push((k, val));
282 }
283 (4, Value::Bytes(b)) => path = text(b),
284 (5, Value::Bytes(b)) => host = text(b),
285 _ => {}
286 }
287 }
288 Ok((method, path, host, headers))
289}