summaryrefslogtreecommitdiff
path: root/src/client.rs
diff options
context:
space:
mode:
authorJohn Turner <jturner.usa@gmail.com>2026-03-04 20:53:24 -0500
committerJohn Turner <jturner.usa@gmail.com>2026-03-04 20:53:32 -0500
commit4a16841789604614bc495c36972236749e5f35b0 (patch)
treeff7383c17f5d265967a1db083884fec78062e53f /src/client.rs
parent3c4208abd325d317c7524ba0dc3b701edfa9ebf8 (diff)
downloadhttpd-4a16841789604614bc495c36972236749e5f35b0.tar.gz
roll our own http types
Diffstat (limited to 'src/client.rs')
-rw-r--r--src/client.rs95
1 files changed, 23 insertions, 72 deletions
diff --git a/src/client.rs b/src/client.rs
index c5c8e18..f5ed2f9 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,88 +1,39 @@
-use httparse::EMPTY_HEADER;
+use tokio::io::{self, AsyncBufRead, AsyncWrite, AsyncWriteExt};
-use tokio::io::{self, AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt};
-
-use crate::{request::Request, response::Response};
-
-#[derive(Debug, thiserror::Error)]
-pub enum Error {
- #[error("unsupported version")]
- Version,
-
- #[error("io error: {0}")]
- Io(#[from] io::Error),
-
- #[error("invalid method: {0}")]
- Method(#[from] http::method::InvalidMethod),
-
- #[error("http error: {0}")]
- Http(#[from] http::Error),
-
- #[error("http parse error: {0}")]
- Parse(#[from] httparse::Error),
-}
+use crate::{
+ request::{self, Request},
+ response::Response,
+};
+#[derive(Debug)]
pub struct Client<R, W> {
reader: R,
writer: W,
+ buf: Vec<u8>,
+ line: Vec<u8>,
}
-impl<R, W> Client<R, W>
-where
- R: AsyncBufRead + Unpin,
- W: AsyncWrite + Unpin,
-{
+impl<R, W> Client<R, W> {
pub fn new(reader: R, writer: W) -> Self {
- Self { reader, writer }
+ Self {
+ reader,
+ writer,
+ buf: Vec::new(),
+ line: Vec::new(),
+ }
}
+}
- pub async fn send_response(&mut self, response: Response) -> io::Result<()> {
- response.to_wire(&mut self.writer).await?;
-
- self.writer.flush().await?;
-
- Ok(())
+impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> Client<R, W> {
+ pub async fn read_request(&mut self) -> Result<Option<Request>, request::Error> {
+ Request::parse(&mut self.reader, &mut self.buf, &mut self.line).await
}
- pub async fn read_request(&mut self) -> Result<Option<Request<Vec<u8>>>, Error> {
- let mut buf = Vec::new();
- let mut line = Vec::new();
+ pub async fn send_response(&mut self, response: Response) -> Result<(), io::Error> {
+ response.serialize(&mut self.writer).await?;
- loop {
- line.clear();
-
- if self.reader.read_until(b'\n', &mut line).await? == 0 {
- return Ok(None);
- }
-
- if line == b"\r\n" || line.is_empty() {
- break;
- }
-
- buf.extend_from_slice(&line);
- buf.extend_from_slice(b"\r\n");
- }
-
- let mut headers = [EMPTY_HEADER; 64];
- let mut parsed = httparse::Request::new(&mut headers);
-
- parsed.parse(&buf)?;
-
- let mut builder = http::Request::builder();
-
- builder = builder.method(http::Method::from_bytes(parsed.method.unwrap().as_bytes())?);
- builder = builder.uri(parsed.path.unwrap());
- builder = builder.version(match parsed.version.unwrap() {
- 1 => http::Version::HTTP_11,
- _ => return Err(Error::Version),
- });
-
- for header in parsed.headers {
- builder = builder.header(header.name, header.value);
- }
-
- let body: Vec<u8> = Vec::new();
+ self.writer.flush().await?;
- Ok(Some(Request::new(builder.body(body)?)))
+ Ok(())
}
}