wasmtime-wasi-http-plus 0.0.2

An enhanced implementation of wasmtime-wasi-http
Documentation
use {
    ::http::*,
    kutil::{std::error::*, tls::*},
    read_url::*,
    rustls::client::*,
    std::result::Result,
    tokio_rustls::*,
};

const ROOT_CERTIFICATES_HEADER: &str = "xx-root-certificates";
const CERTIFICATES_HEADER: &str = "xx-certificates";
const PRIVATE_KEY_HEADER: &str = "xx-private-key";

/// Create TLS client configuration.
///
/// Uses (and removes) the following custom headers, which are all URLs to X.509 certificates
/// encoded as PEM (Privacy-Enhanced Mail):
///
/// * XX-Root-Certificates
/// * XX-Certificates
/// * XX-Private-Key
pub fn tls_client_configuration(
    headers: &mut HeaderMap<HeaderValue>,
    url_context: &UrlContextRef,
) -> Result<ClientConfig, String> {
    let root_certificates = {
        match read_url_from_header(headers, ROOT_CERTIFICATES_HEADER, &url_context)? {
            Some(certificates) => Some(parse_certificates_pem(&certificates).into_string()?),
            None => None,
        }
    };

    let builder = ClientConfig::builder().with_standard_verifier(root_certificates).into_string()?;

    if let Some(certificates) = read_url_from_header(headers, CERTIFICATES_HEADER, &url_context)?
        && let Some(private_key) = read_url_from_header(headers, PRIVATE_KEY_HEADER, &url_context)?
    {
        let certificates = parse_certificates_pem(&certificates).into_string()?;
        let private_key = parse_private_key_pem(&private_key).into_string()?;
        return builder.with_client_auth_cert(certificates, private_key).into_string();
    }

    Ok(builder.with_no_client_auth())
}

fn read_url_from_header(
    headers: &mut HeaderMap<HeaderValue>,
    header_name: &str,
    url_context: &UrlContextRef,
) -> Result<Option<Vec<u8>>, String> {
    let Some(url) = headers.remove(header_name) else {
        return Ok(None);
    };

    let url = url.to_str().into_string()?;
    let url = url_context.url(url).into_string()?;
    let mut reader = url.open().into_string()?;
    let mut bytes = Vec::default();
    reader.read_to_end(&mut bytes).into_string()?;
    Ok(Some(bytes))
}