~demindiro/mhttp

c1094671de228ed6ec69d6832a874bf128576abb — David Hoppenbrouwers 1 year, 9 months ago bbfc09e
Add documentation
4 files changed, 32 insertions(+), 5 deletions(-)

M src/header.rs
M src/lib.rs
M src/request.rs
M src/response.rs
M src/header.rs => src/header.rs +11 -1
@@ 1,11 1,15 @@
use super::Exhausted;

/// Headers builder used by [`RequestBuilder`] and [`ResponseBuilder`].
pub(crate) struct HeadersBuilder<'a> {
	/// Buffer to write headers to.
	pub(crate) buffer: &'a mut [u8],
	/// The offset in the buffer to write additional headers to.
	pub(crate) index: usize,
}

impl<'a> HeadersBuilder<'a> {
	/// Add a single header.
	pub fn add_header(mut self, header: &str, value: &str) -> Result<Self, Exhausted> {
		let size = header.len() + 2 + value.len() + 2;
		if self.buffer.len() - self.index < size + 2 {


@@ 29,6 33,7 @@ impl<'a> HeadersBuilder<'a> {
		Ok(self)
	}

	/// Finish constructing the headers.
	#[inline]
	pub fn finish(self) -> (&'a [u8], &'a mut [u8]) {
		self.buffer[self.index..][..2].copy_from_slice(b"\r\n");


@@ 37,12 42,14 @@ impl<'a> HeadersBuilder<'a> {
	}
}

/// Headers parser used by [`RequestBuilder`] and [`ResponseBuilder`].
#[derive(Debug)]
pub(crate) struct HeadersParser<'a, 'b> {
	headers: &'b [&'a str],
}

impl<'a, 'b> HeadersParser<'a, 'b> {
	/// Parse a list of headers.
	pub fn parse(mut data: &'a [u8], storage: &'b mut [&'a str]) -> Result<(Self, &'a [u8]), InvalidHeader> {
		'l: for index in 0..storage.len() {
			if data.len() < 2 {


@@ 85,9 92,12 @@ impl<'a, 'b> HeadersParser<'a, 'b> {
	}
}

/// Errors that may occur during parsing.
pub enum InvalidHeader {
	/// Data is missing.
	Truncated,
	Exhausted,
	/// A header contains invalid UTF-8.
	InvalidUTF8,
	/// A header is missing a value.
	NoValue,
}

M src/lib.rs => src/lib.rs +1 -0
@@ 9,6 9,7 @@ use core::fmt;
pub use request::{Method, RequestBuilder, RequestParser, InvalidRequest};
pub use response::{Status, ResponseBuilder, ResponseParser, InvalidResponse};

/// An error that is returned if the buffer is too small.
pub struct Exhausted;

impl fmt::Debug for Exhausted {

M src/request.rs => src/request.rs +10 -2
@@ 1,5 1,6 @@
use super::{Exhausted, header::{HeadersBuilder, HeadersParser, InvalidHeader}};

/// All methods that may be used in requests.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Method {
	Get,


@@ 13,9 14,11 @@ pub enum Method {
	Patch,
}

/// Utility for creating HTTP requests.
pub struct RequestBuilder<'a>(HeadersBuilder<'a>);

impl<'a> RequestBuilder<'a> {
	/// Begin creating a new HTTP request.
	pub fn new(buffer: &'a mut [u8], path: &str, method: Method) -> Result<Self, Exhausted> {
		let s = match method {
			Method::Get => "GET",


@@ 52,17 55,21 @@ impl<'a> RequestBuilder<'a> {
		Ok(Self(HeadersBuilder { buffer, index: size }))
	}

	/// Append a single header.
	#[inline]
	pub fn add_header(self, header: &str, value: &str) -> Result<Self, Exhausted> {
		self.0.add_header(header, value).map(Self)
	}

	/// Construct the final request, returning the slice with the headers and the remainder
	/// of the buffer.
	#[inline]
	pub fn finish(self) -> (&'a [u8], &'a mut [u8]) {
		self.0.finish()
	}
}

/// Utility for parsing HTTP requests.
#[derive(Debug)]
pub struct RequestParser<'a, 'b> {
	pub method: Method,


@@ 71,6 78,7 @@ pub struct RequestParser<'a, 'b> {
}

impl<'a, 'b> RequestParser<'a, 'b> {
	/// Parse a HTTP request, returning the method, path, headers and any additional data if successful.
	pub fn parse(data: &'a [u8], storage: &'b mut [&'a str]) -> Result<(Self, &'a [u8]), InvalidRequest<'a>> {
		for (i, w) in data.windows(2).enumerate() {
			if w == b"\r\n" {


@@ 113,12 121,14 @@ impl<'a, 'b> RequestParser<'a, 'b> {
		Err(InvalidRequest::Truncated)
	}

	/// Get the value of the header with the given name.
	#[inline]
	pub fn header(&self, header: &str) -> Option<&'a str> {
		self.headers.get(header)
	}
}

/// Errors that may occur while parsing a request.
#[derive(Debug)]
pub enum InvalidRequest<'a> {
	InvalidMethod(&'a [u8]),


@@ 126,7 136,6 @@ pub enum InvalidRequest<'a> {
	UnsupportedVersion(&'a [u8]),
	TrailingGarbage(&'a [u8]),
	Truncated,
	Exhausted,
	InvalidUTF8,
	NoValue,
}


@@ 135,7 144,6 @@ impl From<InvalidHeader> for InvalidRequest<'_> {
	fn from(h: InvalidHeader) -> Self {
		match h {
			InvalidHeader::Truncated => Self::Truncated,
			InvalidHeader::Exhausted => Self::Exhausted,
			InvalidHeader::InvalidUTF8 => Self::InvalidUTF8,
			InvalidHeader::NoValue => Self::NoValue,
		}

M src/response.rs => src/response.rs +10 -2
@@ 1,5 1,6 @@
use super::{Exhausted, header::{HeadersBuilder, HeadersParser, InvalidHeader}};

/// All status codes that responses can return.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Status {
	// 1xx


@@ 72,9 73,11 @@ pub enum Status {
	NetworkAuthenticationRequired,
}

/// Utility for creating HTTP responses.
pub struct ResponseBuilder<'a>(HeadersBuilder<'a>);

impl<'a> ResponseBuilder<'a> {
	/// Create a new HTTP response by writing into the given buffer.
	pub fn new(buffer: &'a mut [u8], status: Status) -> Result<Self, Exhausted> {
		let s = match status {
			// 1xx


@@ 164,17 167,21 @@ impl<'a> ResponseBuilder<'a> {
		Ok(Self(HeadersBuilder { buffer, index: size }))
	}

	/// Append a single header.
	#[inline]
	pub fn add_header(self, header: &str, value: &str) -> Result<Self, Exhausted> {
		self.0.add_header(header, value).map(Self)
	}

	/// Finish constructing the HTTP response, returning the slice with the headers and
	/// the remaining buffer slice.
	#[inline]
	pub fn finish(self) -> (&'a [u8], &'a mut [u8]) {
		self.0.finish()
	}
}

/// Utility for parsing HTTP responses.
#[derive(Debug)]
pub struct ResponseParser<'a, 'b> {
	pub status: Status,


@@ 182,6 189,7 @@ pub struct ResponseParser<'a, 'b> {
}

impl<'a, 'b> ResponseParser<'a, 'b> {
	/// Parse a HTTP response, returning the status and any additional data if successful.
	pub fn parse(data: &'a [u8], storage: &'b mut [&'a str]) -> Result<(Self, &'a [u8]), InvalidResponse<'a>> {
		for (i, w) in data.windows(2).enumerate() {
			if w == b"\r\n" {


@@ 276,18 284,19 @@ impl<'a, 'b> ResponseParser<'a, 'b> {
		Err(InvalidResponse::Truncated)
	}

	/// Get the value of the header with the given name.
	#[inline]
	pub fn header(&self, header: &str) -> Option<&'a str> {
		self.headers.get(header)
	}
}

/// Errors that may occur while parsing a response.
#[derive(Debug)]
pub enum InvalidResponse<'a> {
	InvalidStatus(&'a [u8]),
	UnsupportedVersion(&'a [u8]),
	Truncated,
	Exhausted,
	InvalidUTF8,
	NoValue,
}


@@ 296,7 305,6 @@ impl From<InvalidHeader> for InvalidResponse<'_> {
	fn from(h: InvalidHeader) -> Self {
		match h {
			InvalidHeader::Truncated => Self::Truncated,
			InvalidHeader::Exhausted => Self::Exhausted,
			InvalidHeader::InvalidUTF8 => Self::InvalidUTF8,
			InvalidHeader::NoValue => Self::NoValue,
		}