sark_core/http/response/
chunked.rs1use http::StatusCode;
2use o3::buffer::Shared;
3
4use super::Response;
5use super::body::Body;
6use super::header::HeaderList;
7use super::wire_emit::{CRLF, HeadWrite, ProvenWireWriter, TransferEncodingChunked};
8use crate::http::codec::Wire;
9
10#[derive(Clone, Debug)]
11pub struct Chunked {
12 status: StatusCode,
13 headers: HeaderList,
14 wire_headers: Shared,
15 parts: Vec<Shared>,
16}
17
18impl Chunked {
19 pub fn status(&self) -> StatusCode {
20 self.status
21 }
22
23 pub fn into_response(self) -> Response {
24 Response {
25 status: self.status,
26 headers: self.headers,
27 wire_headers: self.wire_headers.as_ref().to_vec(),
28 body: Body::empty(),
29 chunked_parts: Some(self.parts),
30 }
31 }
32
33 pub(super) fn from_parts(
34 status: StatusCode,
35 headers: HeaderList,
36 wire_headers: Shared,
37 parts: Vec<Shared>,
38 ) -> Self {
39 Self {
40 status,
41 headers,
42 wire_headers,
43 parts,
44 }
45 }
46
47 const ZERO_CHUNK: &'static [u8] = b"0\r\n\r\n";
48
49 fn body_wire_len(&self) -> Option<usize> {
50 let mut len = 0usize;
51 for part in &self.parts {
52 if part.is_empty() {
53 continue;
54 }
55 let mut hex = [0u8; 16];
56 let hex_n = Wire::write_hex(part.len(), &mut hex);
57 len = len
58 .checked_add(hex_n)?
59 .checked_add(CRLF.len())?
60 .checked_add(part.len())?
61 .checked_add(CRLF.len())?;
62 }
63 len.checked_add(Self::ZERO_CHUNK.len())
64 }
65
66 fn write_body(&self, out: &mut ProvenWireWriter<'_>) {
67 for part in &self.parts {
68 if part.is_empty() {
69 continue;
70 }
71 let mut hex = [0u8; 16];
72 let hex_n = Wire::write_hex(part.len(), &mut hex);
73 out.put(&hex[..hex_n]);
74 out.put(CRLF);
75 out.put(part.as_ref());
76 out.put(CRLF);
77 }
78 out.put(Self::ZERO_CHUNK);
79 }
80
81 fn head(&self) -> HeadWrite<'_, [u8], TransferEncodingChunked> {
82 HeadWrite {
83 status: self.status,
84 headers: self.wire_headers.as_ref(),
85 framing: TransferEncodingChunked,
86 }
87 }
88
89 pub fn write_into_slice(&self, out: &mut [u8], date: &[u8; 29]) -> Option<usize> {
90 let head = self.head();
91 let total = head.wire_len().checked_add(self.body_wire_len()?)?;
92 let mut out = ProvenWireWriter::new(out, total)?;
93 head.emit(&mut out, date);
94 self.write_body(&mut out);
95 Some(out.finish(total))
96 }
97
98 pub fn write_head_split(self, out: &mut [u8], date: &[u8; 29]) -> Option<(usize, Shared)> {
99 let head = self.head();
100 let head_len = head.wire_len();
101 let body_len = self.body_wire_len()?;
102 let mut out = ProvenWireWriter::new(out, head_len)?;
103 head.emit(&mut out, date);
104 let written = out.finish(head_len);
105
106 let mut body = vec![0u8; body_len];
107 let mut out = ProvenWireWriter::exact(&mut body);
108 self.write_body(&mut out);
109 out.finish(body_len);
110 Some((written, Shared::from(body)))
111 }
112}