Skip to content

Commit

Permalink
Merge pull request #40 from kbleeke/update-embedded-io
Browse files Browse the repository at this point in the history
(hacky) update embedded-io to 0.5
  • Loading branch information
Ulf Lilleengen committed Sep 30, 2023
2 parents c234dda + c49a502 commit 8872395
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 43 deletions.
20 changes: 14 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@ keywords = ["embedded", "async", "http", "no_std"]
exclude = [".github"]

[dependencies]
buffered-io = { version = "0.1.0", features = ["async"] }
embedded-io = { version = "0.4.0", features = ["async"] }
embedded-nal-async = "0.4.0"
buffered-io = { version = "0.3.0", features = ["async"] }
embedded-io = { version = "0.5.0" }
embedded-io-async = { version = "0.5.0" }
embedded-nal-async = "0.5.0"
httparse = { version = "1.8.0", default-features = false }
heapless = "0.7"
hex = { version = "0.4", default-features = false }
base64 = { version = "0.21.0", default-features = false }
rand_core = { version = "0.6", default-features = true }
log = { version = "0.4", optional = true }
defmt = { version = "0.3", optional = true }
embedded-tls = { version = "0.14", default-features = false, features = [
embedded-tls = { version = "0.15", default-features = false, features = [
"async",
], optional = true }
rand_chacha = { version = "0.3", default-features = false }
Expand All @@ -34,7 +35,8 @@ hyper = { version = "0.14.23", features = ["full"] }
tokio = { version = "1.21.2", features = ["full"] }
tokio-rustls = { version = "0.23.4" }
futures-util = { version = "0.3" }
embedded-io = { version = "0.4", features = ["async", "tokio"] }
embedded-io-async = { version = "0.5", features = ["std"] }
embedded-io-adapters = { version = "0.5", features = ["std", "tokio-1"] }
rustls-pemfile = "1.0"
env_logger = "0.10"
log = "0.4"
Expand All @@ -43,4 +45,10 @@ rand = "0.8"
[features]
default = ["embedded-tls"]
alloc = ["embedded-tls?/alloc"]
defmt = ["dep:defmt", "embedded-io/defmt", "embedded-tls?/defmt", "nourl/defmt"]
defmt = [
"dep:defmt",
"embedded-io/defmt-03",
"embedded-io-async/defmt-03",
"embedded-tls?/defmt",
"nourl/defmt",
]
92 changes: 86 additions & 6 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use crate::request::*;
use crate::response::*;
use crate::Error;
use buffered_io::asynch::BufferedWrite;
use embedded_io::asynch::{Read, Write};
use embedded_io::Error as _;
use embedded_io::ErrorType;
use embedded_io_async::{Read, Write};
use embedded_nal_async::{Dns, SocketAddr, TcpConnect};
use nourl::{Url, UrlScheme};

Expand Down Expand Up @@ -184,7 +185,7 @@ where
}
}

impl<T> embedded_io::Io for HttpConnection<'_, T>
impl<T> ErrorType for HttpConnection<'_, T>
where
T: Read + Write,
{
Expand Down Expand Up @@ -242,9 +243,12 @@ where
/// Turn the request into a buffered request
///
/// This is most likely only relevant for non-tls endpoints, as `embedded-tls` buffers internally.
pub fn into_buffered<'buf>(self, tx_buf: &'buf mut [u8]) -> HttpRequestHandle<'m, BufferedWrite<'buf, C>, B> {
pub fn into_buffered<'buf>(
self,
tx_buf: &'buf mut [u8],
) -> HttpRequestHandle<'m, BufferedWrite<'buf, buffered_io_adapter::ConnErrorAdapter<C>>, B> {
HttpRequestHandle {
conn: BufferedWrite::new(self.conn, tx_buf),
conn: BufferedWrite::new(buffered_io_adapter::ConnErrorAdapter(self.conn), tx_buf),
request: self.request,
}
}
Expand Down Expand Up @@ -324,9 +328,12 @@ where
/// Turn the resource into a buffered resource
///
/// This is most likely only relevant for non-tls endpoints, as `embedded-tls` buffers internally.
pub fn into_buffered<'buf>(self, tx_buf: &'buf mut [u8]) -> HttpResource<'res, BufferedWrite<'buf, C>> {
pub fn into_buffered<'buf>(
self,
tx_buf: &'buf mut [u8],
) -> HttpResource<'res, BufferedWrite<'buf, buffered_io_adapter::ConnErrorAdapter<C>>> {
HttpResource {
conn: BufferedWrite::new(self.conn, tx_buf),
conn: BufferedWrite::new(buffered_io_adapter::ConnErrorAdapter(self.conn), tx_buf),
host: self.host,
base_path: self.base_path,
}
Expand Down Expand Up @@ -478,3 +485,76 @@ where
self.request.build()
}
}

