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