1use crate::body::Body;
2#[cfg(feature = "cookie")]
3use crate::cookies;
4use crate::errors::{new_io_error, Error, Result};
5use crate::record::{HTTPRecord, RedirectRecord};
6#[cfg(feature = "tls")]
7use crate::tls::PeerCertificate;
8use crate::{Request, COLON_SPACE, CR_LF, SPACE};
9use bytes::Bytes;
10#[cfg(feature = "charset")]
11use encoding_rs::{Encoding, UTF_8};
12#[cfg(feature = "gzip")]
13use flate2::read::MultiGzDecoder;
14use http::{Method, Response as HttpResponse};
15#[cfg(feature = "charset")]
16use mime::Mime;
17#[cfg(feature = "gzip")]
18use std::io::Read;
19use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncReadExt, BufReader};
20use tokio::time::{timeout, Duration};
21
22#[derive(Debug, Default, Clone)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
26pub struct Response {
27 #[cfg_attr(feature = "serde", serde(with = "http_serde::version"))]
28 #[cfg_attr(
29 feature = "schema",
30 schemars(
31 with = "String",
32 title = "HTTP version",
33 description = "The protocol version used in the HTTP response",
34 example = "HTTP/1.1"
35 )
36 )]
37 pub version: http::Version,
39 #[cfg_attr(feature = "serde", serde(with = "http_serde::uri"))]
40 #[cfg_attr(
41 feature = "schema",
42 schemars(
43 with = "String",
44 title = "request URI",
45 description = "The original request URI that generated this response",
46 example = "https://example.com/api/v1/resource"
47 )
48 )]
49 pub uri: http::Uri,
51 #[cfg_attr(feature = "serde", serde(with = "http_serde::status_code"))]
52 #[cfg_attr(
53 feature = "schema",
54 schemars(
55 title = "status code",
56 description = "The HTTP status code indicating the response status",
57 example = 200,
58 schema_with = "crate::serde_schema::status_code_schema"
59 )
60 )]
61 pub status_code: http::StatusCode,
63 #[cfg_attr(feature = "serde", serde(with = "http_serde::header_map"))]
64 #[cfg_attr(
65 feature = "schema",
66 schemars(
67 with = "std::collections::HashMap<String,String>",
68 title = "response headers",
69 description = "Key-value pairs of HTTP headers included in the response",
70 example = r#"{"Content-Type": "application/json", "Cache-Control": "max-age=3600"}"#
71 )
72 )]
73 pub headers: http::HeaderMap<http::HeaderValue>,
75 #[cfg_attr(feature = "serde", serde(skip))]
76 pub extensions: http::Extensions,
78 #[cfg_attr(
79 feature = "schema",
80 schemars(
81 title = "response body",
82 description = "Optional body content received in the HTTP response",
83 example = r#"{"data": {"id": 123, "name": "example"}}"#,
84 )
85 )]
86 pub body: Option<Body>,
88}
89
90impl PartialEq for Response {
91 fn eq(&self, other: &Self) -> bool {
92 self.version == other.version
93 && self.status_code == other.status_code
94 && self.headers == other.headers
95 && self.body.eq(&self.body)
96 }
97}
98
99impl<T> From<HttpResponse<T>> for Response
100where
101 T: Into<Body>,
102{
103 fn from(value: HttpResponse<T>) -> Self {
104 let (parts, body) = value.into_parts();
105 let body = body.into();
106 Self {
107 version: parts.version,
108 uri: Default::default(),
109 status_code: parts.status,
110 headers: parts.headers,
111 extensions: parts.extensions,
112 body: if body.is_empty() { None } else { Some(body) },
113 }
114 }
115}
116
117impl Response {
118 pub(crate) fn to_raw(&self) -> Bytes {
119 let mut http_response = Vec::new();
120 http_response.extend(format!("{:?}", self.version).as_bytes());
121 http_response.extend(SPACE);
122 http_response.extend(format!("{}", self.status_code).as_bytes());
123 http_response.extend(CR_LF);
124 for (k, v) in self.headers.iter() {
125 http_response.extend(k.as_str().as_bytes());
126 http_response.extend(COLON_SPACE);
127 http_response.extend(v.as_bytes());
128 http_response.extend(CR_LF);
129 }
130 http_response.extend(CR_LF);
131 if let Some(b) = self.body() {
133 if !b.is_empty() {
134 http_response.extend(b.as_ref());
135 }
136 }
137 Bytes::from(http_response)
138 }
139 pub fn builder() -> http::response::Builder {
144 http::response::Builder::new()
145 }
146}
147
148impl Response {
149 #[cfg(feature = "cookie")]
157 #[cfg_attr(docsrs, doc(cfg(feature = "cookie")))]
158 pub fn cookies(&self) -> impl Iterator<Item = cookies::Cookie<'_>> {
159 cookies::extract_response_cookies(&self.headers).filter_map(|x| x.ok())
160 }
161
162 #[cfg(feature = "charset")]
164 pub fn text_with_charset(&self, default_encoding: &str) -> Result<String> {
165 let body = if let Some(b) = self.body() {
166 b
167 } else {
168 return Ok(String::new());
169 };
170 let content_type = self
171 .headers
172 .get(http::header::CONTENT_TYPE)
173 .and_then(|value| value.to_str().ok())
174 .and_then(|value| value.parse::<Mime>().ok());
175 let header_encoding = content_type
176 .as_ref()
177 .and_then(|mime| mime.get_param("charset").map(|charset| charset.as_str()))
178 .unwrap_or(default_encoding);
179 let mut decode_text = String::new();
180 for encoding_name in &[header_encoding, default_encoding] {
181 let encoding = Encoding::for_label(encoding_name.as_bytes()).unwrap_or(UTF_8);
182 let (text, _, is_errors) = encoding.decode(body);
183 if !is_errors {
184 decode_text = text.to_string();
185 break;
186 }
187 }
188 Ok(decode_text)
189 }
190 pub fn text(&self) -> Result<String> {
213 #[cfg(feature = "charset")]
214 {
215 let default_encoding = "utf-8";
216 self.text_with_charset(default_encoding)
217 }
218 #[cfg(not(feature = "charset"))]
219 Ok(String::from_utf8_lossy(&self.body().clone().unwrap_or_default()).to_string())
220 }
221 #[inline]
265 pub fn status_code(&self) -> http::StatusCode {
266 self.status_code
267 }
268 #[inline]
270 pub fn version(&self) -> http::Version {
271 self.version
272 }
273
274 #[inline]
297 pub fn headers(&self) -> &http::HeaderMap {
298 &self.headers
299 }
300 #[inline]
302 pub fn headers_mut(&mut self) -> &mut http::HeaderMap {
303 &mut self.headers
304 }
305 pub fn content_length(&self) -> Option<u64> {
313 self
314 .headers
315 .get(http::header::CONTENT_LENGTH)
316 .and_then(|x| x.to_str().ok()?.parse().ok())
317 }
318 #[inline]
330 pub fn uri(&self) -> &http::Uri {
331 &self.uri
332 }
333 #[inline]
334 pub(crate) fn url_mut(&mut self) -> &mut http::Uri {
335 &mut self.uri
336 }
337 pub fn body(&self) -> &Option<Body> {
350 &self.body
351 }
352 pub fn body_mut(&mut self) -> &mut Option<Body> {
354 &mut self.body
355 }
356 pub fn extensions(&self) -> &http::Extensions {
358 &self.extensions
359 }
360 pub fn extensions_mut(&mut self) -> &mut http::Extensions {
362 &mut self.extensions
363 }
364}
365
366impl Response {
368 #[cfg(feature = "tls")]
381 pub fn certificate(&self) -> Option<&Vec<PeerCertificate>> {
382 self.extensions().get::<Vec<PeerCertificate>>()
383 }
384 pub fn http_record(&self) -> Option<&Vec<HTTPRecord>> {
396 self.extensions().get::<Vec<HTTPRecord>>()
397 }
398 pub fn request(&self) -> Option<&Request> {
410 self.extensions().get::<Request>()
411 }
412 pub fn redirect_record(&self) -> Option<&RedirectRecord> {
424 self.extensions().get::<RedirectRecord>()
425 }
426}
427
428#[derive(Debug)]
432pub struct ResponseBuilder<T: AsyncRead + AsyncReadExt> {
433 builder: http::response::Builder,
434 reader: BufReader<T>,
435 config: ResponseConfig,
436}
437
438#[derive(Debug, Default)]
440pub struct ResponseConfig {
441 method: Method,
442 timeout: Option<Duration>,
443 unsafe_response: bool,
444 max_read: Option<u64>,
445}
446
447impl ResponseConfig {
448 pub fn new(request: &Request, timeout: Option<Duration>) -> Self {
450 let method = request.method().clone();
451 let unsafe_response = request.is_unsafe();
452 ResponseConfig {
453 method,
454 timeout,
455 unsafe_response,
456 max_read: None,
457 }
458 }
459}
460
461impl<T: AsyncRead + Unpin + Sized> ResponseBuilder<T> {
462 pub fn new(reader: BufReader<T>, config: ResponseConfig) -> ResponseBuilder<T> {
464 ResponseBuilder {
465 builder: Default::default(),
466 reader,
467 config,
468 }
469 }
470 async fn parser_version(&mut self) -> Result<(http::Version, http::StatusCode)> {
471 let (mut vf, mut sf) = (false, false);
472 let mut lines = Vec::new();
473 if let Ok(_length) = timeout(
474 self.config.timeout.unwrap_or(Duration::from_secs(30)),
475 self.reader.read_until(b'\n', &mut lines),
476 )
477 .await
478 .map_err(|e| Error::IO(std::io::Error::new(std::io::ErrorKind::TimedOut, e)))?
479 {
480 let mut version = http::Version::default();
481 let mut sc = http::StatusCode::default();
482 for (index, vc) in lines.splitn(3, |b| b == &b' ').enumerate() {
483 if vc.is_empty() {
484 return Err(new_io_error(
485 std::io::ErrorKind::InvalidData,
486 "invalid http version and status_code data",
487 ));
488 }
489 match index {
490 0 => {
491 version = match vc {
492 b"HTTP/0.9" => http::Version::HTTP_09,
493 b"HTTP/1.0" => http::Version::HTTP_10,
494 b"HTTP/1.1" => http::Version::HTTP_11,
495 b"HTTP/2.0" => http::Version::HTTP_2,
496 b"HTTP/3.0" => http::Version::HTTP_3,
497 _ => {
498 return Err(new_io_error(
499 std::io::ErrorKind::InvalidData,
500 "invalid http version",
501 ));
502 }
503 };
504 vf = true;
505 }
506 1 => {
507 sc = http::StatusCode::try_from(vc).map_err(|x| Error::Http(http::Error::from(x)))?;
508 sf = true;
509 }
510 _ => {}
511 }
512 }
513 if !(vf && sf) {
514 return Err(new_io_error(
515 std::io::ErrorKind::InvalidData,
516 "invalid http version and status_code data",
517 ));
518 }
519 Ok((version, sc))
520 } else {
521 Err(new_io_error(
522 std::io::ErrorKind::InvalidData,
523 "invalid http version and status_code data",
524 ))
525 }
526 }
527 async fn read_headers(&mut self) -> Result<http::HeaderMap> {
528 let mut headers = http::HeaderMap::new();
530 let mut header_line = Vec::new();
531 while let Ok(length) = timeout(
532 self.config.timeout.unwrap_or(Duration::from_secs(30)),
533 self.reader.read_until(b'\n', &mut header_line),
534 )
535 .await
536 .map_err(|e| Error::IO(std::io::Error::new(std::io::ErrorKind::TimedOut, e)))?
537 {
538 if length == 0 || header_line == b"\r\n" {
539 break;
540 }
541 if let Ok((Some(k), Some(v))) = parser_headers(&header_line) {
542 if headers.contains_key(&k) {
543 headers.append(k, v);
544 } else {
545 headers.insert(k, v);
546 }
547 };
548 header_line.clear();
549 }
550 Ok(headers)
551 }
552 async fn read_body(&mut self, header: &http::HeaderMap) -> Result<Vec<u8>> {
553 let mut body = Vec::new();
554 if matches!(self.config.method, Method::HEAD) {
555 return Ok(body);
556 }
557 let mut content_length: Option<u64> = header.get(http::header::CONTENT_LENGTH).and_then(|x| {
558 x.to_str()
559 .ok()?
560 .parse()
561 .ok()
562 .and_then(|l| if l == 0 { None } else { Some(l) })
563 });
564 if self.config.unsafe_response {
565 content_length = None;
566 }
567 if let Some(te) = header.get(http::header::TRANSFER_ENCODING) {
568 if te == "chunked" {
569 body = self.read_chunked_body().await?;
570 }
571 } else {
572 let limits = content_length.map(|x| {
573 if let Some(max) = self.config.max_read {
574 std::cmp::min(x, max)
575 } else {
576 x
577 }
578 });
579 let mut buffer = vec![0; 12]; let mut total_bytes_read = 0;
581 let timeout = self.config.timeout;
582 loop {
583 let size = if let Some(to) = timeout {
584 match tokio::time::timeout(to, self.reader.read(&mut buffer)).await {
585 Ok(size) => size,
586 Err(_) => break,
587 }
588 } else {
589 self.reader.read(&mut buffer).await
590 };
591 match size {
592 Ok(0) => break,
593 Ok(n) => {
594 body.extend_from_slice(&buffer[..n]);
595 total_bytes_read += n;
596 }
598 Err(ref err) if err.kind() == std::io::ErrorKind::WouldBlock => {
599 if total_bytes_read > 0 {
602 break;
603 }
604 }
605 Err(_err) => break,
606 }
607 if let Some(limit) = limits {
609 if total_bytes_read >= limit as usize {
610 break;
611 }
612 }
613 }
614 }
615 #[cfg(feature = "gzip")]
616 if let Some(ce) = header.get(http::header::CONTENT_ENCODING) {
617 if ce == "gzip" {
618 let mut gzip_body = Vec::new();
619 let mut d = MultiGzDecoder::new(&body[..]);
620 d.read_to_end(&mut gzip_body)?;
621 body = gzip_body;
622 }
623 }
624 Ok(body)
625 }
626
627 async fn read_chunked_body(&mut self) -> Result<Vec<u8>> {
628 let mut body: Vec<u8> = Vec::new();
629 loop {
630 let mut chunk: String = String::new();
631 loop {
632 let mut one_byte = vec![0; 1];
633 self.reader.read_exact(&mut one_byte).await?;
634 if one_byte[0] != 10 && one_byte[0] != 13 {
635 chunk.push(one_byte[0] as char);
636 break;
637 }
638 }
639 loop {
640 let mut one_byte = vec![0; 1];
641 self.reader.read_exact(&mut one_byte).await?;
642 if one_byte[0] == 10 || one_byte[0] == 13 {
643 self.reader.read_exact(&mut one_byte).await?;
644 break;
645 } else {
646 chunk.push(one_byte[0] as char)
647 }
648 }
649 if chunk == "0" || chunk.is_empty() {
650 break;
651 }
652 let chunk = usize::from_str_radix(&chunk, 16)?;
653 let mut chunk_of_bytes = vec![0; chunk];
654 self.reader.read_exact(&mut chunk_of_bytes).await?;
655 body.append(&mut chunk_of_bytes);
656 }
657 Ok(body)
658 }
659
660 pub async fn build(mut self) -> Result<(Response, T)> {
663 let (v, c) = self.parser_version().await?;
664 self.builder = self.builder.version(v).status(c);
665 let header = self.read_headers().await?;
666 let body = self.read_body(&header).await?;
668 if let Some(h) = self.builder.headers_mut() {
669 *h = header;
670 }
671 let resp = self.builder.body(body)?;
672 let response = resp.into();
673 let socket = self.reader.into_inner();
674 Ok((response, socket))
675 }
676}
677
678pub(crate) fn parser_headers(
679 buffer: &[u8],
680) -> Result<(Option<http::HeaderName>, Option<http::HeaderValue>)> {
681 let mut k = None;
682 let mut v = None;
683 let buffer = buffer.strip_suffix(CR_LF).unwrap_or(buffer);
684 for (index, h) in buffer.splitn(2, |s| s == &58).enumerate() {
685 let h = h.strip_prefix(SPACE).unwrap_or(h);
686 match index {
687 0 => match http::HeaderName::from_bytes(h) {
688 Ok(hk) => k = Some(hk),
689 Err(err) => {
690 return Err(Error::Http(http::Error::from(err)));
691 }
692 },
693 1 => match http::HeaderValue::from_bytes(h) {
694 Ok(hv) => v = Some(hv),
695 Err(err) => {
696 return Err(Error::Http(http::Error::from(err)));
697 }
698 },
699 _ => {}
700 }
701 }
702 Ok((k, v))
703}