feat(unstable): Support data: urls (#5157)

This commit is contained in:
Valentin Anger 2020-09-11 22:40:48 +02:00 committed by GitHub
parent a3282aa9ed
commit e3319f34a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 170 additions and 10 deletions

View file

@ -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,