sark_core/http/response/
chunked.rs1use http::StatusCode;
2use o3::buffer::{Owned, Shared};
3
4use super::Response;
5use super::body::Body;
6use super::header::HeaderList;
7use super::wire_emit::{CRLF, HeadWrite, Out, 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: Owned::from(self.wire_headers.as_ref()),
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) -> 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 += hex_n + CRLF.len() + part.len() + CRLF.len();
58 }
59 len + Self::ZERO_CHUNK.len()
60 }
61
62 fn write_body(&self, dst: &mut [u8], off: &mut usize) {
63 for part in &self.parts {
64 if part.is_empty() {
65 continue;
66 }
67 let mut hex = [0u8; 16];
68 let hex_n = Wire::write_hex(part.len(), &mut hex);
69 Out::put(dst, off, &hex[..hex_n]);
70 Out::put(dst, off, CRLF);
71 Out::put(dst, off, part.as_ref());
72 Out::put(dst, off, CRLF);
73 }
74 Out::put(dst, off, Self::ZERO_CHUNK);
75 }
76
77 fn head(&self) -> HeadWrite<'_, [u8], TransferEncodingChunked> {
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.wire_headers.as_ref(),
86 framing: TransferEncodingChunked,
87 }
88 }
89
90 pub fn write_into_slice(&self, out: &mut [u8], date: &[u8; 29]) -> Option<usize> {
91 let head = self.head();
92 let total = head.wire_len() + self.body_wire_len();
93 if out.len() < total {
94 return None;
95 }
96
97 let mut off = 0usize;
98 head.write(out, &mut off, date);
99 self.write_body(out, &mut off);
100 Some(off)
101 }
102
103 pub fn write_head_split(self, out: &mut [u8], date: &[u8; 29]) -> Option<(usize, Shared)> {
104 let head = self.head();
105 if out.len() < head.wire_len() {
106 return None;
107 }
108 let mut off = 0usize;
109 head.write(out, &mut off, date);
110
111 let mut body = vec![0u8; self.body_wire_len()];
112 let mut boff = 0usize;
113 self.write_body(&mut body, &mut boff);
114 Some((off, Shared::copy_from_slice(&body)))
115 }
116}