Skip to main content

sark_core/http/response/
mono.rs

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