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 Response<Vec<u8>> {
175 pub(crate) fn new_with_status(status: http_types::StatusCode) -> Self {
176 let headers = new_headers();
177
178 Response {
179 status,
180 headers,
181 version: None,
182 body: None,
183 }
184 }
185
186 pub fn body_bytes(&mut self) -> crate::Result<Vec<u8>> {
208 self.body.take().ok_or_else(|| crate::HttpError::Http {
209 code: self.status(),
210 message: "Body had no bytes".to_string(),
211 body: None,
212 })
213 }
214
215 pub fn body_string(&mut self) -> crate::Result<String> {
249 let bytes = self.body_bytes()?;
250
251 let mime = self.content_type();
252 let claimed_encoding = mime
253 .as_ref()
254 .and_then(|mime| mime.param("charset"))
255 .map(|name| name.to_string());
256 Ok(decode_body(bytes, claimed_encoding.as_deref())?)
257 }
258
259 pub fn body_json<T: DeserializeOwned>(&mut self) -> crate::Result<T> {
288 let body_bytes = self.body_bytes()?;
289 serde_json::from_slice(&body_bytes).map_err(crate::HttpError::from)
290 }
291}
292
293impl<Body> AsRef<http_types::Headers> for Response<Body> {
294 fn as_ref(&self) -> &http_types::Headers {
295 &self.headers
296 }
297}
298
299impl<Body> AsMut<http_types::Headers> for Response<Body> {
300 fn as_mut(&mut self) -> &mut http_types::Headers {
301 &mut self.headers
302 }
303}
304
305impl<Body> fmt::Debug for Response<Body> {
306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307 f.debug_struct("Response")
308 .field("version", &self.version)
309 .field("status", &self.status)
310 .field("headers", &self.headers)
311 .finish_non_exhaustive()
312 }
313}
314
315impl<Body> Index<HeaderName> for Response<Body> {
316 type Output = HeaderValues;
317
318 #[inline]
324 fn index(&self, name: HeaderName) -> &HeaderValues {
325 &self.headers[name]
326 }
327}
328
329impl<Body> Index<&str> for Response<Body> {
330 type Output = HeaderValues;
331
332 #[inline]
338 fn index(&self, name: &str) -> &HeaderValues {
339 &self.headers[name]
340 }
341}
342
343impl<Body> PartialEq for Response<Body>
344where
345 Body: PartialEq,
346{
347 fn eq(&self, other: &Self) -> bool {
348 self.version == other.version
349 && self.status == other.status
350 && self.headers.iter().zip(other.headers.iter()).all(
351 |((lhs_name, lhs_values), (rhs_name, rhs_values))| {
352 lhs_name == rhs_name
353 && lhs_values
354 .iter()
355 .zip(rhs_values.iter())
356 .all(|(lhs, rhs)| lhs == rhs)
357 },
358 )
359 && self.body == other.body
360 }
361}
362
363impl<Body> Eq for Response<Body> where Body: Eq {}
364
365#[cfg(feature = "http-compat")]
366impl<Body> TryInto<http::Response<Body>> for Response<Body> {
367 type Error = ();
368
369 fn try_into(self) -> Result<http::Response<Body>, Self::Error> {
370 let mut response = http::Response::new(self.body.ok_or(())?);
371
372 if let Some(version) = self.version {
373 let version = match version {
374 Version::Http0_9 => Some(http::Version::HTTP_09),
375 Version::Http1_0 => Some(http::Version::HTTP_10),
376 Version::Http1_1 => Some(http::Version::HTTP_11),
377 Version::Http2_0 => Some(http::Version::HTTP_2),
378 Version::Http3_0 => Some(http::Version::HTTP_3),
379 _ => None,
380 };
381
382 if let Some(version) = version {
383 *response.version_mut() = version;
384 }
385 }
386
387 let mut headers = self.headers;
388 headers_to_hyperium_headers(&mut headers, response.headers_mut());
389
390 Ok(response)
391 }
392}
393
394#[cfg(feature = "http-compat")]
395fn headers_to_hyperium_headers(headers: &mut Headers, hyperium_headers: &mut http::HeaderMap) {
396 for (name, values) in headers {
397 let name = format!("{}", name).into_bytes();
398 let name = http::header::HeaderName::from_bytes(&name).unwrap();
399
400 for value in values.iter() {
401 let value = format!("{}", value).into_bytes();
402 let value = http::header::HeaderValue::from_bytes(&value).unwrap();
403 hyperium_headers.append(&name, value);
404 }
405 }
406}
407
408mod header_serde {
409 use crate::{http::Headers, response::new_headers};
410 use http_types::headers::HeaderName;
411 use serde::{de::Error, Deserializer, Serializer};
412
413 pub fn serialize<S>(headers: &Headers, serializer: S) -> Result<S::Ok, S::Error>
414 where
415 S: Serializer,
416 {
417 serializer.collect_map(headers.iter().map(|(name, values)| {
418 (
419 name.as_str(),
420 values.iter().map(|v| v.as_str()).collect::<Vec<_>>(),
421 )
422 }))
423 }
424
425 pub fn deserialize<'de, D>(deserializer: D) -> Result<Headers, D::Error>
426 where
427 D: Deserializer<'de>,
428 {
429 let strs = <Vec<(String, Vec<String>)> as serde::Deserialize>::deserialize(deserializer)?;
430
431 let mut headers = new_headers();
432
433 for (name, values) in strs {
434 let name = HeaderName::from_string(name).map_err(D::Error::custom)?;
435 for value in values {
436 headers.append(&name, value);
437 }
438 }
439
440 Ok(headers)
441 }
442}