http/
stream.rs

1use std::{
2    cmp::min,
3    io::{self, Read, Write},
4    net::TcpStream,
5    time::Duration,
6};
7
8#[derive(Debug)]
9struct StringStream(Vec<u8>, usize);
10
11impl Read for StringStream {
12    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
13        let n = self.peek(buf)?;
14        self.1 += n;
15        Ok(n)
16    }
17
18    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
19        const CHUNK_SIZE: usize = 1024;
20        let mut chunk: [u8; CHUNK_SIZE] = [0; CHUNK_SIZE];
21        let n = self.1;
22        while self.read(&mut chunk)? > 0 {
23            buf.write_all(&chunk)?;
24        }
25        Ok(self.1 - n)
26    }
27}
28
29impl StringStream {
30    fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
31        if buf.is_empty() || self.1 >= self.0.len() {
32            return Ok(0);
33        }
34        let src = &self.0[self.1..];
35        let n = min(buf.len(), src.len());
36        buf[..n].copy_from_slice(src);
37        Ok(n)
38    }
39}
40
41#[derive(Debug)]
42enum HttpStreamInner {
43    Tcp(TcpStream),
44    String(StringStream, Vec<u8>),
45    Dummy,
46}
47
48/// Holds a "stream" for a [`request`]
49/// This is an object where the http request can read and write to.
50///
51/// It can be build with a [`TcpStream`] or a [String]
52///
53/// It can also serve as a dummy object to build `HttpRequests`
54/// that are not parsed from any source
55///
56/// ```
57/// use http::*;
58/// use std::net::TcpStream;
59///
60/// fn from_str() -> HttpRequest {
61///     let stream = HttpStream::from("GET / HTTP/1.0");
62///     HttpRequest::parse(stream).unwrap()
63/// }
64/// fn from_tcp(tcp: TcpStream) -> HttpRequest {
65///     let stream = HttpStream::from(tcp);
66///     HttpRequest::parse(stream).unwrap()
67/// }
68/// fn dummy() -> HttpRequest {
69///     /* This HttpRequest holds a dummy HttpStream.
70///        All read/write operations are no-ops */
71///     HttpRequest::builder()
72///         .method(HttpMethod::GET)
73///         .url("/")
74///         .version(1.0)
75///         .build().unwrap()
76/// }
77/// ```
78///
79/// [`request`]: crate::HttpRequest
80#[derive(Debug)]
81pub struct HttpStream {
82    inner: HttpStreamInner,
83}
84
85impl HttpStream {
86    pub fn set_read_timeout(&self, d: Option<Duration>) -> io::Result<()> {
87        match &self.inner {
88            HttpStreamInner::Tcp(tcp_stream) => tcp_stream.set_read_timeout(d),
89            HttpStreamInner::Dummy | HttpStreamInner::String(..) => Ok(()),
90        }
91    }
92    pub fn peek(&self, buf: &mut [u8]) -> std::io::Result<usize> {
93        match &self.inner {
94            HttpStreamInner::Tcp(tcp_stream) => tcp_stream.peek(buf),
95            HttpStreamInner::Dummy => Ok(0),
96            HttpStreamInner::String(read, _) => read.peek(buf),
97        }
98    }
99    pub fn is_ready(&self) -> std::io::Result<bool> {
100        let mut buf = [0_u8; 1];
101        let n = match &self.inner {
102            HttpStreamInner::Tcp(tcp_stream) => tcp_stream.peek(&mut buf)?,
103            HttpStreamInner::String(string_stream, _) => string_stream.peek(&mut buf)?,
104            HttpStreamInner::Dummy => 0,
105        };
106        Ok(n > 0)
107    }
108}
109
110impl Read for HttpStream {
111    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
112        match &mut self.inner {
113            HttpStreamInner::Tcp(tcp_stream) => tcp_stream.read(buf),
114            HttpStreamInner::Dummy => Ok(0),
115            HttpStreamInner::String(buf_reader, _) => buf_reader.read(buf),
116        }
117    }
118}
119
120impl Write for HttpStream {
121    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
122        match &mut self.inner {
123            HttpStreamInner::Tcp(tcp_stream) => tcp_stream.write(buf),
124            HttpStreamInner::Dummy => Ok(0),
125            HttpStreamInner::String(_, w) => w.write(buf),
126        }
127    }
128
129    fn flush(&mut self) -> std::io::Result<()> {
130        match &mut self.inner {
131            HttpStreamInner::Tcp(tcp_stream) => tcp_stream.flush(),
132            HttpStreamInner::Dummy | HttpStreamInner::String(..) => Ok(()),
133        }
134    }
135}
136
137impl From<TcpStream> for HttpStream {
138    fn from(value: TcpStream) -> Self {
139        Self {
140            inner: HttpStreamInner::Tcp(value),
141        }
142    }
143}
144
145impl From<String> for HttpStream {
146    fn from(value: String) -> Self {
147        let src_vec = value.into_bytes();
148        let stream = StringStream(src_vec, 0);
149        Self {
150            inner: HttpStreamInner::String(stream, Vec::new()),
151        }
152    }
153}
154
155impl<'a> From<&'a str> for HttpStream {
156    fn from(value: &'a str) -> Self {
157        Self::from(value.to_string())
158    }
159}
160
161impl HttpStream {
162    #[must_use]
163    pub fn dummy() -> Self {
164        Self {
165            inner: HttpStreamInner::Dummy,
166        }
167    }
168}