sark_core/http/response/
fixed.rs1use http::StatusCode;
2use o3::buffer::{Owned, Shared};
3
4use super::wire_emit::{ContentLength, DATE_LEN, HeadWrite, NO_DATE, Out};
5use super::{HeadInner, HeadersInner, InlineHeaderValue};
6
7#[derive(Clone, Debug)]
8pub struct FixedResponseInner<'req> {
9 pub(super) status: StatusCode,
10 pub(super) head: HeadInner<'req>,
11 pub(super) body: Shared,
12 pub(super) body_len_ascii: InlineHeaderValue,
13}
14
15pub type FixedResponse = FixedResponseInner<'static>;
16
17impl<'req> FixedResponseInner<'req> {
18 pub fn direct<B>(
19 status: StatusCode,
20 static_headers: &'static [u8],
21 headers: HeadersInner<'req>,
22 body: B,
23 ) -> Self
24 where
25 B: Into<Shared>,
26 {
27 let body = body.into();
28 Self {
29 status,
30 head: HeadInner::new(static_headers, headers),
31 body_len_ascii: InlineHeaderValue::from_decimal(body.len()),
32 body,
33 }
34 }
35
36 pub fn status(&self) -> StatusCode {
37 self.status
38 }
39
40 pub fn body_ref(&self) -> &[u8] {
41 self.body.as_ref()
42 }
43
44 pub fn has_content_encoding(&self) -> bool {
45 self.head.headers().has_content_encoding()
46 }
47
48 pub fn wire_headers(&self) -> Shared {
49 let mut out = Owned::with_capacity(self.head.wire_len());
50 self.head.write_into(&mut out);
51 out.freeze()
52 }
53
54 pub fn write_preserialized(
55 out: &mut [u8],
56 template: &[u8],
57 date_offset: usize,
58 date: &[u8; 29],
59 ) -> Option<usize> {
60 let total = template.len();
61 if out.len() < total {
62 return None;
63 }
64 out[..total].copy_from_slice(template);
65 if date_offset != NO_DATE {
66 out[date_offset..date_offset + DATE_LEN].copy_from_slice(date);
67 }
68 Some(total)
69 }
70
71 pub fn preserialize(&self) -> (Vec<u8>, usize) {
72 let dummy_date: &[u8; 29] = b"Mon, 01 Jan 2000 00:00:00 GMT";
73 let mut buf = vec![0u8; 4096];
74 let n = self
75 .write_into_slice(&mut buf, dummy_date)
76 .expect("preserialize: 4096 must be enough for any response");
77 buf.truncate(n);
78 let date_offset = buf
79 .windows(29)
80 .position(|w| w == dummy_date)
81 .expect("preserialize: dummy date must appear in output");
82 (buf, date_offset)
83 }
84
85 pub fn write_into_slice(&self, out: &mut [u8], date: &[u8; 29]) -> Option<usize> {
86 let status_str = self.status.as_str().as_bytes();
87 let reason = self
88 .status
89 .canonical_reason()
90 .map(str::as_bytes)
91 .unwrap_or(b"");
92 let cl_body = self.body_len_ascii.as_bytes();
93 let body = self.body.as_ref();
94
95 let head = HeadWrite {
96 status_str,
97 reason,
98 headers: &self.head,
99 framing: ContentLength(cl_body),
100 };
101 let total = head.wire_len() + body.len();
102 if out.len() < total {
103 return None;
104 }
105
106 let mut off = 0usize;
107 head.write(out, &mut off, date);
108 Out::put(out, &mut off, body);
109 Some(off)
110 }
111
112 pub fn write_head_split(self, out: &mut [u8], date: &[u8; 29]) -> Option<(usize, Shared)> {
113 let status_str = self.status.as_str().as_bytes();
114 let reason = self
115 .status
116 .canonical_reason()
117 .map(str::as_bytes)
118 .unwrap_or(b"");
119 let cl_body = self.body_len_ascii.as_bytes();
120 let head = HeadWrite {
121 status_str,
122 reason,
123 headers: &self.head,
124 framing: ContentLength(cl_body),
125 };
126 if out.len() < head.wire_len() {
127 return None;
128 }
129 let mut off = 0usize;
130 head.write(out, &mut off, date);
131 Some((off, self.body))
132 }
133
134 pub fn apply_gzip(&mut self, compressed: Shared) {
135 const GZIP_EXTRA: &[u8] = b"Content-Encoding: gzip\r\nVary: Accept-Encoding\r\n";
136 self.body_len_ascii = InlineHeaderValue::from_decimal(compressed.len());
137 self.body = compressed;
138 self.head.set_extra_static(GZIP_EXTRA);
139 }
140}