4个版本 (2个重大更改)

0.2.1 2024年2月1日
0.2.0 2024年2月1日
0.1.0 2024年1月27日
0.0.0 2023年11月22日

1572嵌入式开发 中排名

Download history 1/week @ 2024-04-21 9/week @ 2024-05-19 1/week @ 2024-05-26 8/week @ 2024-06-02 2/week @ 2024-06-09 2/week @ 2024-06-16 17/week @ 2024-06-23 1/week @ 2024-06-30 15/week @ 2024-07-07 14/week @ 2024-07-14 14/week @ 2024-07-21 54/week @ 2024-07-28 50/week @ 2024-08-04

每月下载量 134
用于 edge-net

MIT/Apache

99KB
2.5K SLoC

edge-http

CI crates.io Documentation

异步 + no_std + 无分配的HTTP协议实现。

该实现基于出色的 httparse 库。

关于其他协议,请参阅 edge-net 聚合crate的文档。

下一步计划

进一步优化生成的future的内存消耗

  • 特别是,edge_http::io:::server::Server::run future - 目前默认的4个处理程序和请求中64个头的大小权重为 ~ 6 - 9KB
  • 此外,这还不包括 edge_http::io:::server::Server 运作所需的内存缓冲区 - 虽然已经优化,但还需要另外 2048 * 4 ~ 8KB(但这当然是正常且应接受的)

与各种Rust开放问题相关的相关材料

示例

HTTP客户端

use embedded_io_async::Read;
use embedded_nal_async::{AddrType, Dns, SocketAddr, TcpConnect};

use edge_http::io::{client::Connection, Error};
use edge_http::Method;

use log::*;

fn main() {
    env_logger::init_from_env(
        env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
    );

    let stack: edge_std_nal_async::Stack = Default::default();

    let mut buf = [0_u8; 8192];

    futures_lite::future::block_on(read(&stack, &mut buf)).unwrap();
}

async fn read<T: TcpConnect + Dns>(
    stack: &T,
    buf: &mut [u8],
) -> Result<(), Error<<T as TcpConnect>::Error>>
where
    <T as Dns>::Error: Into<<T as TcpConnect>::Error>,
{
    info!("About to open an HTTP connection to httpbin.org port 80");

    let ip = stack
        .get_host_by_name("httpbin.org", AddrType::IPv4)
        .await
        .map_err(|e| Error::Io(e.into()))?;

    let mut conn: Connection<_> = Connection::new(buf, stack, SocketAddr::new(ip, 80));

    for uri in ["/ip", "/headers"] {
        request(&mut conn, uri).await?;
    }

    Ok(())
}

async fn request<'b, const N: usize, T: TcpConnect>(
    conn: &mut Connection<'b, T, N>,
    uri: &str,
) -> Result<(), Error<T::Error>> {
    conn.initiate_request(true, Method::Get, uri, &[("Host", "httpbin.org")])
        .await?;

    conn.initiate_response().await?;

    let mut result = Vec::new();

    let mut buf = [0_u8; 1024];

    loop {
        let len = conn.read(&mut buf).await?;

        if len > 0 {
            result.extend_from_slice(&buf[0..len]);
        } else {
            break;
        }
    }

    info!(
        "Request to httpbin.org, URI \"{}\" returned:\nBody:\n=================\n{}\n=================\n\n\n\n",
        uri,
        core::str::from_utf8(&result).unwrap());

    Ok(())
}

HTTP服务器

use edge_http::io::server::{Connection, DefaultServer, Handler};
use edge_http::Method;

use embedded_nal_async_xtra::TcpListen;

use embedded_io_async::{Read, Write};

use log::info;

fn main() {
    env_logger::init_from_env(
        env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
    );

    let mut server = DefaultServer::new();

    futures_lite::future::block_on(run(&mut server)).unwrap();
}

pub async fn run(server: &mut DefaultServer) -> Result<(), anyhow::Error> {
    let addr = "0.0.0.0:8881";

    info!("Running HTTP server on {addr}");

    let acceptor = edge_std_nal_async::Stack::new()
        .listen(addr.parse().unwrap())
        .await?;

    server.run(acceptor, HttpHandler, None).await?;

    Ok(())
}

struct HttpHandler;

impl<'b, T, const N: usize> Handler<'b, T, N> for HttpHandler
where
    T: Read + Write,
    T::Error: Send + Sync + std::error::Error + 'static,
{
    type Error = anyhow::Error;

    async fn handle(&self, conn: &mut Connection<'b, T, N>) -> Result<(), Self::Error> {
        let headers = conn.headers()?;

        if !matches!(headers.method, Some(Method::Get)) {
            conn.initiate_response(405, Some("Method Not Allowed"), &[])
                .await?;
        } else if !matches!(headers.path, Some("/")) {
            conn.initiate_response(404, Some("Not Found"), &[]).await?;
        } else {
            conn.initiate_response(200, Some("OK"), &[("Content-Type", "text/plain")])
                .await?;

            conn.write_all(b"Hello world!").await?;
        }

        Ok(())
    }
}

依赖项

~1–1.6MB
~31K SLoC