mod buffered_io_adapter {
use embedded_io::{Error as _, ErrorType, ReadExactError, WriteAllError};
use embedded_io_async::{Read, Write};

pub struct Error(embedded_io::ErrorKind);

impl core::fmt::Debug for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}

impl embedded_io_async::Error for Error {
fn kind(&self) -> embedded_io::ErrorKind {
self.0
}
}

impl<T> From<WriteAllError<T>> for Error
where
T: embedded_io::Error,
{
fn from(value: WriteAllError<T>) -> Self {
match value {
WriteAllError::WriteZero => Self(embedded_io::ErrorKind::Other),
WriteAllError::Other(e) => Self(e.kind()),
}
}
}

pub struct ConnErrorAdapter<C>(pub C);

impl<C> ErrorType for ConnErrorAdapter<C> {
type Error = Error;
}

impl<C> Write for ConnErrorAdapter<C>
where
C: Write,
{
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.0.write(buf).await.map_err(|e| Error(e.kind()))
}

async fn flush(&mut self) -> Result<(), Self::Error> {
self.0.flush().await.map_err(|e| Error(e.kind()))
}

async fn write_all(&mut self, buf: &[u8]) -> Result<(), embedded_io::WriteAllError<Self::Error>> {
self.0.write_all(buf).await.map_err(|e| match e {
WriteAllError::WriteZero => WriteAllError::WriteZero,
WriteAllError::Other(e) => WriteAllError::Other(Error(e.kind())),
})
}
}

impl<C> Read for ConnErrorAdapter<C>
where
C: Read,
{
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.0.read(buf).await.map_err(|e| Error(e.kind()))
}

async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError<Self::Error>> {
self.0.read_exact(buf).await.map_err(|e| match e {
ReadExactError::UnexpectedEof => ReadExactError::UnexpectedEof,
ReadExactError::Other(e) => ReadExactError::Other(Error(e.kind())),
})
}
}
}
5 changes: 3 additions & 2 deletions src/concat.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use embedded_io::{asynch::Read, ErrorKind, Io};
use embedded_io::{ErrorKind, ErrorType};
use embedded_io_async::Read;

pub struct ConcatReader<A, B>
where
Expand Down Expand Up @@ -59,7 +60,7 @@ where
}
}

impl<A, B> Io for ConcatReader<A, B>
impl<A, B> ErrorType for ConcatReader<A, B>
where
A: Read,
B: Read,
Expand Down
14 changes: 13 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#![doc = include_str!("../README.md")]
use core::{num::ParseIntError, str::Utf8Error};

use embedded_io::asynch::ReadExactError;
use embedded_io_async::{ReadExactError, WriteAllError};

mod fmt;

Expand Down Expand Up @@ -61,6 +61,18 @@ impl<E: embedded_io::Error> From<ReadExactError<E>> for Error {
}
}

impl<E> From<WriteAllError<E>> for Error
where
E: embedded_io::Error,
{
fn from(value: WriteAllError<E>) -> Self {
match value {
WriteAllError::WriteZero => Error::Network(embedded_io::ErrorKind::Other),
WriteAllError::Other(e) => Error::Network(e.kind()),
}
}
}

