nanofish 0.11.9

🐟 A lightweight, `no_std` HTTP client and server for embedded systems built on top of Embassy networking.
Documentation
/// Common HTTP header names as constants for convenience
pub mod headers {
    /// Content-Type header
    pub const CONTENT_TYPE: &str = "Content-Type";
    /// Authorization header
    pub const AUTHORIZATION: &str = "Authorization";
    /// User-Agent header
    pub const USER_AGENT: &str = "User-Agent";
    /// Accept header
    pub const ACCEPT: &str = "Accept";
    /// Content-Length header (usually auto-generated)
    pub const CONTENT_LENGTH: &str = "Content-Length";
    /// Cache-Control header
    pub const CACHE_CONTROL: &str = "Cache-Control";
    /// Host header (auto-generated by the client)
    pub const HOST: &str = "Host";
    /// Connection header
    pub const CONNECTION: &str = "Connection";
    /// X-API-Key header for API authentication
    pub const X_API_KEY: &str = "X-API-Key";
    /// Accept-Encoding header
    pub const ACCEPT_ENCODING: &str = "Accept-Encoding";
}

/// Common MIME types for Content-Type header values
pub mod mime_types {
    /// application/json
    pub const JSON: &str = "application/json";
    /// application/problem+json (RFC 7807 Problem Details)
    pub const PROBLEM_JSON: &str = "application/problem+json";
    /// application/xml
    pub const XML: &str = "application/xml";
    /// text/plain
    pub const TEXT: &str = "text/plain";
    /// text/html
    pub const HTML: &str = "text/html";
    /// application/x-www-form-urlencoded
    pub const FORM: &str = "application/x-www-form-urlencoded";
    /// application/octet-stream
    pub const BINARY: &str = "application/octet-stream";
    /// text/event-stream
    pub const EVENT_STREAM: &str = "text/event-stream";
}

/// HTTP Header struct for representing a single header with owned strings
///
/// This struct represents a single HTTP header with a name and value.
/// Headers are used to pass additional information about the request or response.
/// For `no_std` compatibility, we use `heapless::String` with fixed capacity.
#[derive(Clone, Debug)]
pub struct HttpHeader<'a> {
    /// The name of the header (e.g., "Content-Type", "Authorization")
    pub name: &'a str,
    /// The value of the header (e.g., "application/json", "Bearer token123")
    pub value: &'a str,
}

impl<'a> HttpHeader<'a> {
    /// Create a new HTTP header
    #[must_use]
    pub const fn new(name: &'a str, value: &'a str) -> Self {
        Self { name, value }
    }

    /// Create a Content-Type header
    #[must_use]
    pub const fn content_type(value: &'a str) -> Self {
        Self::new(headers::CONTENT_TYPE, value)
    }

    /// Create an Authorization header
    #[must_use]
    pub const fn authorization(value: &'a str) -> Self {
        Self::new(headers::AUTHORIZATION, value)
    }

    /// Create a User-Agent header
    #[must_use]
    pub const fn user_agent(value: &'a str) -> Self {
        Self::new(headers::USER_AGENT, value)
    }

    /// Create a Cache-Control header
    #[must_use]
    pub const fn cache_control(value: &'a str) -> Self {
        Self::new(headers::CACHE_CONTROL, value)
    }

    /// Create a Connection header
    #[must_use]
    pub const fn connection(value: &'a str) -> Self {
        Self::new(headers::CONNECTION, value)
    }

    /// Create an Accept header
    #[must_use]
    pub const fn accept(value: &'a str) -> Self {
        Self::new(headers::ACCEPT, value)
    }

    /// Create an X-API-Key header
    #[must_use]
    pub const fn api_key(value: &'a str) -> Self {
        Self::new(headers::X_API_KEY, value)
    }

    /// Create a Content-Type: text/event-stream header
    #[must_use]
    pub const fn event_stream() -> Self {
        Self::new(headers::CONTENT_TYPE, mime_types::EVENT_STREAM)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_http_header_creation() {
        let header = HttpHeader {
            name: "Content-Type",
            value: "application/json",
        };
        assert_eq!(header.name, "Content-Type");
        assert_eq!(header.value, "application/json");

        let cache = HttpHeader::cache_control("no-cache");
        assert_eq!(cache.name, headers::CACHE_CONTROL);
        assert_eq!(cache.value, "no-cache");

        let connection = HttpHeader::connection("keep-alive");
        assert_eq!(connection.name, headers::CONNECTION);
        assert_eq!(connection.value, "keep-alive");

        let event_stream = HttpHeader::event_stream();
        assert_eq!(event_stream.name, headers::CONTENT_TYPE);
        assert_eq!(event_stream.value, mime_types::EVENT_STREAM);
    }
}