stream_httparse/
response.rs1use crate::{
2 header::{HeaderKey, HeaderValue},
3 Headers, StatusCode,
4};
5
6#[derive(Debug)]
7enum ProtocolData<'a> {
8 Ref(&'a str),
9 Owned(String),
10}
11
12impl<'a> AsRef<str> for ProtocolData<'a> {
13 fn as_ref(&self) -> &str {
14 match self {
15 Self::Ref(tmp) => tmp,
16 Self::Owned(tmp) => &tmp,
17 }
18 }
19}
20
21impl<'a> PartialEq for ProtocolData<'a> {
22 fn eq(&self, other: &ProtocolData<'_>) -> bool {
23 self.as_ref().eq(other.as_ref())
24 }
25}
26
27#[derive(Debug, PartialEq)]
29pub struct Response<'a> {
30 status_code: StatusCode,
31 protocol: ProtocolData<'a>,
32 headers: Headers<'a>,
33 body: Vec<u8>,
34}
35
36impl<'a> Response<'a> {
37 pub fn new(
40 protocol: &'a str,
41 status_code: StatusCode,
42 headers: Headers<'a>,
43 body: Vec<u8>,
44 ) -> Self {
45 Self {
46 status_code,
47 protocol: ProtocolData::Ref(protocol),
48 headers,
49 body,
50 }
51 }
52
53 pub(crate) fn new_owned(
56 protocol: String,
57 status_code: StatusCode,
58 headers: Headers<'a>,
59 body: Vec<u8>,
60 ) -> Self {
61 Self {
62 status_code,
63 protocol: ProtocolData::Owned(protocol),
64 headers,
65 body,
66 }
67 }
68
69 pub fn serialize(&self) -> (Vec<u8>, &[u8]) {
72 let protocol = self.protocol.as_ref();
73 let status_code = self.status_code.serialize();
74
75 let capacity = protocol.len() + 1 + status_code.len() + 4;
76 let mut result = Vec::with_capacity(capacity);
77
78 result.extend_from_slice(protocol.as_bytes());
80 result.push(b' ');
81 result.extend_from_slice(status_code.as_bytes());
82 result.extend_from_slice("\r\n".as_bytes());
83
84 self.headers.serialize(&mut result);
86
87 result.extend_from_slice("\r\n".as_bytes());
89
90 (result, &self.body)
91 }
92
93 pub fn protocol(&self) -> &str {
95 self.protocol.as_ref()
96 }
97 pub fn status_code(&self) -> &StatusCode {
99 &self.status_code
100 }
101 pub fn headers(&self) -> &Headers<'a> {
103 &self.headers
104 }
105 pub fn body(&self) -> &[u8] {
107 &self.body
108 }
109
110 pub fn add_header<'b, K, V>(&mut self, key: K, value: V)
114 where
115 'b: 'a,
116 K: Into<HeaderKey<'a>>,
117 V: Into<HeaderValue<'a>>,
118 {
119 self.headers.set(key, value);
120 }
121
122 pub fn set_body(&mut self, n_body: Vec<u8>) {
126 self.body = n_body;
127 self.add_header("Content-Length", self.body.len());
128 }
129
130 pub fn is_chunked(&self) -> bool {
133 match self.headers.get("Transfer-Encoding") {
134 None => false,
135 Some(value) => value.eq_ignore_case(&HeaderValue::StrRef("Chunked")),
136 }
137 }
138
139 pub fn to_owned<'refed, 'owned>(&'refed self) -> Response<'owned> {
142 Response::new_owned(
143 self.protocol.as_ref().to_owned(),
144 self.status_code.clone(),
145 self.headers.to_owned(),
146 self.body.clone(),
147 )
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn serialize_valid() {
157 let mut headers = Headers::new();
158 headers.set("test-1", "value-1");
159
160 let req = Response::new(
161 "HTTP/1.1",
162 StatusCode::OK,
163 headers,
164 "body".as_bytes().to_vec(),
165 );
166 let raw_resp_header = "HTTP/1.1 200 OK\r\ntest-1: value-1\r\n\r\n";
167 let resp_header = raw_resp_header.as_bytes().to_vec();
168 let resp_body = "body".as_bytes();
169
170 assert_eq!(req.serialize(), (resp_header, resp_body));
171 }
172
173 #[test]
174 fn serialize_valid_no_body() {
175 let mut headers = Headers::new();
176 headers.set("test-1", "value-1");
177
178 let req = Response::new("HTTP/1.1", StatusCode::OK, headers, "".as_bytes().to_vec());
179 let raw_resp_header = "HTTP/1.1 200 OK\r\ntest-1: value-1\r\n\r\n";
180 let resp_header = raw_resp_header.as_bytes().to_vec();
181 let resp_body = "".as_bytes();
182
183 assert_eq!(req.serialize(), (resp_header, resp_body));
184 }
185
186 #[test]
187 fn is_chunked_not_set() {
188 let mut headers = Headers::new();
189 headers.set("test-1", "value-1");
190
191 let resp = Response::new("HTTP/1.1", StatusCode::OK, headers, "".as_bytes().to_vec());
192
193 assert_eq!(false, resp.is_chunked());
194 }
195 #[test]
196 fn is_chunked_set() {
197 let mut headers = Headers::new();
198 headers.set("Transfer-Encoding", "Chunked");
199
200 let resp = Response::new("HTTP/1.1", StatusCode::OK, headers, "".as_bytes().to_vec());
201
202 assert_eq!(true, resp.is_chunked());
203 }
204 #[test]
205 fn is_chunked_set_differently() {
206 let mut headers = Headers::new();
207 headers.set("Transfer-Encoding", "compress");
208
209 let resp = Response::new("HTTP/1.1", StatusCode::OK, headers, "".as_bytes().to_vec());
210
211 assert_eq!(false, resp.is_chunked());
212 }
213
214 #[test]
215 fn to_owned() {
216 let resp = Response::new("HTTP/1.1", StatusCode::OK, Headers::new(), Vec::new());
217
218 let cloned = resp.to_owned();
219
220 drop(resp);
221
222 assert_eq!(&StatusCode::OK, cloned.status_code())
223 }
224}