Skip to main content

sark_core/http/response/
mono.rs

1use http::{HeaderValue, StatusCode};
2use o3::buffer::Shared;
3
4use super::wire_emit::{CRLF, ContentLength, HeadWrite, HeaderSection, Out, PLACEHOLDER_DATE};
5use super::{HeadInner, HeaderList, HeadersInner, HotBodyInner, HotHeadInner, IntoHeaderName};
6
7struct MonoHeaders<'a, 'req> {
8    head: &'a HotHeadInner<'req>,
9    dynamic: Option<&'a HeaderList>,
10}
11
12impl HeaderSection for MonoHeaders<'_, '_> {
13    fn header_len(&self) -> usize {
14        let head = match self.head {
15            HotHeadInner::Wire(bytes) => bytes.len(),
16            HotHeadInner::Direct(head) => head.wire_len(),
17        };
18        head + self.dynamic.map_or(0, HeaderList::wire_len)
19    }
20
21    fn write_headers(&self, out: &mut [u8], off: &mut usize) {
22        match self.head {
23            HotHeadInner::Wire(bytes) => Out::put(out, off, bytes),
24            HotHeadInner::Direct(head) => {
25                let written = head
26                    .write_slice(&mut out[*off..])
27                    .expect("HeadWrite invariant: head buffer reserved via wire_len");
28                *off += written;
29            }
30        }
31        if let Some(h) = self.dynamic {
32            for (name, value) in h.iter() {
33                Out::put(out, off, name.as_str().as_bytes());
34                Out::put(out, off, b": ");
35                Out::put(out, off, value.as_bytes());
36                Out::put(out, off, CRLF);
37            }
38        }
39    }
40}
41
42#[derive(Clone, Debug)]
43pub struct MonoResponseInner<'req> {
44    pub(super) status: StatusCode,
45    pub(super) headers: Option<Box<HeaderList>>,
46    pub(super) head: HotHeadInner<'req>,
47    pub(super) body: HotBodyInner<'req>,
48}
49
50impl<'req> MonoResponseInner<'req> {
51    pub fn from_static_slice_body(
52        status: StatusCode,
53        static_headers: &'static [u8],
54        headers: HeadersInner<'req>,
55        body: &'static [u8],
56    ) -> Self {
57        Self {
58            status,
59            headers: None,
60            head: HotHeadInner::Direct(HeadInner::new(static_headers, headers)),
61            body: HotBodyInner::StaticSlice(body),
62        }
63    }
64
65    pub fn status(&self) -> StatusCode {
66        self.status
67    }
68
69    pub fn headers(&self) -> &HeaderList {
70        match &self.headers {
71            Some(h) => h.as_ref(),
72            None => HeaderList::empty_static(),
73        }
74    }
75
76    pub fn headers_mut(&mut self) -> &mut HeaderList {
77        self.headers
78            .get_or_insert_with(|| Box::new(HeaderList::new()))
79            .as_mut()
80    }
81
82    pub fn insert_header<N>(&mut self, name: N, value: HeaderValue) -> &mut Self
83    where
84        N: IntoHeaderName,
85    {
86        let _ = self.headers_mut().insert(name, value);
87        self
88    }
89
90    pub fn write_into_slice(&self, out: &mut [u8], date: &[u8; 29]) -> Option<usize> {
91        let (mut off, _) = self.write_head_into(out, date)?;
92        let body_len = self.body.body_len();
93        if out.len() - off < body_len {
94            return None;
95        }
96        off += self.body.write_to(&mut out[off..off + body_len]);
97        Some(off)
98    }
99
100    pub fn write_head_only(
101        &self,
102        out: &mut [u8],
103        date: &[u8; 29],
104    ) -> Option<(usize, &'static [u8])> {
105        let body = match &self.body {
106            HotBodyInner::StaticSlice(s) => *s,
107            _ => return None,
108        };
109        let (off, _) = self.write_head_into(out, date)?;
110        Some((off, body))
111    }
112
113    pub fn write_head_split(self, out: &mut [u8], date: &[u8; 29]) -> Option<(usize, Shared)> {
114        let (off, _) = self.write_head_into(out, date)?;
115        Some((off, self.body.into_shared()))
116    }
117
118    pub fn preserialize_static(&self) -> Option<(Vec<u8>, usize, &'static [u8])> {
119        let body = match &self.body {
120            HotBodyInner::StaticSlice(s) => *s,
121            _ => return None,
122        };
123        let mut buf = vec![0u8; self.with_head(|head| head.wire_len())];
124        let (_, date_offset) = self.write_head_into(&mut buf, PLACEHOLDER_DATE)?;
125        Some((buf, date_offset, body))
126    }
127
128    fn with_head<R>(
129        &self,
130        f: impl FnOnce(&HeadWrite<'_, MonoHeaders<'_, 'req>, ContentLength<'_>>) -> R,
131    ) -> R {
132        let mut cl_raw = [0u8; 20];
133        let cl_n = crate::http::codec::Wire::write_dec(self.body.body_len(), &mut cl_raw);
134        let section = MonoHeaders {
135            head: &self.head,
136            dynamic: self.headers.as_deref(),
137        };
138        let head = HeadWrite {
139            status_str: self.status.as_str().as_bytes(),
140            reason: self
141                .status
142                .canonical_reason()
143                .map(str::as_bytes)
144                .unwrap_or(b""),
145            headers: &section,
146            framing: ContentLength(&cl_raw[..cl_n]),
147        };
148        f(&head)
149    }
150
151    fn write_head_into(&self, out: &mut [u8], date: &[u8; 29]) -> Option<(usize, usize)> {
152        self.with_head(|head| {
153            if out.len() < head.wire_len() {
154                return None;
155            }
156            let mut off = 0usize;
157            let date_offset = head.write(out, &mut off, date);
158            Some((off, date_offset))
159        })
160    }
161}