leyline/core/response/
relay.rs1use http::HeaderMap;
2use http::header::{
3 CONNECTION, CONTENT_ENCODING, CONTENT_LENGTH, HeaderName, PROXY_AUTHENTICATE,
4 PROXY_AUTHORIZATION, TE, TRAILER, TRANSFER_ENCODING, UPGRADE,
5};
6
7use super::Response;
8use crate::core::session::decompress::{Decoder, content_codings};
9
10const KEEP_ALIVE: &str = "keep-alive";
11const PROXY_CONNECTION: &str = "proxy-connection";
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14#[non_exhaustive]
15pub enum RelayBody {
16 AsReceived,
17 Decoded,
18}
19
20impl Response {
21 pub fn relay_headers(&self, body: RelayBody) -> HeaderMap {
22 let body = match body {
23 RelayBody::Decoded if !self.decodes_body() => RelayBody::AsReceived,
24 other => other,
25 };
26 relay_headers(&self.headers, body)
27 }
28
29 fn decodes_body(&self) -> bool {
30 let encoding = content_codings(self.headers.get_all(CONTENT_ENCODING));
31 Decoder::new(encoding.as_deref(), &self.compression).is_ok_and(|decoder| decoder.is_some())
32 }
33}
34
35fn hop_by_hop() -> [HeaderName; 9] {
36 [
37 CONNECTION,
38 HeaderName::from_static(KEEP_ALIVE),
39 HeaderName::from_static(PROXY_CONNECTION),
40 PROXY_AUTHENTICATE,
41 PROXY_AUTHORIZATION,
42 TE,
43 TRAILER,
44 TRANSFER_ENCODING,
45 UPGRADE,
46 ]
47}
48
49pub fn relay_headers(headers: &HeaderMap, body: RelayBody) -> HeaderMap {
50 let mut out = headers.clone();
51 if body == RelayBody::Decoded && out.contains_key(CONTENT_ENCODING) {
52 out.remove(CONTENT_ENCODING);
53 out.remove(CONTENT_LENGTH);
54 }
55 let listed: Vec<String> = headers
56 .get_all(CONNECTION)
57 .iter()
58 .filter_map(|value| value.to_str().ok())
59 .flat_map(|value| value.split(','))
60 .map(|token| token.trim().to_ascii_lowercase())
61 .filter(|token| !token.is_empty())
62 .collect();
63 for name in hop_by_hop() {
64 out.remove(name);
65 }
66 for name in &listed {
67 out.remove(name.as_str());
68 }
69 out
70}