turbopack_core/
data_uri_source.rs1use anyhow::{Result, bail};
2use turbo_rcstr::RcStr;
3use turbo_tasks::{ResolvedVc, Vc};
4use turbo_tasks_fs::{File, FileContent, FileSystemPath, rope::Rope};
5use turbo_tasks_hash::{encode_hex, hash_xxh3_hash64};
6
7use crate::{
8 asset::{Asset, AssetContent},
9 ident::AssetIdent,
10 source::Source,
11};
12
13#[turbo_tasks::value]
16pub struct DataUriSource {
17 media_type: RcStr,
18 encoding: RcStr,
19 data: ResolvedVc<RcStr>,
20 lookup_path: ResolvedVc<FileSystemPath>,
21}
22
23#[turbo_tasks::value_impl]
24impl DataUriSource {
25 #[turbo_tasks::function]
26 pub fn new(
27 media_type: RcStr,
28 encoding: RcStr,
29 data: ResolvedVc<RcStr>,
30 lookup_path: ResolvedVc<FileSystemPath>,
31 ) -> Vc<Self> {
32 Self::cell(DataUriSource {
33 media_type,
34 encoding,
35 data,
36 lookup_path,
37 })
38 }
39}
40
41#[turbo_tasks::value_impl]
42impl Source for DataUriSource {
43 #[turbo_tasks::function]
44 async fn ident(&self) -> Result<Vc<AssetIdent>> {
45 let content_type = self.media_type.split(";").next().unwrap().into();
46 let filename = format!(
47 "data:{}",
48 &encode_hex(hash_xxh3_hash64((
49 &*self.data.await?,
50 &self.media_type,
51 &self.encoding
52 )))[0..6]
53 );
54 Ok(
55 AssetIdent::from_path(self.lookup_path.join(filename.into()))
56 .with_content_type(content_type),
57 )
58 }
59}
60
61#[turbo_tasks::value_impl]
62impl Asset for DataUriSource {
63 #[turbo_tasks::function]
64 async fn content(&self) -> Result<Vc<AssetContent>> {
65 let data = self.data.await?;
66 let rope = if self.encoding == "base64" {
67 let decoded = data_encoding::BASE64.decode(data.as_bytes())?;
68 Rope::from(decoded)
70 } else if self.encoding.is_empty() {
71 let decoded = urlencoding::decode(data.as_str())?.into_owned();
72 Rope::from(decoded)
73 } else {
74 bail!("Unsupported data URL encoding: {}", self.encoding);
75 };
76 Ok(AssetContent::file(
77 FileContent::from(File::from(rope)).cell(),
78 ))
79 }
80}