diff options
author | Valentin Anger <syrupthinker@gryphno.de> | 2020-09-11 22:40:48 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-11 22:40:48 +0200 |
commit | e3319f34a6ece36eab3138eae83c8d0e18fcc07c (patch) | |
tree | c194f400d91d11b9a29416e1697d00d8cf2e3628 /cli/file_fetcher.rs | |
parent | a3282aa9ed749f2e80618c6e2f25047d9a2bb2d8 (diff) |
feat(unstable): Support data: urls (#5157)
Diffstat (limited to 'cli/file_fetcher.rs')
-rw-r--r-- | cli/file_fetcher.rs | 42 |
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, |