#[cfg(feature = "embedded-tls")]
impl From<embedded_tls::TlsError> for Error {
fn from(e: embedded_tls::TlsError) -> Error {
Expand Down
51 changes: 29 additions & 22 deletions src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use crate::headers::ContentType;
use crate::Error;
use core::fmt::Write as _;
use core::mem::size_of;
use embedded_io::asynch::Write;
use embedded_io::{Error as _, Io};
use embedded_io::{Error as _, ErrorType};
use embedded_io_async::{Write, WriteAllError};
use heapless::String;

/// A read only HTTP request type
Expand Down Expand Up @@ -169,7 +169,7 @@ where
Some(len) => {
trace!("Writing not-chunked body");
let mut writer = FixedBodyWriter(c, 0);
body.write(&mut writer).await.map_err(|e| e.kind())?;
body.write(&mut writer).await?;

if writer.1 != len {
return Err(Error::IncorrectBodyWritten);
Expand All @@ -178,7 +178,7 @@ where
None => {
trace!("Writing chunked body");
let mut writer = ChunkedBodyWriter(c, 0);
body.write(&mut writer).await.map_err(|e| e.kind())?;
body.write(&mut writer).await?;

write_str(c, "0\r\n\r\n").await?;
}
Expand Down Expand Up @@ -273,7 +273,7 @@ impl Method {
}

async fn write_str<C: Write>(c: &mut C, data: &str) -> Result<(), Error> {
c.write_all(data.as_bytes()).await.map_err(|e| e.kind())?;
c.write_all(data.as_bytes()).await?;
Ok(())
}

Expand All @@ -297,15 +297,15 @@ pub trait RequestBody {
}

/// Write the body to the provided writer
async fn write<W: Write>(&self, writer: &mut W) -> Result<(), W::Error>;
async fn write<W: Write>(&self, writer: &mut W) -> Result<(), WriteAllError<W::Error>>;
}

impl RequestBody for () {
fn len(&self) -> Option<usize> {
None
}

async fn write<W: Write>(&self, _writer: &mut W) -> Result<(), W::Error> {
async fn write<W: Write>(&self, _writer: &mut W) -> Result<(), WriteAllError<W::Error>> {
Ok(())
}
}
Expand All @@ -315,7 +315,7 @@ impl RequestBody for &[u8] {
Some(<[u8]>::len(self))
}

async fn write<W: Write>(&self, writer: &mut W) -> Result<(), W::Error> {
async fn write<W: Write>(&self, writer: &mut W) -> Result<(), WriteAllError<W::Error>> {
writer.write_all(self).await
}
}
Expand All @@ -328,7 +328,7 @@ where
self.as_ref().map(|inner| inner.len()).unwrap_or_default()
}

async fn write<W: Write>(&self, writer: &mut W) -> Result<(), W::Error> {
async fn write<W: Write>(&self, writer: &mut W) -> Result<(), WriteAllError<W::Error>> {
if let Some(inner) = self.as_ref() {
inner.write(writer).await
} else {
Expand All @@ -339,7 +339,7 @@ where

pub struct FixedBodyWriter<'a, C: Write>(&'a mut C, usize);

impl<C> Io for FixedBodyWriter<'_, C>
impl<C> ErrorType for FixedBodyWriter<'_, C>
where
C: Write,
{
Expand All @@ -356,7 +356,7 @@ where
Ok(written)
}

async fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
async fn write_all(&mut self, buf: &[u8]) -> Result<(), WriteAllError<Self::Error>> {
self.0.write_all(buf).await?;
self.1 += buf.len();
Ok(())
Expand All @@ -369,43 +369,50 @@ where

pub struct ChunkedBodyWriter<'a, C: Write>(&'a mut C, usize);

impl<C> Io for ChunkedBodyWriter<'_, C>
impl<C> ErrorType for ChunkedBodyWriter<'_, C>
where
C: Write,
{
type Error = C::Error;
type Error = embedded_io::ErrorKind;
}

fn to_errorkind<E: embedded_io::Error>(e: WriteAllError<E>) -> embedded_io::ErrorKind {
match e {
WriteAllError::WriteZero => embedded_io::ErrorKind::Other,
WriteAllError::Other(e) => e.kind(),
}
}

impl<C> Write for ChunkedBodyWriter<'_, C>
where
C: Write,
{
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_all(buf).await?;
self.write_all(buf).await.map_err(to_errorkind)?;
Ok(buf.len())
}

async fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
async fn write_all(&mut self, buf: &[u8]) -> Result<(), WriteAllError<Self::Error>> {
// Write chunk header
let len = buf.len();
let mut hex = [0; 2 * size_of::<usize>()];
hex::encode_to_slice(len.to_be_bytes(), &mut hex).unwrap();
let leading_zeros = hex.iter().position(|x| *x != b'0').unwrap_or_default();
let (_, hex) = hex.split_at(leading_zeros);
self.0.write_all(hex).await?;
self.0.write_all(b"\r\n").await?;
self.0.write_all(hex).await.map_err(to_errorkind)?;
self.0.write_all(b"\r\n").await.map_err(to_errorkind)?;

// Write chunk
self.0.write_all(buf).await?;
self.0.write_all(buf).await.map_err(to_errorkind)?;
self.1 += len;

// Write newline
self.0.write_all(b"\r\n").await?;
self.0.write_all(b"\r\n").await.map_err(to_errorkind)?;
Ok(())
}

async fn flush(&mut self) -> Result<(), Self::Error> {
self.0.flush().await
self.0.flush().await.map_err(|e| e.kind())
}
}

Expand All @@ -415,7 +422,7 @@ mod tests {

#[tokio::test]
async fn basic_auth() {
let mut buffer = Vec::new();
let mut buffer: Vec<u8> = Vec::new();
Request::new(Method::GET, "/")
.basic_auth("username", "password")
.build()
Expand Down Expand Up @@ -462,7 +469,7 @@ mod tests {
None // Unknown length: triggers chunked body
}

async fn write<W: Write>(&self, writer: &mut W) -> Result<(), W::Error> {
async fn write<W: Write>(&self, writer: &mut W) -> Result<(), WriteAllError<W::Error>> {
writer.write_all(self.0).await
}
}
Expand Down
Loading

0 comments on commit 8872395

Please sign in to comment.