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}