1use super::{decode::decode_body, new_headers};
2use http_types::{
3 self,
4 headers::{self, HeaderName, HeaderValues, ToHeaderValues},
5 Mime, StatusCode, Version,
6};
7
8use http_types::{headers::CONTENT_TYPE, Headers};
9use serde::de::DeserializeOwned;
10
11use std::fmt;
12use std::ops::Index;
13
14#[derive(Clone, serde::Serialize, serde::Deserialize)]
16pub struct Response<Body> {
17 version: Option<http_types::Version>,
18 status: http_types::StatusCode,
19 #[serde(with = "header_serde")]
20 headers: Headers,
21 body: Option<Body>,
22}
23
24impl<Body> Response<Body> {
25 pub(crate) async fn new(mut res: super::ResponseAsync) -> crate::Result<Response<Vec<u8>>> {
27 let body = res.body_bytes().await?;
28 let status = res.status();
29
30 if status.is_client_error() || status.is_server_error() {
31 return Err(crate::HttpError::Http {
32 code: status,
33 message: status.to_string(),
34 body: Some(body),
35 });
36 }
37
38 let headers: &Headers = res.as_ref();
39 let headers = headers.clone();
40
41 Ok(Response {
42 status: res.status(),
43 headers,
44 version: res.version(),
45 body: Some(body),
46 })
47 }
48
49 pub fn status(&self) -> StatusCode {
58 self.status
59 }
60
61 pub fn version(&self) -> Option<Version> {
71 self.version
72 }
73
74 pub fn header(&self, name: impl Into<HeaderName>) -> Option<&HeaderValues> {
85 self.headers.get(name)
86 }
87
88 pub fn header_mut(&mut self, name: impl Into<HeaderName>) -> Option<&mut HeaderValues> {
90 self.headers.get_mut(name)
91 }
92
93 pub fn remove_header(&mut self, name: impl Into<HeaderName>) -> Option<HeaderValues> {
95 self.headers.remove(name)
96 }
97
98 pub fn insert_header(&mut self, key: impl Into<HeaderName>, value: impl ToHeaderValues) {
100 self.headers.insert(key, value);
101 }
102
103 pub fn append_header(&mut self, key: impl Into<HeaderName>, value: impl ToHeaderValues) {
105 self.headers.append(key, value);
106 }
107
108 #[must_use]
110 pub fn iter(&self) -> headers::Iter<'_> {
111 self.headers.iter()
112 }
113
114 #[must_use]
117 pub fn iter_mut(&mut self) -> headers::IterMut<'_> {
118 self.headers.iter_mut()
119 }
120
121 #[must_use]
123 pub fn header_names(&self) -> headers::Names<'_> {
124 self.headers.names()
125 }
126
127 #[must_use]
129 pub fn header_values(&self) -> headers::Values<'_> {
130 self.headers.values()
131 }
132
133 pub fn content_type(&self) -> Option<Mime> {
153 self.header(CONTENT_TYPE)?.last().as_str().parse().ok()
154 }
155
156 pub fn body(&self) -> Option<&Body> {
157 self.body.as_ref()
158 }
159
160 pub fn take_body(&mut self) -> Option<Body> {
161 self.body.take()
162 }
163
164 pub fn with_body<NewBody>(self, body: NewBody) -> Response<NewBody> {
165 Response {
166 body: Some(body),
167 headers: self.headers,
168 status: self.status,
169 version: self.version,
170 }
171 }
172}
173
174impl<'a, Body> IntoIterator for &'a Response<Body> {
175 type Item = (&'a headers::HeaderName, &'a headers::HeaderValues);
176 type IntoIter = headers::Iter<'a>;
177 fn into_iter(self) -> Self::IntoIter {
178 self.iter()
179 }
180}
181
182impl<'a, Body> IntoIterator for &'a mut Response<Body> {
183 type Item = (&'a headers::HeaderName, &'a mut headers::HeaderValues);
184 type IntoIter = headers::IterMut<'a>;
185 fn into_iter(self) -> Self::IntoIter {
186 self.iter_mut()
187 }
188}
189
190impl Response<Vec<u8>> {
191 pub(crate) fn new_with_status(status: http_types::StatusCode) -> Self {
192 let headers = new_headers();
193
194 Response {
195 status,
196 headers,
197 version: None,
198 body: None,
199 }
200 }
201
202 pub fn body_bytes(&mut self) -> crate::Result<Vec<u8>> {
224 self.body.take().ok_or_else(|| crate::HttpError::Http {
225 code: self.status(),
226 message: "Body had no bytes".to_string(),
227 body: None,
228 })
229 }
230
231 pub fn body_string(&mut self) -> crate::Result<String> {
265 let bytes = self.body_bytes()?;
266
267 let mime = self.content_type();
268 let claimed_encoding = mime
269 .as_ref()
270 .and_then(|mime| mime.param("charset"))
271 .map(std::string::ToString::to_string);
272 Ok(decode_body(bytes, claimed_encoding.as_deref())?)
273 }
274
275 pub fn body_json<T: DeserializeOwned>(&mut self) -> crate::Result<T> {
304 let body_bytes = self.body_bytes()?;
305 serde_json::from_slice(&body_bytes).map_err(crate::HttpError::from)
306 }
307}
308
309impl<Body> AsRef<http_types::Headers> for Response<Body> {
310 fn as_ref(&self) -> &http_types::Headers {
311 &self.headers
312 }
313}
314
315impl<Body> AsMut<http_types::Headers> for Response<Body> {
316 fn as_mut(&mut self) -> &mut http_types::Headers {
317 &mut self.headers
318 }
319}
320
321impl<Body> fmt::Debug for Response<Body> {
322 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
323 f.debug_struct("Response")
324 .field("version", &self.version)
325 .field("status", &self.status)
326 .field("headers", &self.headers)
327 .finish_non_exhaustive()
328 }
329}
330
331impl<Body> Index<HeaderName> for Response<Body> {
332 type Output = HeaderValues;
333
334 #[inline]
340 fn index(&self, name: HeaderName) -> &HeaderValues {
341 &self.headers[name]
342 }
343}
344
345impl<Body> Index<&str> for Response<Body> {
346 type Output = HeaderValues;
347
348 #[inline]
354 fn index(&self, name: &str) -> &HeaderValues {
355 &self.headers[name]
356 }
357}
358
359impl<Body> PartialEq for Response<Body>
360where
361 Body: PartialEq,
362{
363 fn eq(&self, other: &Self) -> bool {
364 self.version == other.version
365 && self.status == other.status
366 && self.headers.iter().zip(other.headers.iter()).all(
367 |((lhs_name, lhs_values), (rhs_name, rhs_values))| {
368 lhs_name == rhs_name
369 && lhs_values
370 .iter()
371 .zip(rhs_values.iter())
372 .all(|(lhs, rhs)| lhs == rhs)
373 },
374 )
375 && self.body == other.body
376 }
377}
378
379impl<Body> Eq for Response<Body> where Body: Eq {}
380
381#[cfg(feature = "http-compat")]
382impl<Body> TryInto<http::Response<Body>> for Response<Body> {
383 type Error = ();
384
385 fn try_into(self) -> Result<http::Response<Body>, Self::Error> {
386 let mut response = http::Response::new(self.body.ok_or(())?);
387
388 if let Some(version) = self.version {
389 let version = match version {
390 Version::Http0_9 => Some(http::Version::HTTP_09),
391 Version::Http1_0 => Some(http::Version::HTTP_10),
392 Version::Http1_1 => Some(http::Version::HTTP_11),
393 Version::Http2_0 => Some(http::Version::HTTP_2),
394 Version::Http3_0 => Some(http::Version::HTTP_3),
395 _ => None,
396 };
397
398 if let Some(version) = version {
399 *response.version_mut() = version;
400 }
401 }
402
403 let mut headers = self.headers;
404 headers_to_hyperium_headers(&mut headers, response.headers_mut());
405
406 Ok(response)
407 }
408}
409
410#[cfg(feature = "http-compat")]
411fn headers_to_hyperium_headers(headers: &mut Headers, hyperium_headers: &mut http::HeaderMap) {
412 for (name, values) in headers {
413 let name = format!("{name}").into_bytes();
414 let name = http::header::HeaderName::from_bytes(&name).unwrap();
415
416 for value in values.iter() {
417 let value = format!("{value}").into_bytes();
418 let value = http::header::HeaderValue::from_bytes(&value).unwrap();
419 hyperium_headers.append(&name, value);
420 }
421 }
422}
423
424mod header_serde {
425 use crate::{http::Headers, response::new_headers};
426 use http_types::headers::{HeaderName, HeaderValue};
427 use serde::{de::Error, Deserializer, Serializer};
428
429 pub fn serialize<S>(headers: &Headers, serializer: S) -> Result<S::Ok, S::Error>
430 where
431 S: Serializer,
432 {
433 serializer.collect_map(headers.iter().map(|(name, values)| {
434 (
435 name.as_str(),
436 values.iter().map(HeaderValue::as_str).collect::<Vec<_>>(),
437 )
438 }))
439 }
440
441 pub fn deserialize<'de, D>(deserializer: D) -> Result<Headers, D::Error>
442 where
443 D: Deserializer<'de>,
444 {
445 let strs = <Vec<(String, Vec<String>)> as serde::Deserialize>::deserialize(deserializer)?;
446
447 let mut headers = new_headers();
448
449 for (name, values) in strs {
450 let name = HeaderName::from_string(name).map_err(D::Error::custom)?;
451 for value in values {
452 headers.append(&name, value);
453 }
454 }
455
456 Ok(headers)
457 }
458}