Niceties for constructing headers
This commit is contained in:
parent
29a2fd3c7f
commit
9e2664ec36
|
|
@ -14,20 +14,21 @@ pub fn main() -> Result<(), Box<dyn Error>> {
|
|||
.and_then(|h| Some((h, args.next()?, args.next()?, args.next()?)))
|
||||
.ok_or_else(|| Box::<dyn Error>::from(String::from("Missing required argument")))?;
|
||||
|
||||
let mut stream = TcpStream::connect((host, port.parse()?))?;
|
||||
let mut stream = TcpStream::connect((host.as_str(), port.parse()?))?;
|
||||
|
||||
let buf = vec![0; 4096];
|
||||
let mut buf = uhttp_ext::Buf::new(buf);
|
||||
let mut conn = uhttp::Connection::new(uhttp::Role::Client);
|
||||
let events = &[
|
||||
uhttp::Event::RequestLine(uhttp::RequestLine {
|
||||
uhttp::RequestLine {
|
||||
version: uhttp::Version::HTTP1_1,
|
||||
method: "POST",
|
||||
target: &path,
|
||||
}),
|
||||
uhttp::Event::Header(uhttp::Header::Special(uhttp::HeaderSpecial::ContentLength(
|
||||
data.len(),
|
||||
))),
|
||||
}
|
||||
.into(),
|
||||
uhttp::HeaderOther::from(("Host", host.as_bytes())).into(),
|
||||
uhttp::HeaderOther::from(("Accept", "*/*")).into(),
|
||||
uhttp::HeaderSpecial::ContentLength(data.len()).into(),
|
||||
uhttp::Event::HeadersDone,
|
||||
uhttp::Event::BodyChunk(data.as_bytes()),
|
||||
uhttp::Event::SendDone,
|
||||
|
|
@ -42,7 +43,6 @@ pub fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
buf.clear();
|
||||
loop {
|
||||
buf.read_from(&mut stream)?;
|
||||
let data = buf.filled();
|
||||
let (d, r) = conn.handle_recv(data).lift();
|
||||
|
||||
|
|
@ -51,6 +51,7 @@ pub fn main() -> Result<(), Box<dyn Error>> {
|
|||
kind: uhttp::ErrorKind::NeedMoreData,
|
||||
..
|
||||
}) => {
|
||||
buf.read_from(&mut stream)?;
|
||||
continue;
|
||||
},
|
||||
Err(e) => panic!("{e:?}"),
|
||||
|
|
|
|||
31
src/lib.rs
31
src/lib.rs
|
|
@ -23,6 +23,37 @@ pub enum Event<'a> {
|
|||
StatusLine(StatusLine<'a>),
|
||||
SendDone,
|
||||
}
|
||||
|
||||
impl<'a> From<HeaderSpecial> for Event<'a> {
|
||||
fn from(value: HeaderSpecial) -> Self {
|
||||
Self::Header(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<HeaderOther<'a>> for Event<'a> {
|
||||
fn from(value: HeaderOther<'a>) -> Self {
|
||||
Self::Header(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Header<'a>> for Event<'a> {
|
||||
fn from(value: Header<'a>) -> Self {
|
||||
Self::Header(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<RequestLine<'a>> for Event<'a> {
|
||||
fn from(value: RequestLine<'a>) -> Self {
|
||||
Self::RequestLine(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<StatusLine<'a>> for Event<'a> {
|
||||
fn from(value: StatusLine<'a>) -> Self {
|
||||
Self::StatusLine(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> core::fmt::Display for Event<'a> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
|
|
|
|||
31
src/parse.rs
31
src/parse.rs
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
fail_details,
|
||||
parts::{RequestLine, Version},
|
||||
Error, ErrorKind, Header, HeaderOther, HeaderSpecial, StatusLine, Tup,
|
||||
Error, ErrorKind, Header, StatusLine, Tup,
|
||||
};
|
||||
|
||||
pub type Parse<'a, T> = Result<(&'a [u8], T), (&'a [u8], Error)>;
|
||||
|
|
@ -109,9 +109,7 @@ pub fn header(d: &[u8]) -> Parse<Header> {
|
|||
let (line, rest) = split_crlf(d).ok_or((d, ErrorKind::NeedMoreData.into()))?;
|
||||
|
||||
let go = || {
|
||||
let mut it = line
|
||||
.split(|b| b.is_ascii_whitespace())
|
||||
.filter(|bs| !bs.is_empty());
|
||||
let mut it = line.split(|b| *b == b':').filter(|bs| !bs.is_empty());
|
||||
|
||||
let (name, value) = match (it.next(), it.next()) {
|
||||
(Some(n), Some(v)) => (n, v),
|
||||
|
|
@ -127,30 +125,11 @@ pub fn header(d: &[u8]) -> Parse<Header> {
|
|||
Ok(m) => m,
|
||||
_ => return fail_details(ErrorKind::Parse, "expected target to be ascii"),
|
||||
};
|
||||
let name = name
|
||||
.split_once(":")
|
||||
.map(|(f, _)| f)
|
||||
.ok_or(Error::with_details(ErrorKind::Parse, "invalid header name"))?;
|
||||
let name = name.trim();
|
||||
|
||||
let h = match () {
|
||||
_ if name.eq_ignore_ascii_case("transfer-encoding")
|
||||
&& value.eq_ignore_ascii_case(b"chunked") =>
|
||||
{
|
||||
Header::Special(HeaderSpecial::TransferEncodingChunked)
|
||||
},
|
||||
_ if name.eq_ignore_ascii_case("content-length") => {
|
||||
match core::str::from_utf8(value)
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
{
|
||||
Some(v) => Header::Special(HeaderSpecial::ContentLength(v)),
|
||||
_ => Header::Other(HeaderOther { name, value }),
|
||||
}
|
||||
},
|
||||
_ => Header::Other(HeaderOther { name, value }),
|
||||
};
|
||||
let value = value.trim_ascii();
|
||||
|
||||
Ok(h)
|
||||
Ok(Header::from((name, value)))
|
||||
};
|
||||
|
||||
go().tup(rest)
|
||||
|
|
|
|||
56
src/parts.rs
56
src/parts.rs
|
|
@ -37,8 +37,64 @@ pub struct HeaderOther<'a> {
|
|||
pub value: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a, Name, Value> From<(&'a Name, &'a Value)> for HeaderOther<'a>
|
||||
where
|
||||
Name: AsRef<str> + ?Sized,
|
||||
Value: AsRef<[u8]> + ?Sized,
|
||||
{
|
||||
fn from(value: (&'a Name, &'a Value)) -> Self {
|
||||
let (name, value) = value;
|
||||
let name = name.as_ref();
|
||||
let value = value.as_ref();
|
||||
|
||||
Self { name, value }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub enum Header<'a> {
|
||||
Special(HeaderSpecial),
|
||||
Other(HeaderOther<'a>),
|
||||
}
|
||||
|
||||
impl<'a> From<HeaderSpecial> for Header<'a> {
|
||||
fn from(value: HeaderSpecial) -> Self {
|
||||
Self::Special(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<HeaderOther<'a>> for Header<'a> {
|
||||
fn from(value: HeaderOther<'a>) -> Self {
|
||||
Self::Other(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Name, Value> From<(&'a Name, &'a Value)> for Header<'a>
|
||||
where
|
||||
Name: AsRef<str> + ?Sized,
|
||||
Value: AsRef<[u8]> + ?Sized,
|
||||
{
|
||||
fn from(value: (&'a Name, &'a Value)) -> Self {
|
||||
let (name, value) = value;
|
||||
let name = name.as_ref();
|
||||
let value = value.as_ref();
|
||||
|
||||
match () {
|
||||
_ if name.eq_ignore_ascii_case("transfer-encoding")
|
||||
&& value.eq_ignore_ascii_case(b"chunked") =>
|
||||
{
|
||||
Header::Special(HeaderSpecial::TransferEncodingChunked)
|
||||
},
|
||||
_ if name.eq_ignore_ascii_case("content-length") => {
|
||||
match core::str::from_utf8(value)
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
{
|
||||
Some(v) => Header::Special(HeaderSpecial::ContentLength(v)),
|
||||
_ => Header::Other(HeaderOther { name, value }),
|
||||
}
|
||||
},
|
||||
_ => Header::Other(HeaderOther { name, value }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue