ps-blitz-net 0.6.5

Blitz networking
Documentation
use blitz_traits::net::{Bytes, Initiator};
use blitz_traits::platform::{FetchError, FetchRequest, FetchResponse, HeaderMap, StatusCode};
use bytes::BytesMut;
use data_url::DataUrl;
use std::io::Read;

pub(crate) fn fetch(request: FetchRequest) -> Result<FetchResponse, FetchError> {
    request
        .initiator
        .check_url(&request.url)
        .map_err(FetchError::Blocked)?;
    let mut headers = HeaderMap::new();
    let body = match request.url.scheme() {
        "file" => {
            let path = request.url.to_file_path().map_err(|()| {
                FetchError::InvalidRequest(format!("not a local path: {}", request.url))
            })?;
            let mut file = std::fs::File::open(path)
                .map_err(|error| FetchError::Network(error.to_string()))?;
            read_file(&mut file, &request.initiator)?
        }
        "data" => {
            let data = DataUrl::process(request.url.as_str())
                .map_err(|error| FetchError::InvalidRequest(format!("{error:?}")))?;
            let mime = data.mime_type().to_string();
            let mut body = BytesMut::new();
            data.decode(|bytes| {
                request
                    .initiator
                    .charge(bytes.len())
                    .map_err(FetchError::Blocked)?;
                body.extend_from_slice(bytes);
                Ok::<(), FetchError>(())
            })
            .map_err(|error| match error {
                data_url::forgiving_base64::DecodeError::WriteError(error) => error,
                data_url::forgiving_base64::DecodeError::InvalidBase64(error) => {
                    FetchError::InvalidRequest(format!("{error:?}"))
                }
            })?;
            if let Ok(value) = mime.parse() {
                headers.insert("content-type", value);
            }
            body.freeze()
        }
        scheme => return Err(FetchError::UnsupportedScheme(scheme.into())),
    };
    Ok(FetchResponse::new(request.url, StatusCode::OK)
        .headers(headers)
        .body(body))
}

fn read_file(file: &mut std::fs::File, initiator: &Initiator) -> Result<Bytes, FetchError> {
    let mut body = BytesMut::new();
    loop {
        let capacity = initiator.remaining_bytes().clamp(1, 16 * 1024);
        let start = body.len();
        body.resize(start + capacity, 0);
        let read = file
            .read(&mut body[start..])
            .map_err(|error| FetchError::Network(error.to_string()))?;
        body.truncate(start + read);
        initiator.charge(read).map_err(FetchError::Blocked)?;
        if read == 0 {
            return Ok(body.freeze());
        }
    }
}