diff options
Diffstat (limited to 'cli/file_fetcher.rs')
-rw-r--r-- | cli/file_fetcher.rs | 132 |
1 files changed, 127 insertions, 5 deletions
diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index 1c97d7018..0c1d9519d 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -18,9 +18,11 @@ use deno_core::futures; use deno_core::futures::future::FutureExt; use deno_core::ModuleSpecifier; use deno_runtime::deno_fetch::reqwest; +use deno_runtime::deno_file::BlobUrlStore; use deno_runtime::permissions::Permissions; use log::debug; use log::info; +use std::borrow::Borrow; use std::collections::HashMap; use std::env; use std::fs; @@ -32,7 +34,8 @@ use std::sync::Arc; use std::sync::Mutex; static DENO_AUTH_TOKENS: &str = "DENO_AUTH_TOKENS"; -pub const SUPPORTED_SCHEMES: [&str; 4] = ["data", "file", "http", "https"]; +pub const SUPPORTED_SCHEMES: [&str; 5] = + ["data", "blob", "file", "http", "https"]; /// A structure representing a source file. #[derive(Debug, Clone, Eq, PartialEq)] @@ -317,6 +320,7 @@ pub struct FileFetcher { cache_setting: CacheSetting, http_cache: HttpCache, http_client: reqwest::Client, + blob_url_store: BlobUrlStore, } impl FileFetcher { @@ -325,6 +329,7 @@ impl FileFetcher { cache_setting: CacheSetting, allow_remote: bool, ca_data: Option<Vec<u8>>, + blob_url_store: BlobUrlStore, ) -> Result<Self, AnyError> { Ok(Self { auth_tokens: AuthTokens::new(env::var(DENO_AUTH_TOKENS).ok()), @@ -333,6 +338,7 @@ impl FileFetcher { cache_setting, http_cache, http_client: create_http_client(get_user_agent(), ca_data)?, + blob_url_store, }) } @@ -446,6 +452,62 @@ impl FileFetcher { }) } + /// Get a blob URL. + fn fetch_blob_url( + &self, + specifier: &ModuleSpecifier, + ) -> Result<File, AnyError> { + debug!("FileFetcher::fetch_blob_url() - specifier: {}", specifier); + match self.fetch_cached(specifier, 0) { + Ok(Some(file)) => return Ok(file), + Ok(None) => {} + Err(err) => return Err(err), + } + + if self.cache_setting == CacheSetting::Only { + return Err(custom_error( + "NotFound", + format!( + "Specifier not found in cache: \"{}\", --cached-only is specified.", + specifier + ), + )); + } + + let blob_url_storage = self.blob_url_store.borrow(); + let blob = blob_url_storage.get(specifier)?.ok_or_else(|| { + custom_error( + "NotFound", + format!("Blob URL not found: \"{}\".", specifier), + ) + })?; + + let content_type = blob.media_type; + + let (media_type, maybe_charset) = + map_content_type(specifier, Some(content_type.clone())); + let source = + strip_shebang(get_source_from_bytes(blob.data, maybe_charset)?); + + let local = + self + .http_cache + .get_cache_filename(specifier) + .ok_or_else(|| { + generic_error("Cannot convert specifier to cached filename.") + })?; + let mut headers = HashMap::new(); + headers.insert("content-type".to_string(), content_type); + self.http_cache.set(specifier, headers, source.as_bytes())?; + + Ok(File { + local, + maybe_types: None, + media_type, + source, + specifier: specifier.clone(), + }) + } /// Asynchronously fetch remote source file specified by the URL following /// redirects. /// @@ -555,6 +617,12 @@ impl FileFetcher { self.cache.insert(specifier.clone(), file.clone()); } result + } else if scheme == "blob" { + let result = self.fetch_blob_url(specifier); + if let Ok(file) = &result { + self.cache.insert(specifier.clone(), file.clone()); + } + result } else if !self.allow_remote { Err(custom_error( "NoRemote", @@ -604,6 +672,7 @@ mod tests { use deno_core::error::get_custom_error_class; use deno_core::resolve_url; use deno_core::resolve_url_or_path; + use deno_runtime::deno_file::Blob; use std::rc::Rc; use tempfile::TempDir; @@ -611,14 +680,29 @@ mod tests { cache_setting: CacheSetting, maybe_temp_dir: Option<Rc<TempDir>>, ) -> (FileFetcher, Rc<TempDir>) { + let (file_fetcher, temp_dir, _) = + setup_with_blob_url_store(cache_setting, maybe_temp_dir); + (file_fetcher, temp_dir) + } + + fn setup_with_blob_url_store( + cache_setting: CacheSetting, + maybe_temp_dir: Option<Rc<TempDir>>, + ) -> (FileFetcher, Rc<TempDir>, BlobUrlStore) { let temp_dir = maybe_temp_dir.unwrap_or_else(|| { Rc::new(TempDir::new().expect("failed to create temp directory")) }); let location = temp_dir.path().join("deps"); - let file_fetcher = - FileFetcher::new(HttpCache::new(&location), cache_setting, true, None) - .expect("setup failed"); - (file_fetcher, temp_dir) + let blob_url_store = BlobUrlStore::default(); + let file_fetcher = FileFetcher::new( + HttpCache::new(&location), + cache_setting, + true, + None, + blob_url_store.clone(), + ) + .expect("setup failed"); + (file_fetcher, temp_dir, blob_url_store) } macro_rules! file_url { @@ -989,6 +1073,36 @@ mod tests { } #[tokio::test] + async fn test_fetch_blob_url() { + let (file_fetcher, _, blob_url_store) = + setup_with_blob_url_store(CacheSetting::Use, None); + + let specifier = blob_url_store.insert( + Blob { + data: + "export const a = \"a\";\n\nexport enum A {\n A,\n B,\n C,\n}\n" + .as_bytes() + .to_vec(), + media_type: "application/typescript".to_string(), + }, + None, + ); + + let result = file_fetcher + .fetch(&specifier, &Permissions::allow_all()) + .await; + assert!(result.is_ok()); + let file = result.unwrap(); + assert_eq!( + file.source, + "export const a = \"a\";\n\nexport enum A {\n A,\n B,\n C,\n}\n" + ); + assert_eq!(file.media_type, MediaType::TypeScript); + assert_eq!(file.maybe_types, None); + assert_eq!(file.specifier, specifier); + } + + #[tokio::test] async fn test_fetch_complex() { let _http_server_guard = test_util::http_server(); let (file_fetcher, temp_dir) = setup(CacheSetting::Use, None); @@ -1061,6 +1175,7 @@ mod tests { CacheSetting::ReloadAll, true, None, + BlobUrlStore::default(), ) .expect("setup failed"); let result = file_fetcher @@ -1087,6 +1202,7 @@ mod tests { CacheSetting::Use, true, None, + BlobUrlStore::default(), ) .expect("could not create file fetcher"); let specifier = @@ -1114,6 +1230,7 @@ mod tests { CacheSetting::Use, true, None, + BlobUrlStore::default(), ) .expect("could not create file fetcher"); let result = file_fetcher_02 @@ -1274,6 +1391,7 @@ mod tests { CacheSetting::Use, true, None, + BlobUrlStore::default(), ) .expect("could not create file fetcher"); let specifier = @@ -1304,6 +1422,7 @@ mod tests { CacheSetting::Use, true, None, + BlobUrlStore::default(), ) .expect("could not create file fetcher"); let result = file_fetcher_02 @@ -1413,6 +1532,7 @@ mod tests { CacheSetting::Use, false, None, + BlobUrlStore::default(), ) .expect("could not create file fetcher"); let specifier = @@ -1439,6 +1559,7 @@ mod tests { CacheSetting::Only, true, None, + BlobUrlStore::default(), ) .expect("could not create file fetcher"); let file_fetcher_02 = FileFetcher::new( @@ -1446,6 +1567,7 @@ mod tests { CacheSetting::Use, true, None, + BlobUrlStore::default(), ) .expect("could not create file fetcher"); let specifier = |