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