summaryrefslogtreecommitdiff
path: root/cli/file_fetcher.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/file_fetcher.rs')
-rw-r--r--cli/file_fetcher.rs42
1 files changed, 41 insertions, 1 deletions
diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs
index 8b3ca46a0..f6400027a 100644
--- a/cli/file_fetcher.rs
+++ b/cli/file_fetcher.rs
@@ -100,7 +100,7 @@ impl SourceFileCache {
}
}
-const SUPPORTED_URL_SCHEMES: [&str; 3] = ["http", "https", "file"];
+const SUPPORTED_URL_SCHEMES: [&str; 4] = ["http", "https", "file", "data"];
#[derive(Clone)]
pub struct SourceFileFetcher {
@@ -278,6 +278,7 @@ impl SourceFileFetcher {
) -> Result<Option<SourceFile>, ErrBox> {
let url_scheme = module_url.scheme();
let is_local_file = url_scheme == "file";
+ let is_data_url = url_scheme == "data";
SourceFileFetcher::check_if_supported_scheme(&module_url)?;
// Local files are always fetched from disk bypassing cache entirely.
@@ -285,6 +286,10 @@ impl SourceFileFetcher {
return self.fetch_local_file(&module_url, permissions).map(Some);
}
+ if is_data_url {
+ return extract_data_url(module_url).map(Some);
+ }
+
self.fetch_cached_remote_source(&module_url, 10)
}
@@ -309,6 +314,7 @@ impl SourceFileFetcher {
) -> Result<SourceFile, ErrBox> {
let url_scheme = module_url.scheme();
let is_local_file = url_scheme == "file";
+ let is_data_url = url_scheme == "data";
SourceFileFetcher::check_if_supported_scheme(&module_url)?;
// Local files are always fetched from disk bypassing cache entirely.
@@ -316,6 +322,10 @@ impl SourceFileFetcher {
return self.fetch_local_file(&module_url, permissions);
}
+ if is_data_url {
+ return extract_data_url(module_url);
+ }
+
// The file is remote, fail if `no_remote` is true.
if no_remote {
let e = std::io::Error::new(
@@ -552,6 +562,36 @@ impl SourceFileFetcher {
}
}
+fn extract_data_url(url: &Url) -> Result<SourceFile, ErrBox> {
+ assert_eq!(url.scheme(), "data");
+ let url_content = &url.as_str()[5..];
+ let mut part_iterator = url_content.splitn(2, ',');
+
+ let media_type_str = part_iterator.next().unwrap();
+ let data = if let Some(d) = part_iterator.next() {
+ d
+ } else {
+ return Err(ErrBox::new("URIError", "Malformed data url, missing comma"));
+ };
+
+ let filename = PathBuf::new();
+ let (media_type, charset) = map_content_type(&filename, Some(media_type_str));
+ let is_base64 = media_type_str.rsplit(';').any(|v| v == "base64");
+ let bytes = if is_base64 {
+ base64::decode(data)?
+ } else {
+ percent_encoding::percent_decode_str(data).collect::<Vec<u8>>()
+ };
+
+ Ok(SourceFile {
+ url: url.clone(),
+ filename,
+ types_header: None,
+ media_type,
+ source_code: TextDocument::new(bytes, charset),
+ })
+}
+
pub fn map_file_extension(path: &Path) -> msg::MediaType {
match path.extension() {
None => msg::MediaType::Unknown,