diff --git a/Cargo.lock b/Cargo.lock index 4826a4edb8..a27cce7189 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -516,6 +516,7 @@ dependencies = [ "byteorder", "chrono", "clap", + "data-url", "deno_core", "deno_doc", "deno_lint", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index ea1c5b9637..909ec15370 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -43,6 +43,7 @@ atty = "0.2.14" base64 = "0.13.0" byteorder = "1.4.3" clap = "2.33.3" +data-url = "0.1.0" dissimilar = "1.0.2" dprint-plugin-json = "0.10.1" dprint-plugin-markdown = "0.6.2" diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index b5cc1c838d..471873195f 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -10,6 +10,7 @@ use crate::http_util::FetchOnceResult; use crate::media_type::MediaType; use crate::text_encoding; use crate::version::get_user_agent; +use data_url::DataUrl; use deno_core::error::custom_error; use deno_core::error::generic_error; use deno_core::error::uri_error; @@ -153,40 +154,6 @@ pub fn get_source_from_bytes( Ok(source) } -fn get_source_from_data_url( - specifier: &ModuleSpecifier, -) -> Result<(String, MediaType, String), AnyError> { - if specifier.scheme() != "data" { - return Err(custom_error( - "BadScheme", - format!("Unexpected scheme of \"{}\"", specifier.scheme()), - )); - } - let path = specifier.path(); - let mut parts = path.splitn(2, ','); - let media_type_part = - percent_encoding::percent_decode_str(parts.next().unwrap()) - .decode_utf8()?; - let data_part = if let Some(data) = parts.next() { - data - } else { - return Err(custom_error( - "BadUrl", - "The data URL is badly formed, missing a comma.", - )); - }; - let (media_type, maybe_charset) = - map_content_type(specifier, Some(media_type_part.to_string())); - let is_base64 = media_type_part.rsplit(';').any(|p| p == "base64"); - let bytes = if is_base64 { - base64::decode(data_part)? - } else { - percent_encoding::percent_decode_str(data_part).collect() - }; - let source = strip_shebang(get_source_from_bytes(bytes, maybe_charset)?); - Ok((source, media_type, media_type_part.to_string())) -} - /// Return a validated scheme for a given module specifier. fn get_validated_scheme( specifier: &ModuleSpecifier, @@ -430,8 +397,18 @@ impl FileFetcher { )); } - let (source, media_type, content_type) = - get_source_from_data_url(specifier)?; + let data_url = DataUrl::process(specifier.as_str()) + .map_err(|e| uri_error(format!("{:?}", e)))?; + let mime = data_url.mime_type(); + let charset = mime.get_parameter("charset").map(|v| v.to_string()); + let (bytes, _) = data_url + .decode_to_vec() + .map_err(|e| uri_error(format!("{:?}", e)))?; + let source = strip_shebang(get_source_from_bytes(bytes, charset)?); + let content_type = format!("{}", mime); + let (media_type, _) = + map_content_type(specifier, Some(content_type.clone())); + let local = self .http_cache @@ -762,39 +739,6 @@ mod tests { assert_eq!(file.source, expected); } - #[test] - fn test_get_source_from_data_url() { - let fixtures = vec![ - ("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=", true, MediaType::TypeScript, "application/typescript;base64", "export const a = \"a\";\n\nexport enum A {\n A,\n B,\n C,\n}\n"), - ("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=?a=b&b=c", true, MediaType::TypeScript, "application/typescript;base64", "export const a = \"a\";\n\nexport enum A {\n A,\n B,\n C,\n}\n"), - ("data:text/plain,Hello%2C%20Deno!", true, MediaType::Unknown, "text/plain", "Hello, Deno!"), - ("data:,Hello%2C%20Deno!", true, MediaType::Unknown, "", "Hello, Deno!"), - ("data:application/javascript,console.log(\"Hello, Deno!\");%0A", true, MediaType::JavaScript, "application/javascript", "console.log(\"Hello, Deno!\");\n"), - ("data:text/jsx;base64,ZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24oKSB7CiAgcmV0dXJuIDxkaXY+SGVsbG8gRGVubyE8L2Rpdj4KfQo=", true, MediaType::Jsx, "text/jsx;base64", "export default function() {\n return