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.rs278
1 files changed, 238 insertions, 40 deletions
diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs
index c4e0e4fec..2e75517e6 100644
--- a/cli/file_fetcher.rs
+++ b/cli/file_fetcher.rs
@@ -6,6 +6,7 @@ use crate::http_util::create_http_client;
use crate::http_util::FetchOnceResult;
use crate::msg;
use crate::op_error::OpError;
+use crate::permissions::Permissions;
use deno_core::ErrBox;
use deno_core::ModuleSpecifier;
use futures::future::FutureExt;
@@ -109,6 +110,7 @@ impl SourceFileFetcher {
pub fn fetch_cached_source_file(
&self,
specifier: &ModuleSpecifier,
+ permissions: Permissions,
) -> Option<SourceFile> {
let maybe_source_file = self.source_file_cache.get(specifier.to_string());
@@ -123,7 +125,7 @@ impl SourceFileFetcher {
// future, because it doesn't actually do any asynchronous
// action in that path.
if let Ok(maybe_source_file) =
- self.get_source_file_from_local_cache(specifier.as_url())
+ self.get_source_file_from_local_cache(specifier.as_url(), &permissions)
{
return maybe_source_file;
}
@@ -148,6 +150,7 @@ impl SourceFileFetcher {
&self,
specifier: &ModuleSpecifier,
maybe_referrer: Option<ModuleSpecifier>,
+ permissions: Permissions,
) -> Result<SourceFile, ErrBox> {
let module_url = specifier.as_url().to_owned();
debug!("fetch_source_file specifier: {} ", &module_url);
@@ -167,6 +170,7 @@ impl SourceFileFetcher {
self.use_disk_cache,
self.no_remote,
self.cached_only,
+ &permissions,
)
.await;
@@ -222,6 +226,7 @@ impl SourceFileFetcher {
fn get_source_file_from_local_cache(
&self,
module_url: &Url,
+ permissions: &Permissions,
) -> Result<Option<SourceFile>, ErrBox> {
let url_scheme = module_url.scheme();
let is_local_file = url_scheme == "file";
@@ -229,7 +234,7 @@ impl SourceFileFetcher {
// Local files are always fetched from disk bypassing cache entirely.
if is_local_file {
- return self.fetch_local_file(&module_url).map(Some);
+ return self.fetch_local_file(&module_url, permissions).map(Some);
}
self.fetch_cached_remote_source(&module_url)
@@ -252,6 +257,7 @@ impl SourceFileFetcher {
use_disk_cache: bool,
no_remote: bool,
cached_only: bool,
+ permissions: &Permissions,
) -> Result<SourceFile, ErrBox> {
let url_scheme = module_url.scheme();
let is_local_file = url_scheme == "file";
@@ -259,7 +265,7 @@ impl SourceFileFetcher {
// Local files are always fetched from disk bypassing cache entirely.
if is_local_file {
- return self.fetch_local_file(&module_url);
+ return self.fetch_local_file(&module_url, permissions);
}
// The file is remote, fail if `no_remote` is true.
@@ -276,18 +282,29 @@ impl SourceFileFetcher {
// Fetch remote file and cache on-disk for subsequent access
self
- .fetch_remote_source(&module_url, use_disk_cache, cached_only, 10)
+ .fetch_remote_source(
+ &module_url,
+ use_disk_cache,
+ cached_only,
+ 10,
+ permissions,
+ )
.await
}
/// Fetch local source file.
- fn fetch_local_file(&self, module_url: &Url) -> Result<SourceFile, ErrBox> {
+ fn fetch_local_file(
+ &self,
+ module_url: &Url,
+ permissions: &Permissions,
+ ) -> Result<SourceFile, ErrBox> {
let filepath = module_url.to_file_path().map_err(|()| {
ErrBox::from(OpError::uri_error(
"File URL contains invalid path".to_owned(),
))
})?;
+ permissions.check_read(&filepath)?;
let source_code = match fs::read(filepath.clone()) {
Ok(c) => c,
Err(e) => return Err(e.into()),
@@ -390,12 +407,17 @@ impl SourceFileFetcher {
use_disk_cache: bool,
cached_only: bool,
redirect_limit: i64,
+ permissions: &Permissions,
) -> Pin<Box<dyn Future<Output = Result<SourceFile, ErrBox>>>> {
if redirect_limit < 0 {
let e = OpError::http("too many redirects".to_string());
return futures::future::err(e.into()).boxed_local();
}
+ if let Err(e) = permissions.check_net_url(&module_url) {
+ return futures::future::err(e.into()).boxed_local();
+ }
+
let is_blacklisted =
check_cache_blacklist(module_url, self.cache_blacklist.as_ref());
// First try local cache
@@ -441,6 +463,7 @@ impl SourceFileFetcher {
Ok((_, headers)) => headers.get("etag").map(String::from),
Err(_) => None,
};
+ let permissions = permissions.clone();
let http_client = self.http_client.clone();
// Single pass fetch, either yields code or yields redirect.
let f = async move {
@@ -463,6 +486,7 @@ impl SourceFileFetcher {
use_disk_cache,
cached_only,
redirect_limit - 1,
+ &permissions,
)
.await
}
@@ -752,11 +776,15 @@ mod tests {
if cfg!(windows) {
// Should fail: missing drive letter.
let u = Url::parse("file:///etc/passwd").unwrap();
- fetcher.fetch_local_file(&u).unwrap_err();
+ fetcher
+ .fetch_local_file(&u, &Permissions::allow_all())
+ .unwrap_err();
} else {
// Should fail: local network paths are not supported on unix.
let u = Url::parse("file://server/etc/passwd").unwrap();
- fetcher.fetch_local_file(&u).unwrap_err();
+ fetcher
+ .fetch_local_file(&u, &Permissions::allow_all())
+ .unwrap_err();
}
}
@@ -774,7 +802,13 @@ mod tests {
let cache_filename = fetcher.http_cache.get_cache_filename(&module_url);
let result = fetcher
- .get_source_file(&module_url, true, false, false)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r = result.unwrap();
@@ -795,7 +829,13 @@ mod tests {
metadata.write(&cache_filename).unwrap();
let result2 = fetcher_1
- .get_source_file(&module_url, true, false, false)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result2.is_ok());
let r2 = result2.unwrap();
@@ -818,7 +858,13 @@ mod tests {
metadata.write(&cache_filename).unwrap();
let result3 = fetcher_2
- .get_source_file(&module_url_1, true, false, false)
+ .get_source_file(
+ &module_url_1,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result3.is_ok());
let r3 = result3.unwrap();
@@ -839,7 +885,13 @@ mod tests {
// and don't use cache
let fetcher = setup_file_fetcher(temp_dir.path());
let result4 = fetcher
- .get_source_file(&module_url_2, false, false, false)
+ .get_source_file(
+ &module_url_2,
+ false,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result4.is_ok());
let r4 = result4.unwrap();
@@ -863,7 +915,13 @@ mod tests {
let cache_filename = fetcher.http_cache.get_cache_filename(&module_url);
let result = fetcher
- .get_source_file(&module_url, true, false, false)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r = result.unwrap();
@@ -883,7 +941,13 @@ mod tests {
metadata.write(&cache_filename).unwrap();
let result2 = fetcher
- .get_source_file(&module_url, true, false, false)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result2.is_ok());
let r2 = result2.unwrap();
@@ -903,7 +967,13 @@ mod tests {
// process) and don't use cache
let fetcher = setup_file_fetcher(temp_dir.path());
let result3 = fetcher
- .get_source_file(&module_url_1, false, false, false)
+ .get_source_file(
+ &module_url_1,
+ false,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result3.is_ok());
let r3 = result3.unwrap();
@@ -930,7 +1000,9 @@ mod tests {
fetcher.http_cache.get_cache_filename(&specifier.as_url());
// first download
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
let headers_file_name =
@@ -946,7 +1018,9 @@ mod tests {
// `use_disk_cache` is set to false, this can be verified using source
// header file creation timestamp (should be the same as after first
// download)
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
let result = fs::File::open(&headers_file_name);
@@ -984,7 +1058,13 @@ mod tests {
// Test basic follow and headers recording
let result = fetcher
- .get_source_file(&redirect_module_url, true, false, false)
+ .get_source_file(
+ &redirect_module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let mod_meta = result.unwrap();
@@ -1033,7 +1113,13 @@ mod tests {
// Test double redirects and headers recording
let result = fetcher
- .get_source_file(&double_redirect_url, true, false, false)
+ .get_source_file(
+ &double_redirect_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let mod_meta = result.unwrap();
@@ -1080,7 +1166,13 @@ mod tests {
// Test that redirect target is not downloaded twice for different redirect source.
let result = fetcher
- .get_source_file(&double_redirect_url, true, false, false)
+ .get_source_file(
+ &double_redirect_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let result = fs::File::open(&target_path);
@@ -1095,7 +1187,13 @@ mod tests {
// using source header file creation timestamp (should be the same as
// after first `get_source_file`)
let result = fetcher
- .get_source_file(&redirect_url, true, false, false)
+ .get_source_file(
+ &redirect_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let result = fs::File::open(&target_path_);
@@ -1121,12 +1219,24 @@ mod tests {
// Test that redirections can be limited
let result = fetcher
- .fetch_remote_source(&double_redirect_url, false, false, 2)
+ .fetch_remote_source(
+ &double_redirect_url,
+ false,
+ false,
+ 2,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let result = fetcher
- .fetch_remote_source(&double_redirect_url, false, false, 1)
+ .fetch_remote_source(
+ &double_redirect_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_err());
// FIXME(bartlomieju):
@@ -1161,7 +1271,13 @@ mod tests {
// Test basic follow and headers recording
let result = fetcher
- .get_source_file(&redirect_module_url, true, false, false)
+ .get_source_file(
+ &redirect_module_url,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let mod_meta = result.unwrap();
@@ -1193,7 +1309,13 @@ mod tests {
Url::parse("http://localhost:4545/cli/tests/002_hello.ts").unwrap();
// Remote modules are not allowed
let result = fetcher
- .get_source_file(&module_url, true, true, false)
+ .get_source_file(
+ &module_url,
+ true,
+ true,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_err());
// FIXME(bartlomieju):
@@ -1216,7 +1338,13 @@ mod tests {
// file hasn't been cached before
let result = fetcher
- .get_source_file(&module_url, true, false, true)
+ .get_source_file(
+ &module_url,
+ true,
+ false,
+ true,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_err());
// FIXME(bartlomieju):
@@ -1225,12 +1353,24 @@ mod tests {
// download and cache file
let result = fetcher_1
- .get_source_file(&module_url_1, true, false, false)
+ .get_source_file(
+ &module_url_1,
+ true,
+ false,
+ false,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
// module is already cached, should be ok even with `cached_only`
let result = fetcher_2
- .get_source_file(&module_url_2, true, false, true)
+ .get_source_file(
+ &module_url_2,
+ true,
+ false,
+ true,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
drop(http_server_guard);
@@ -1244,7 +1384,13 @@ mod tests {
Url::parse("http://127.0.0.1:4545/cli/tests/subdir/mt_video_mp2t.t3.ts")
.unwrap();
let result = fetcher
- .fetch_remote_source(&module_url, false, false, 10)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 10,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r = result.unwrap();
@@ -1289,7 +1435,13 @@ mod tests {
let module_url_3_ = module_url_3.clone();
let result = fetcher
- .fetch_remote_source(&module_url, false, false, 10)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 10,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r = result.unwrap();
@@ -1298,7 +1450,13 @@ mod tests {
let (_, headers) = fetcher.http_cache.get(&module_url).unwrap();
assert_eq!(headers.get("content-type").unwrap(), "text/typescript");
let result = fetcher_1
- .fetch_remote_source(&module_url_2, false, false, 10)
+ .fetch_remote_source(
+ &module_url_2,
+ false,
+ false,
+ 10,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r2 = result.unwrap();
@@ -1309,7 +1467,13 @@ mod tests {
// test unknown extension
let result = fetcher_2
- .fetch_remote_source(&module_url_3, false, false, 10)
+ .fetch_remote_source(
+ &module_url_3,
+ false,
+ false,
+ 10,
+ &Permissions::allow_all(),
+ )
.await;
assert!(result.is_ok());
let r3 = result.unwrap();
@@ -1328,14 +1492,18 @@ mod tests {
// Test failure case.
let specifier =
ModuleSpecifier::resolve_url(file_url!("/baddir/hello.ts")).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_err());
let p =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("js/main.ts");
let specifier =
ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
}
@@ -1347,14 +1515,18 @@ mod tests {
// Test failure case.
let specifier =
ModuleSpecifier::resolve_url(file_url!("/baddir/hello.ts")).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_err());
let p =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("js/main.ts");
let specifier =
ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
}
@@ -1367,7 +1539,9 @@ mod tests {
.join("tests/001_hello.js");
let specifier =
ModuleSpecifier::resolve_url_or_path(p.to_str().unwrap()).unwrap();
- let r = fetcher.fetch_source_file(&specifier, None).await;
+ let r = fetcher
+ .fetch_source_file(&specifier, None, Permissions::allow_all())
+ .await;
assert!(r.is_ok());
}
@@ -1611,7 +1785,13 @@ mod tests {
Url::parse("http://127.0.0.1:4545/etag_script.ts").unwrap();
let source = fetcher
- .fetch_remote_source(&module_url, false, false, 1)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await;
assert!(source.is_ok());
let source = source.unwrap();
@@ -1633,7 +1813,13 @@ mod tests {
let file_name = fetcher.http_cache.get_cache_filename(&module_url);
let _ = fs::write(&file_name, "changed content");
let cached_source = fetcher
- .fetch_remote_source(&module_url, false, false, 1)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await
.unwrap();
assert_eq!(cached_source.source_code, b"changed content");
@@ -1732,7 +1918,13 @@ mod tests {
let module_url =
Url::parse("http://127.0.0.1:4545/xTypeScriptTypes.js").unwrap();
let source = fetcher
- .fetch_remote_source(&module_url, false, false, 1)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await;
assert!(source.is_ok());
let source = source.unwrap();
@@ -1752,7 +1944,13 @@ mod tests {
let module_url =
Url::parse("http://127.0.0.1:4545/referenceTypes.js").unwrap();
let source = fetcher
- .fetch_remote_source(&module_url, false, false, 1)
+ .fetch_remote_source(
+ &module_url,
+ false,
+ false,
+ 1,
+ &Permissions::allow_all(),
+ )
.await;
assert!(source.is_ok());
let source = source.unwrap();