goods_dataurl/
lib.rs

1use {
2    futures_core::future::BoxFuture,
3    goods::{AssetNotFound, AutoLocalSource, Source},
4    std::future::ready,
5};
6
7/// Quasi-source that decodes data directly from URL with `data:` scheme.
8#[derive(Debug)]
9pub struct DataUrlSource;
10
11impl AutoLocalSource for DataUrlSource {}
12
13impl<U> Source<U> for DataUrlSource
14where
15    U: AsRef<str>,
16{
17    fn read(&self, url: &U) -> BoxFuture<'static, eyre::Result<Box<[u8]>>> {
18        let url = url.as_ref();
19
20        let result = if !url.starts_with("data:") {
21            #[cfg(feature = "trace")]
22            tracing::trace!("Not a data URL");
23            Err(AssetNotFound.into())
24        } else if let Some(comma) = url["data:".len()..].find(',') {
25            let data = &url["data:".len() + comma + 1..];
26            match base64::decode_config(data, base64::URL_SAFE.decode_allow_trailing_bits(true)) {
27                Ok(bytes) => Ok(bytes.into_boxed_slice()),
28                Err(err) => {
29                    #[cfg(feature = "trace")]
30                    tracing::warn!("failed to decode bese64 payload in data URL");
31                    Err(err.into())
32                }
33            }
34        } else {
35            #[cfg(feature = "trace")]
36            tracing::warn!("missing comma in data URL");
37            Err(AssetNotFound.into())
38        };
39
40        Box::pin(ready(result))
41    }
42}