irox_networking/http/
response.rs1use crate::http::headers::HttpHeaders;
6use crate::http::{HeaderResponse, HttpBody};
7use irox_tools::options::MaybeMap;
8use irox_tools::read::{ReadAny, ReadEmpty};
9use std::fmt::{Debug, Formatter};
10use std::io::{BufRead, BufReader, Error, Read, Write};
11use std::str::FromStr;
12
13pub struct HttpResponse {
14 pub(crate) version: String,
15 pub(crate) code: String,
16 pub(crate) status: String,
17 pub(crate) headers: HttpHeaders,
18 pub(crate) body: HttpBody,
19}
20
21impl HttpResponse {
22 pub fn create_from<T: Read + 'static>(input: T) -> Result<HttpResponse, Error> {
23 let mut bufread = BufReader::new(input);
24 let mut line = String::new();
25 let _read = bufread.read_line(&mut line)?;
26 let mut status = line.split(' ');
27 let version = status.next().unwrap_or_default().to_string();
28 let code = status.next().unwrap_or_default().to_string();
29 let status = status.collect::<Vec<&str>>().join(" ");
30
31 let HeaderResponse {
32 headers,
33 mut remaining,
34 } = HttpHeaders::create_from(bufread)?;
35
36 let content_length = headers
37 .get_header("Content-Length")
38 .maybe_map(|v| u64::from_str(v).ok())
39 .unwrap_or(0);
40 let body = if content_length == 0 {
41 HttpBody::Empty
42 } else if content_length < 1_000_000 {
43 let mut buf: Vec<u8> = Vec::with_capacity(1_000_000);
44 remaining.read_to_end(&mut buf)?;
45 HttpBody::Bytes(buf)
46 } else {
47 HttpBody::Read(Box::new(remaining))
48 };
49
50 Ok(HttpResponse {
51 version,
52 code,
53 status,
54 headers,
55 body,
56 })
57 }
58 pub fn body_read(self) -> Box<dyn Read> {
59 match self.body {
60 HttpBody::Read(r) => r,
61 HttpBody::Empty => Box::<ReadEmpty>::default(),
62 HttpBody::String(s) => Box::new(ReadAny::from(s)),
63 HttpBody::Bytes(b) => Box::new(ReadAny::from(b)),
64 }
65 }
66}
67
68impl Debug for HttpResponse {
69 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
70 let mut val: Vec<u8> = Vec::with_capacity(4096);
71 let _ = write!(val, "{} {} {}\r\n", self.version, self.code, self.status);
72 let _ = self.headers.write_to(&mut val);
73 match &self.body {
74 HttpBody::String(s) => {
75 let _ = write!(val, "{s}");
76 }
77 HttpBody::Bytes(b) => val.extend_from_slice(b),
78 _ => {}
79 }
80 write!(f, "{}", String::from_utf8_lossy(&val))?;
81 Ok(())
82 }
83}