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: §ion,
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}