sark_core/http/response/
fixed.rs1use http::StatusCode;
2use o3::buffer::{Owned, Shared};
3
4use super::wire_emit::{
5 ContentLength, DATE_LEN, HeadWrite, HeaderSection, PLACEHOLDER_DATE, WireWriter,
6};
7use super::{DEFAULT_HEADER_CAPACITY, HeadInner, Headers};
8
9const GZIP_HEADERS: &[u8] = b"Content-Encoding: gzip\r\nVary: Accept-Encoding\r\n";
10
11struct GzipHeaders<'a, 'req, const N: usize>(&'a HeadInner<'req, N>);
12
13impl<const N: usize> HeaderSection for GzipHeaders<'_, '_, N> {
14 fn header_len(&self) -> usize {
15 self.0.wire_len() + GZIP_HEADERS.len()
16 }
17
18 fn write_headers(&self, out: &mut WireWriter<'_>) {
19 self.0.write_headers(out);
20 out.put(GZIP_HEADERS);
21 }
22}
23
24#[derive(Clone, Debug)]
25pub struct FixedResponse<'req, const N: usize = DEFAULT_HEADER_CAPACITY> {
26 pub(super) status: StatusCode,
27 pub(super) head: HeadInner<'req, N>,
28 pub(super) body: Shared,
29}
30
31impl<'req, const N: usize> FixedResponse<'req, N> {
32 pub fn direct<B>(
33 status: StatusCode,
34 static_headers: &'static [u8],
35 headers: Headers<'req, N>,
36 body: B,
37 ) -> Self
38 where
39 B: Into<Shared>,
40 {
41 let body = body.into();
42 Self {
43 status,
44 head: HeadInner::new(static_headers, headers),
45 body,
46 }
47 }
48
49 pub fn status(&self) -> StatusCode {
50 self.status
51 }
52
53 pub fn body_ref(&self) -> &[u8] {
54 self.body.as_ref()
55 }
56
57 pub fn has_content_encoding(&self) -> bool {
58 self.head.headers().has_content_encoding()
59 }
60
61 pub fn wire_headers(&self) -> Shared {
62 let mut out = Owned::with_capacity(self.head.wire_len());
63 self.head.write_into_owned(&mut out);
64 out.freeze()
65 }
66
67 fn head_write(&self) -> (HeadWrite<'_, HeadInner<'req, N>, ContentLength>, &[u8]) {
68 (
69 self.head_write_with_len(self.body.len()),
70 self.body.as_ref(),
71 )
72 }
73
74 fn head_write_with_len(
75 &self,
76 body_len: usize,
77 ) -> HeadWrite<'_, HeadInner<'req, N>, ContentLength> {
78 HeadWrite {
79 status_str: self.status.as_str().as_bytes(),
80 reason: self
81 .status
82 .canonical_reason()
83 .map(str::as_bytes)
84 .unwrap_or(b""),
85 headers: &self.head,
86 framing: ContentLength(body_len),
87 }
88 }
89
90 pub fn preserialize(&self) -> (Vec<u8>, usize) {
91 let (head, body) = self.head_write();
92 let mut buf = vec![0u8; head.wire_len() + body.len()];
93 let written = head.write(&mut buf, PLACEHOLDER_DATE);
94 WireWriter::at(&mut buf, written.len).put(body);
95 (buf, written.date_offset)
96 }
97
98 pub fn write_into_slice(&self, out: &mut [u8], date: &[u8; 29]) -> Option<usize> {
99 let (head, body) = self.head_write();
100 if out.len() < head.wire_len() + body.len() {
101 return None;
102 }
103 let written = head.write(out, date);
104 let mut out = WireWriter::at(out, written.len);
105 out.put(body);
106 Some(out.len())
107 }
108
109 pub fn write_head_split(self, out: &mut [u8], date: &[u8; 29]) -> Option<(usize, Shared)> {
110 let (head, _) = self.head_write();
111 if out.len() < head.wire_len() {
112 return None;
113 }
114 let written = head.write(out, date);
115 Some((written.len, self.body))
116 }
117
118 pub fn write_gzip_head(
119 self,
120 out: &mut [u8],
121 date: &[u8; 29],
122 body_len: usize,
123 ) -> Option<usize> {
124 let headers = GzipHeaders(&self.head);
125 let head = HeadWrite {
126 status_str: self.status.as_str().as_bytes(),
127 reason: self
128 .status
129 .canonical_reason()
130 .map(str::as_bytes)
131 .unwrap_or(b""),
132 headers: &headers,
133 framing: ContentLength(body_len),
134 };
135 if out.len() < head.wire_len() {
136 return None;
137 }
138 Some(head.write(out, date).len)
139 }
140}
141
142impl FixedResponse<'static> {
143 pub fn write_preserialized(
144 out: &mut [u8],
145 template: &[u8],
146 date_offset: Option<usize>,
147 date: &[u8; 29],
148 ) -> Option<usize> {
149 let total = template.len();
150 if out.len() < total {
151 return None;
152 }
153 out[..total].copy_from_slice(template);
154 if let Some(off) = date_offset {
155 out[off..off + DATE_LEN].copy_from_slice(date);
156 }
157 Some(total)
158 }
159}