feat: add --location=<href> and globalThis.location (#7369)

This commit is contained in:
Nayeem Rahman 2021-01-07 18:06:08 +00:00 committed by GitHub
parent c347dfcd56
commit e61e81eb57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 737 additions and 193 deletions

View file

@ -11,6 +11,7 @@ use deno_core::serde::Deserialize;
use deno_core::serde::Deserializer;
use deno_core::serde::Serialize;
use deno_core::serde::Serializer;
use deno_core::url::Url;
use deno_runtime::permissions::PermissionsOptions;
use log::Level;
use std::fmt;
@ -172,6 +173,7 @@ pub struct Flags {
pub allow_read: Option<Vec<PathBuf>>,
pub allow_run: bool,
pub allow_write: Option<Vec<PathBuf>>,
pub location: Option<Url>,
pub cache_blocklist: Vec<String>,
pub ca_file: Option<String>,
pub cached_only: bool,
@ -324,19 +326,13 @@ lazy_static! {
}
/// Main entry point for parsing deno's command line flags.
/// Exits the process on error.
pub fn flags_from_vec(args: Vec<String>) -> Flags {
match flags_from_vec_safe(args) {
Ok(flags) => flags,
Err(err) => err.exit(),
}
}
/// Same as flags_from_vec but does not exit on error.
pub fn flags_from_vec_safe(args: Vec<String>) -> clap::Result<Flags> {
pub fn flags_from_vec(args: Vec<String>) -> clap::Result<Flags> {
let version = crate::version::deno();
let app = clap_root(&*version);
let matches = app.get_matches_from_safe(args)?;
let matches = app.get_matches_from_safe(args).map_err(|e| clap::Error {
message: e.message.trim_start_matches("error: ").to_string(),
..e
})?;
let mut flags = Flags::default();
@ -597,7 +593,7 @@ fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
print,
code,
as_typescript,
}
};
}
fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
@ -671,6 +667,7 @@ fn runtime_args<'a, 'b>(
};
app
.arg(cached_only_arg())
.arg(location_arg())
.arg(v8_flags_arg())
.arg(seed_arg())
}
@ -689,8 +686,10 @@ fn runtime_args_parse(
if include_inspector {
inspect_arg_parse(flags, matches);
}
location_arg_parse(flags, matches);
v8_flags_arg_parse(flags, matches);
seed_arg_parse(flags, matches);
inspect_arg_parse(flags, matches);
}
fn run_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
@ -1487,6 +1486,30 @@ fn ca_file_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
flags.ca_file = matches.value_of("cert").map(ToOwned::to_owned);
}
fn location_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
flags.location = matches
.value_of("location")
.map(|href| Url::parse(href).unwrap());
}
fn location_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("location")
.long("location")
.takes_value(true)
.value_name("HREF")
.validator(|href| {
let url = Url::parse(&href);
if url.is_err() {
return Err("Failed to parse URL".to_string());
}
if !["http", "https"].contains(&url.unwrap().scheme()) {
return Err("Expected protocol \"http\" or \"https\"".to_string());
}
Ok(())
})
.help("Value of 'globalThis.location' used by some web APIs")
}
fn inspect_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
app
.arg(
@ -1729,7 +1752,6 @@ fn permission_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
// TODO(ry) move this to utility module and add test.
/// Strips fragment part of URL. Panics on bad URL.
pub fn resolve_urls(urls: Vec<String>) -> Vec<String> {
use deno_core::url::Url;
let mut out: Vec<String> = vec![];
for urlstr in urls.iter() {
if let Ok(mut url) = Url::from_str(urlstr) {
@ -1758,7 +1780,7 @@ mod tests {
#[test]
fn global_flags() {
#[rustfmt::skip]
let r = flags_from_vec_safe(svec!["deno", "--unstable", "--log-level", "debug", "--quiet", "run", "script.ts"]);
let r = flags_from_vec(svec!["deno", "--unstable", "--log-level", "debug", "--quiet", "run", "script.ts"]);
let flags = r.unwrap();
assert_eq!(
flags,
@ -1772,15 +1794,14 @@ mod tests {
}
);
#[rustfmt::skip]
let r2 = flags_from_vec_safe(svec!["deno", "run", "--unstable", "--log-level", "debug", "--quiet", "script.ts"]);
let r2 = flags_from_vec(svec!["deno", "run", "--unstable", "--log-level", "debug", "--quiet", "script.ts"]);
let flags2 = r2.unwrap();
assert_eq!(flags2, flags);
}
#[test]
fn upgrade() {
let r =
flags_from_vec_safe(svec!["deno", "upgrade", "--dry-run", "--force"]);
let r = flags_from_vec(svec!["deno", "upgrade", "--dry-run", "--force"]);
let flags = r.unwrap();
assert_eq!(
flags,
@ -1800,15 +1821,15 @@ mod tests {
#[test]
fn version() {
let r = flags_from_vec_safe(svec!["deno", "--version"]);
let r = flags_from_vec(svec!["deno", "--version"]);
assert_eq!(r.unwrap_err().kind, clap::ErrorKind::VersionDisplayed);
let r = flags_from_vec_safe(svec!["deno", "-V"]);
let r = flags_from_vec(svec!["deno", "-V"]);
assert_eq!(r.unwrap_err().kind, clap::ErrorKind::VersionDisplayed);
}
#[test]
fn run_reload() {
let r = flags_from_vec_safe(svec!["deno", "run", "-r", "script.ts"]);
let r = flags_from_vec(svec!["deno", "run", "-r", "script.ts"]);
let flags = r.unwrap();
assert_eq!(
flags,
@ -1824,7 +1845,7 @@ mod tests {
#[test]
fn run_watch() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--unstable",
@ -1847,13 +1868,8 @@ mod tests {
#[test]
fn run_reload_allow_write() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"-r",
"--allow-write",
"script.ts"
]);
let r =
flags_from_vec(svec!["deno", "run", "-r", "--allow-write", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -1869,7 +1885,7 @@ mod tests {
#[test]
fn run_v8_flags() {
let r = flags_from_vec_safe(svec!["deno", "run", "--v8-flags=--help"]);
let r = flags_from_vec(svec!["deno", "run", "--v8-flags=--help"]);
assert_eq!(
r.unwrap(),
Flags {
@ -1881,7 +1897,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--v8-flags=--expose-gc,--gc-stats=1",
@ -1901,7 +1917,7 @@ mod tests {
#[test]
fn script_args() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--allow-net",
@ -1924,7 +1940,7 @@ mod tests {
#[test]
fn allow_all() {
let r = flags_from_vec_safe(svec!["deno", "run", "--allow-all", "gist.ts"]);
let r = flags_from_vec(svec!["deno", "run", "--allow-all", "gist.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -1945,8 +1961,7 @@ mod tests {
#[test]
fn allow_read() {
let r =
flags_from_vec_safe(svec!["deno", "run", "--allow-read", "gist.ts"]);
let r = flags_from_vec(svec!["deno", "run", "--allow-read", "gist.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -1961,8 +1976,7 @@ mod tests {
#[test]
fn allow_hrtime() {
let r =
flags_from_vec_safe(svec!["deno", "run", "--allow-hrtime", "gist.ts"]);
let r = flags_from_vec(svec!["deno", "run", "--allow-hrtime", "gist.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -1980,7 +1994,7 @@ mod tests {
// notice that flags passed after double dash will not
// be parsed to Flags but instead forwarded to
// script args as Deno.args
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--allow-write",
@ -2004,8 +2018,7 @@ mod tests {
#[test]
fn fmt() {
let r =
flags_from_vec_safe(svec!["deno", "fmt", "script_1.ts", "script_2.ts"]);
let r = flags_from_vec(svec!["deno", "fmt", "script_1.ts", "script_2.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2021,7 +2034,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec!["deno", "fmt", "--check"]);
let r = flags_from_vec(svec!["deno", "fmt", "--check"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2034,7 +2047,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec!["deno", "fmt"]);
let r = flags_from_vec(svec!["deno", "fmt"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2047,7 +2060,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec!["deno", "fmt", "--watch", "--unstable"]);
let r = flags_from_vec(svec!["deno", "fmt", "--watch", "--unstable"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2062,7 +2075,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"fmt",
"--check",
@ -2088,7 +2101,7 @@ mod tests {
#[test]
fn language_server() {
let r = flags_from_vec_safe(svec!["deno", "lsp"]);
let r = flags_from_vec(svec!["deno", "lsp"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2100,7 +2113,7 @@ mod tests {
#[test]
fn lint() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"lint",
"--unstable",
@ -2124,7 +2137,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"lint",
"--unstable",
@ -2147,7 +2160,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec!["deno", "lint", "--unstable", "--rules"]);
let r = flags_from_vec(svec!["deno", "lint", "--unstable", "--rules"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2162,7 +2175,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"lint",
"--unstable",
@ -2186,7 +2199,7 @@ mod tests {
#[test]
fn types() {
let r = flags_from_vec_safe(svec!["deno", "types"]);
let r = flags_from_vec(svec!["deno", "types"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2198,7 +2211,7 @@ mod tests {
#[test]
fn cache() {
let r = flags_from_vec_safe(svec!["deno", "cache", "script.ts"]);
let r = flags_from_vec(svec!["deno", "cache", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2212,7 +2225,7 @@ mod tests {
#[test]
fn info() {
let r = flags_from_vec_safe(svec!["deno", "info", "script.ts"]);
let r = flags_from_vec(svec!["deno", "info", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2224,7 +2237,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec!["deno", "info", "--reload", "script.ts"]);
let r = flags_from_vec(svec!["deno", "info", "--reload", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2237,7 +2250,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec!["deno", "info", "--json", "script.ts"]);
let r = flags_from_vec(svec!["deno", "info", "--json", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2249,7 +2262,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec!["deno", "info"]);
let r = flags_from_vec(svec!["deno", "info"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2261,7 +2274,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec!["deno", "info", "--json"]);
let r = flags_from_vec(svec!["deno", "info", "--json"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2276,13 +2289,8 @@ mod tests {
#[test]
fn tsconfig() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"-c",
"tsconfig.json",
"script.ts"
]);
let r =
flags_from_vec(svec!["deno", "run", "-c", "tsconfig.json", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2297,8 +2305,7 @@ mod tests {
#[test]
fn eval() {
let r =
flags_from_vec_safe(svec!["deno", "eval", "'console.log(\"hello\")'"]);
let r = flags_from_vec(svec!["deno", "eval", "'console.log(\"hello\")'"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2321,7 +2328,7 @@ mod tests {
#[test]
fn eval_p() {
let r = flags_from_vec_safe(svec!["deno", "eval", "-p", "1+2"]);
let r = flags_from_vec(svec!["deno", "eval", "-p", "1+2"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2344,12 +2351,8 @@ mod tests {
#[test]
fn eval_typescript() {
let r = flags_from_vec_safe(svec![
"deno",
"eval",
"-T",
"'console.log(\"hello\")'"
]);
let r =
flags_from_vec(svec!["deno", "eval", "-T", "'console.log(\"hello\")'"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2373,7 +2376,7 @@ mod tests {
#[test]
fn eval_with_flags() {
#[rustfmt::skip]
let r = flags_from_vec_safe(svec!["deno", "eval", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "42"]);
let r = flags_from_vec(svec!["deno", "eval", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "42"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2392,6 +2395,7 @@ mod tests {
lock_write: true,
ca_file: Some("example.crt".to_string()),
cached_only: true,
location: Some(Url::parse("https://foo/").unwrap()),
v8_flags: svec!["--help", "--random-seed=1"],
seed: Some(1),
inspect: Some("127.0.0.1:9229".parse().unwrap()),
@ -2409,7 +2413,7 @@ mod tests {
#[test]
fn eval_args() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"eval",
"console.log(Deno.args)",
@ -2439,7 +2443,7 @@ mod tests {
#[test]
fn repl() {
let r = flags_from_vec_safe(svec!["deno"]);
let r = flags_from_vec(svec!["deno"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2460,7 +2464,7 @@ mod tests {
#[test]
fn repl_with_flags() {
#[rustfmt::skip]
let r = flags_from_vec_safe(svec!["deno", "repl", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229"]);
let r = flags_from_vec(svec!["deno", "repl", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2476,6 +2480,7 @@ mod tests {
lock_write: true,
ca_file: Some("example.crt".to_string()),
cached_only: true,
location: Some(Url::parse("https://foo/").unwrap()),
v8_flags: svec!["--help", "--random-seed=1"],
seed: Some(1),
inspect: Some("127.0.0.1:9229".parse().unwrap()),
@ -2496,7 +2501,7 @@ mod tests {
use tempfile::TempDir;
let temp_dir = TempDir::new().expect("tempdir fail").path().to_path_buf();
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
format!("--allow-read=.,{}", temp_dir.to_str().unwrap()),
@ -2519,7 +2524,7 @@ mod tests {
use tempfile::TempDir;
let temp_dir = TempDir::new().expect("tempdir fail").path().to_path_buf();
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
format!("--allow-write=.,{}", temp_dir.to_str().unwrap()),
@ -2539,7 +2544,7 @@ mod tests {
#[test]
fn allow_net_allowlist() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--allow-net=127.0.0.1",
@ -2559,7 +2564,7 @@ mod tests {
#[test]
fn bundle() {
let r = flags_from_vec_safe(svec!["deno", "bundle", "source.ts"]);
let r = flags_from_vec(svec!["deno", "bundle", "source.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2574,7 +2579,7 @@ mod tests {
#[test]
fn bundle_with_config() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"bundle",
"--no-remote",
@ -2600,8 +2605,7 @@ mod tests {
#[test]
fn bundle_with_output() {
let r =
flags_from_vec_safe(svec!["deno", "bundle", "source.ts", "bundle.js"]);
let r = flags_from_vec(svec!["deno", "bundle", "source.ts", "bundle.js"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2617,7 +2621,7 @@ mod tests {
#[test]
fn bundle_with_lock() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"bundle",
"--lock-write",
@ -2640,8 +2644,7 @@ mod tests {
#[test]
fn bundle_with_reload() {
let r =
flags_from_vec_safe(svec!["deno", "bundle", "--reload", "source.ts"]);
let r = flags_from_vec(svec!["deno", "bundle", "--reload", "source.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2657,9 +2660,8 @@ mod tests {
#[test]
fn bundle_nocheck() {
let r =
flags_from_vec_safe(svec!["deno", "bundle", "--no-check", "script.ts"])
.unwrap();
let r = flags_from_vec(svec!["deno", "bundle", "--no-check", "script.ts"])
.unwrap();
assert_eq!(
r,
Flags {
@ -2675,7 +2677,7 @@ mod tests {
#[test]
fn bundle_watch() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"bundle",
"--watch",
@ -2698,7 +2700,7 @@ mod tests {
#[test]
fn run_import_map() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--unstable",
@ -2720,7 +2722,7 @@ mod tests {
#[test]
fn info_import_map() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"info",
"--unstable",
@ -2743,7 +2745,7 @@ mod tests {
#[test]
fn cache_import_map() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"cache",
"--unstable",
@ -2765,7 +2767,7 @@ mod tests {
#[test]
fn doc_import_map() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"doc",
"--unstable",
@ -2791,7 +2793,7 @@ mod tests {
#[test]
fn cache_multiple() {
let r =
flags_from_vec_safe(svec!["deno", "cache", "script.ts", "script_two.ts"]);
flags_from_vec(svec!["deno", "cache", "script.ts", "script_two.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2805,8 +2807,7 @@ mod tests {
#[test]
fn run_seed() {
let r =
flags_from_vec_safe(svec!["deno", "run", "--seed", "250", "script.ts"]);
let r = flags_from_vec(svec!["deno", "run", "--seed", "250", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2822,7 +2823,7 @@ mod tests {
#[test]
fn run_seed_with_v8_flags() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--seed",
@ -2845,7 +2846,7 @@ mod tests {
#[test]
fn install() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"install",
"https://deno.land/std/examples/colors.ts"
@ -2868,7 +2869,7 @@ mod tests {
#[test]
fn install_with_flags() {
#[rustfmt::skip]
let r = flags_from_vec_safe(svec!["deno", "install", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--name", "file_server", "--root", "/foo", "--force", "https://deno.land/std/http/file_server.ts", "foo", "bar"]);
let r = flags_from_vec(svec!["deno", "install", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--name", "file_server", "--root", "/foo", "--force", "https://deno.land/std/http/file_server.ts", "foo", "bar"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2901,12 +2902,8 @@ mod tests {
#[test]
fn log_level() {
let r = flags_from_vec_safe(svec![
"deno",
"run",
"--log-level=debug",
"script.ts"
]);
let r =
flags_from_vec(svec!["deno", "run", "--log-level=debug", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2921,7 +2918,7 @@ mod tests {
#[test]
fn quiet() {
let r = flags_from_vec_safe(svec!["deno", "run", "-q", "script.ts"]);
let r = flags_from_vec(svec!["deno", "run", "-q", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2936,7 +2933,7 @@ mod tests {
#[test]
fn completions() {
let r = flags_from_vec_safe(svec!["deno", "completions", "zsh"]).unwrap();
let r = flags_from_vec(svec!["deno", "completions", "zsh"]).unwrap();
match r.subcommand {
DenoSubcommand::Completions { buf } => assert!(!buf.is_empty()),
@ -2946,7 +2943,7 @@ mod tests {
#[test]
fn run_with_args() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"script.ts",
@ -2963,9 +2960,11 @@ mod tests {
..Flags::default()
}
);
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--location",
"https:foo",
"--allow-read",
"script.ts",
"--allow-net",
@ -2980,14 +2979,14 @@ mod tests {
subcommand: DenoSubcommand::Run {
script: "script.ts".to_string(),
},
location: Some(Url::parse("https://foo/").unwrap()),
allow_read: Some(vec![]),
argv: svec!["--allow-net", "-r", "--help", "--foo", "bar"],
..Flags::default()
}
);
let r =
flags_from_vec_safe(svec!["deno", "run", "script.ts", "foo", "bar"]);
let r = flags_from_vec(svec!["deno", "run", "script.ts", "foo", "bar"]);
assert_eq!(
r.unwrap(),
Flags {
@ -2998,7 +2997,7 @@ mod tests {
..Flags::default()
}
);
let r = flags_from_vec_safe(svec!["deno", "run", "script.ts", "-"]);
let r = flags_from_vec(svec!["deno", "run", "script.ts", "-"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3011,7 +3010,7 @@ mod tests {
);
let r =
flags_from_vec_safe(svec!["deno", "run", "script.ts", "-", "foo", "bar"]);
flags_from_vec(svec!["deno", "run", "script.ts", "-", "foo", "bar"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3026,8 +3025,7 @@ mod tests {
#[test]
fn no_check() {
let r =
flags_from_vec_safe(svec!["deno", "run", "--no-check", "script.ts"]);
let r = flags_from_vec(svec!["deno", "run", "--no-check", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3042,8 +3040,7 @@ mod tests {
#[test]
fn no_remote() {
let r =
flags_from_vec_safe(svec!["deno", "run", "--no-remote", "script.ts"]);
let r = flags_from_vec(svec!["deno", "run", "--no-remote", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3058,8 +3055,7 @@ mod tests {
#[test]
fn cached_only() {
let r =
flags_from_vec_safe(svec!["deno", "run", "--cached-only", "script.ts"]);
let r = flags_from_vec(svec!["deno", "run", "--cached-only", "script.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3074,7 +3070,7 @@ mod tests {
#[test]
fn allow_net_allowlist_with_ports() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--allow-net=deno.land,:8000,:4545",
@ -3102,7 +3098,7 @@ mod tests {
#[test]
fn allow_net_allowlist_with_ipv6_address() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--allow-net=deno.land,deno.land:80,::,127.0.0.1,[::1],1.2.3.4:5678,:5678,[::1]:8080",
@ -3133,7 +3129,7 @@ mod tests {
#[test]
fn lock_write() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--lock-write",
@ -3156,7 +3152,7 @@ mod tests {
#[test]
fn test_with_flags() {
#[rustfmt::skip]
let r = flags_from_vec_safe(svec!["deno", "test", "--unstable", "--no-run", "--filter", "- foo", "--coverage=cov", "--allow-net", "--allow-none", "dir1/", "dir2/", "--", "arg1", "arg2"]);
let r = flags_from_vec(svec!["deno", "test", "--unstable", "--no-run", "--filter", "- foo", "--coverage=cov", "--location", "https:foo", "--allow-net", "--allow-none", "dir1/", "dir2/", "--", "arg1", "arg2"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3170,6 +3166,7 @@ mod tests {
},
unstable: true,
coverage_dir: Some("cov".to_string()),
location: Some(Url::parse("https://foo/").unwrap()),
allow_net: Some(vec![]),
argv: svec!["arg1", "arg2"],
..Flags::default()
@ -3179,7 +3176,7 @@ mod tests {
#[test]
fn run_with_cafile() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"run",
"--cert",
@ -3200,7 +3197,7 @@ mod tests {
#[test]
fn bundle_with_cafile() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"bundle",
"--cert",
@ -3222,8 +3219,7 @@ mod tests {
#[test]
fn upgrade_with_ca_file() {
let r =
flags_from_vec_safe(svec!["deno", "upgrade", "--cert", "example.crt"]);
let r = flags_from_vec(svec!["deno", "upgrade", "--cert", "example.crt"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3243,7 +3239,7 @@ mod tests {
#[test]
fn cache_with_cafile() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"cache",
"--cert",
@ -3265,7 +3261,7 @@ mod tests {
#[test]
fn info_with_cafile() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"info",
"--cert",
@ -3287,8 +3283,7 @@ mod tests {
#[test]
fn doc() {
let r =
flags_from_vec_safe(svec!["deno", "doc", "--json", "path/to/module.ts"]);
let r = flags_from_vec(svec!["deno", "doc", "--json", "path/to/module.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3302,7 +3297,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"doc",
"path/to/module.ts",
@ -3321,7 +3316,7 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec!["deno", "doc"]);
let r = flags_from_vec(svec!["deno", "doc"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3335,8 +3330,7 @@ mod tests {
}
);
let r =
flags_from_vec_safe(svec!["deno", "doc", "--builtin", "Deno.Listener"]);
let r = flags_from_vec(svec!["deno", "doc", "--builtin", "Deno.Listener"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3350,12 +3344,8 @@ mod tests {
}
);
let r = flags_from_vec_safe(svec![
"deno",
"doc",
"--private",
"path/to/module.js"
]);
let r =
flags_from_vec(svec!["deno", "doc", "--private", "path/to/module.js"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3372,7 +3362,7 @@ mod tests {
#[test]
fn inspect_default_host() {
let r = flags_from_vec_safe(svec!["deno", "run", "--inspect", "foo.js"]);
let r = flags_from_vec(svec!["deno", "run", "--inspect", "foo.js"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3387,7 +3377,7 @@ mod tests {
#[test]
fn compile() {
let r = flags_from_vec_safe(svec![
let r = flags_from_vec(svec![
"deno",
"compile",
"https://deno.land/std/examples/colors.ts"
@ -3408,7 +3398,7 @@ mod tests {
#[test]
fn compile_with_flags() {
#[rustfmt::skip]
let r = flags_from_vec_safe(svec!["deno", "compile", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--output", "colors", "https://deno.land/std/examples/colors.ts", "foo", "bar"]);
let r = flags_from_vec(svec!["deno", "compile", "--unstable", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--output", "colors", "https://deno.land/std/examples/colors.ts", "foo", "bar"]);
assert_eq!(
r.unwrap(),
Flags {
@ -3427,6 +3417,7 @@ mod tests {
lock_write: true,
ca_file: Some("example.crt".to_string()),
cached_only: true,
location: Some(Url::parse("https://foo/").unwrap()),
allow_read: Some(vec![]),
allow_net: Some(vec![]),
v8_flags: svec!["--help", "--random-seed=1"],

View file

@ -204,6 +204,7 @@ pub fn create_main_worker(
ts_version: version::TYPESCRIPT.to_string(),
no_color: !colors::use_color(),
get_error_class_fn: Some(&crate::errors::get_error_class_name),
location: program_state.flags.location.clone(),
};
let mut worker = MainWorker::from_options(main_module, permissions, &options);
@ -1223,6 +1224,21 @@ fn get_subcommand(
}
}
fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
match result {
Ok(value) => value,
Err(error) => {
let msg = format!(
"{}: {}",
colors::red_bold("error"),
error.to_string().trim()
);
eprintln!("{}", msg);
std::process::exit(1);
}
}
}
pub fn main() {
#[cfg(windows)]
colors::enable_ansi(); // For Windows 10
@ -1233,16 +1249,12 @@ pub fn main() {
std::process::exit(1);
}
let flags = flags::flags_from_vec(args);
let flags =
unwrap_or_exit(flags::flags_from_vec(args).map_err(AnyError::from));
if !flags.v8_flags.is_empty() {
init_v8_flags(&*flags.v8_flags);
}
init_logger(flags.log_level);
let subcommand_future = get_subcommand(flags);
let result = tokio_util::run_basic(subcommand_future);
if let Err(err) = result {
eprintln!("{}: {}", colors::red_bold("error"), err.to_string());
std::process::exit(1);
}
unwrap_or_exit(tokio_util::run_basic(get_subcommand(flags)));
}

View file

@ -167,7 +167,7 @@ async fn run(source_code: String, metadata: Metadata) -> Result<(), AnyError> {
// TODO(nayeemrmn): Unify this Flags -> WorkerOptions mapping with `deno run`.
let options = WorkerOptions {
apply_source_maps: false,
args: flags.argv.clone(),
args: flags.argv,
debug_flag: flags.log_level.map_or(false, |l| l == log::Level::Debug),
user_agent: crate::http_util::get_user_agent(),
unstable: flags.unstable,
@ -183,6 +183,7 @@ async fn run(source_code: String, metadata: Metadata) -> Result<(), AnyError> {
ts_version: version::TYPESCRIPT.to_string(),
no_color: !colors::use_color(),
get_error_class_fn: Some(&crate::errors::get_error_class_name),
location: flags.location,
};
let mut worker =
MainWorker::from_options(main_module.clone(), permissions, &options);
@ -297,6 +298,7 @@ pub fn compile_to_runtime_flags(
import_map_path: None,
inspect: None,
inspect_brk: None,
location: flags.location,
lock: None,
lock_write: false,
log_level: flags.log_level,

10
cli/tests/070_location.ts Normal file
View file

@ -0,0 +1,10 @@
// TODO(nayeemrmn): Add `Location` and `location` to `dlint`'s globals.
// deno-lint-ignore-file no-undef
console.log(Location);
console.log(Location.prototype);
console.log(location);
try {
location.hostname = "bar";
} catch (error) {
console.log(error);
}

View file

@ -0,0 +1,22 @@
[WILDCARD][Function: Location]
Location { [Symbol(Symbol.toStringTag)]: "Location" }
Location {
hash: [Getter/Setter],
host: [Getter/Setter],
hostname: [Getter/Setter],
href: [Getter/Setter],
origin: [Getter],
password: [Getter/Setter],
pathname: [Getter/Setter],
port: [Getter/Setter],
protocol: [Getter/Setter],
search: [Getter/Setter],
username: [Getter/Setter],
ancestorOrigins: [Getter],
assign: [Function: assign],
reload: [Function: reload],
replace: [Function: replace],
toString: [Function: toString]
}
NotSupportedError: Cannot set "location.hostname".
[WILDCARD]

View file

@ -0,0 +1,5 @@
// TODO(nayeemrmn): Add `Location` and `location` to `dlint`'s globals.
// deno-lint-ignore-file no-undef
console.log(Location);
console.log(Location.prototype);
console.log(location);

View file

@ -0,0 +1,4 @@
[WILDCARD][Function: Location]
Location { [Symbol(Symbol.toStringTag)]: "Location" }
error: Uncaught ReferenceError: Access to "location", run again with --location <href>.
[WILDCARD]

View file

@ -0,0 +1,2 @@
const response = await fetch("fetch/hello.txt");
console.log(await response.text());

View file

@ -0,0 +1,2 @@
[WILDCARD]Hello, world!

View file

@ -0,0 +1 @@
await fetch("");

View file

@ -0,0 +1,2 @@
[WILDCARD]error: Uncaught (in promise) URIError: relative URL without a base
[WILDCARD]

View file

@ -10,8 +10,8 @@ const test: { [key: string]: (...args: any[]) => void | Promise<void> } = {
Deno.writeFileSync(file, new Uint8Array(0), { append: true })
);
},
netFetch(hosts: string[]): void {
hosts.forEach((host) => fetch(host));
netFetch(urls: string[]): void {
urls.forEach((url) => fetch(url));
},
netListen(endpoints: string[]): void {
endpoints.forEach((endpoint) => {

View file

@ -0,0 +1 @@
Hello, world!

View file

@ -1246,7 +1246,7 @@ fn bundle_import_map_no_check() {
.current_dir(util::root_path())
.arg("bundle")
.arg("--no-check")
.arg("--importmap")
.arg("--import-map")
.arg(import_map_path)
.arg("--unstable")
.arg(import)
@ -1689,7 +1689,7 @@ fn repl_test_pty_bad_input() {
#[test]
#[ignore]
fn run_watch_with_importmap_and_relative_paths() {
fn run_watch_with_import_map_and_relative_paths() {
fn create_relative_tmp_file(
directory: &TempDir,
filename: &'static str,
@ -1722,7 +1722,7 @@ fn run_watch_with_importmap_and_relative_paths() {
.arg("run")
.arg("--unstable")
.arg("--watch")
.arg("--importmap")
.arg("--import-map")
.arg(&import_map_path)
.arg(&file_to_watch)
.env("NO_COLOR", "1")
@ -2307,6 +2307,8 @@ fn workers() {
.current_dir(util::tests_path())
.arg("test")
.arg("--reload")
.arg("--location")
.arg("http://127.0.0.1:4545/cli/tests/")
.arg("--allow-net")
.arg("--allow-read")
.arg("--unstable")
@ -2548,6 +2550,23 @@ itest!(_067_test_no_run_type_error {
exit_code: 1,
});
itest!(_070_location {
args: "run --location https://foo/bar?baz#bat 070_location.ts",
output: "070_location.ts.out",
});
itest!(_071_location_unset {
args: "run 071_location_unset.ts",
output: "071_location_unset.ts.out",
exit_code: 1,
});
itest!(_072_location_relative_fetch {
args: "run --location http://127.0.0.1:4545/cli/tests/ --allow-net 072_location_relative_fetch.ts",
output: "072_location_relative_fetch.ts.out",
http_server: true,
});
itest!(_073_worker_error {
args: "run -A 073_worker_error.ts",
output: "073_worker_error.ts.out",
@ -2570,6 +2589,12 @@ itest!(_076_info_json_deps_order {
output: "076_info_json_deps_order.out",
});
itest!(_077_fetch_empty {
args: "run -A 077_fetch_empty.ts",
output: "077_fetch_empty.ts.out",
exit_code: 1,
});
itest!(js_import_detect {
args: "run --quiet --reload js_import_detect.ts",
output: "js_import_detect.ts.out",
@ -5200,16 +5225,14 @@ fn web_platform_tests() {
.tempfile()
.unwrap();
let bundle = concat_bundle(
files,
file.path(),
format!("window.location = {{search: \"{}\"}};\n", variant),
);
let bundle = concat_bundle(files, file.path(), "".to_string());
file.write_all(bundle.as_bytes()).unwrap();
let child = util::deno_cmd()
.current_dir(test_file_path.parent().unwrap())
.arg("run")
.arg("--location")
.arg(&format!("http://web-platform-tests/?{}", variant))
.arg("-A")
.arg(file.path())
.arg(deno_core::serde_json::to_string(&expect_fail).unwrap())

View file

@ -0,0 +1,4 @@
onmessage = function (): void {
postMessage(self.location.href);
close();
};

View file

@ -221,17 +221,6 @@ unitTest({ perms: { net: true } }, async function responseClone(): Promise<
}
});
unitTest({ perms: { net: true } }, async function fetchEmptyInvalid(): Promise<
void
> {
await assertThrowsAsync(
async () => {
await fetch("");
},
URIError,
);
});
unitTest(
{ perms: { net: true } },
async function fetchMultipartFormDataSuccess(): Promise<void> {

View file

@ -1,5 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { assert, assertEquals, assertThrows, unitTest } from "./test_util.ts";
import { assert, assertEquals, unitTest } from "./test_util.ts";
unitTest(function fromInit(): void {
const req = new Request("http://foo/", {
@ -46,8 +46,10 @@ unitTest(function methodNonString(): void {
});
unitTest(function requestRelativeUrl(): void {
// TODO(nayeemrmn): Base from `--location` when implemented and set.
assertThrows(() => new Request("relative-url"), TypeError, "Invalid URL.");
assertEquals(
new Request("relative-url").url,
"http://js-unit-tests/foo/relative-url",
);
});
unitTest(async function cloneRequestBodyStream(): Promise<void> {

View file

@ -97,6 +97,7 @@ function spawnWorkerRunner(
Deno.execPath(),
"run",
"--unstable", // TODO(ry) be able to test stable vs unstable
"--location=http://js-unit-tests/foo/bar",
"-A",
"cli/tests/unit/unit_test_runner.ts",
"--worker",

View file

@ -614,3 +614,41 @@ Deno.test("Worker with disabled permissions", async function () {
await promise;
worker.terminate();
});
Deno.test({
name: "worker location",
fn: async function (): Promise<void> {
const promise = deferred();
const workerModuleHref =
new URL("subdir/worker_location.ts", import.meta.url).href;
const w = new Worker(workerModuleHref, { type: "module" });
w.onmessage = (e): void => {
assertEquals(e.data, workerModuleHref);
promise.resolve();
};
w.postMessage("Hello, world!");
await promise;
w.terminate();
},
});
Deno.test({
name: "worker with relative specifier",
fn: async function (): Promise<void> {
// TODO(nayeemrmn): Add `Location` and `location` to `dlint`'s globals.
// deno-lint-ignore no-undef
assertEquals(location.href, "http://127.0.0.1:4545/cli/tests/");
const promise = deferred();
const w = new Worker(
"./workers/test_worker.ts",
{ type: "module", name: "tsWorker" },
);
w.onmessage = (e): void => {
assertEquals(e.data, "Hello, world!");
promise.resolve();
};
w.postMessage("Hello, world!");
await promise;
w.terminate();
},
});

View file

@ -202,6 +202,10 @@ pub fn install(
let mut executable_args = vec!["run".to_string()];
executable_args.extend_from_slice(&flags.to_permission_args());
if let Some(url) = flags.location.as_ref() {
executable_args.push("--location".to_string());
executable_args.push(url.to_string());
}
if let Some(ca_file) = flags.ca_file {
executable_args.push("--cert".to_string());
executable_args.push(ca_file)

View file

@ -0,0 +1,76 @@
## Location API
Deno supports the
[`location`](https://developer.mozilla.org/en-US/docs/Web/API/Window/location)
global from the web. Please read on.
### Location flag
There is no "web page" whose URL we can use for a location in a Deno process. We
instead allow users to emulate a document location by specifying one on the CLI
using the `--location` flag. It can be a `http` or `https` URL.
```ts
// deno run --location https://example.com/path main.ts
console.log(location.href);
// "https://example.com/path"
```
You must pass `--location <href>` for this to work. If you don't, any access to
the `location` global will throw an error.
```ts
// deno run main.ts
console.log(location.href);
// error: Uncaught ReferenceError: Access to "location", run again with --location <href>.
```
Setting `location` or any of its fields will normally cause navigation in
browsers. This is not applicable in Deno, so it will throw in this situation.
```ts
// deno run --location https://example.com/path main.ts
location.pathname = "./foo";
// error: Uncaught NotSupportedError: Cannot set "location.pathname".
```
### Extended usage
On the web, resource resolution (excluding modules) typically uses the value of
`location.href` as the root on which to base any relative URLs. This affects
some web APIs adopted by Deno.
#### Fetch API
```ts
// deno run --location https://api.github.com/ --allow-net main.ts
const response = await fetch("./orgs/denoland");
// Fetches "https://api.github.com/orgs/denoland".
```
The `fetch()` call above would throw if the `--location` flag was not passed,
since there is no web-analogous location to base it onto.
#### Worker modules
```ts
// deno run --location https://example.com/index.html --allow-net main.ts
const worker = new Worker("./workers/hello.ts", { type: "module" });
// Fetches worker module at "https://example.com/workers/hello.ts".
```
### Only use if necessary
For the above use cases, it is preferable to pass URLs in full rather than
relying on `--location`. You can manually base a relative URL using the `URL`
constructor if needed.
The `--location` flag is intended for those who have some specific purpose in
mind for emulating a document location and are aware that this will only work at
application-level. However, you may also use it to silence errors from a
dependency which is frivolously accessing the `location` global.

View file

@ -9,10 +9,11 @@ is run on a separate thread, dedicated only to that worker.
Currently Deno supports only `module` type workers; thus it's essential to pass
the `type: "module"` option when creating a new worker.
Relative module specifiers are
[not supported](https://github.com/denoland/deno/issues/5216) at the moment. You
can instead use the `URL` constructor and `import.meta.url` to easily create a
specifier for some nearby script.
Use of relative module specifiers in the main worker are only supported with
`--location <href>` passed on the CLI. This is not recommended for portability.
You can instead use the `URL` contructor and `import.meta.url` to easily create
a specifier for some nearby script. Dedicated workers, however, have a location
and this capability by default.
```ts
// Good

View file

@ -23,6 +23,7 @@
"permission_apis": "Permission APIs",
"compiler_apis": "Compiler APIs",
"web_platform_apis": "Web Platform APIs",
"location_api": "Location API",
"workers": "Workers"
}
},

View file

@ -5,6 +5,7 @@
// provided by "deno_web"
const { URLSearchParams } = window.__bootstrap.url;
const { getLocationHref } = window.__bootstrap.location;
const { requiredArguments } = window.__bootstrap.fetchUtil;
const { ReadableStream, isReadableStreamDisturbed } =
@ -987,8 +988,10 @@
this.credentials = input.credentials;
this._stream = input._stream;
} else {
// TODO(nayeemrmn): Base from `--location` when implemented and set.
this.url = new URL(String(input)).href;
const baseUrl = getLocationHref();
this.url = baseUrl != null
? new URL(String(input), baseUrl).href
: new URL(String(input)).href;
}
if (init && "method" in init && init.method) {
@ -1175,20 +1178,25 @@
}
}
let baseUrl = null;
function setBaseUrl(href) {
baseUrl = href;
}
function sendFetchReq(url, method, headers, body, clientRid) {
let headerArray = [];
if (headers) {
headerArray = Array.from(headers.entries());
}
const args = {
return opFetch({
method,
url,
baseUrl,
headers: headerArray,
clientRid,
};
return opFetch(args, body);
}, body);
}
async function fetch(input, init) {
@ -1385,6 +1393,7 @@
Blob,
DomFile,
FormData,
setBaseUrl,
fetch,
Request,
Response,

View file

@ -100,12 +100,12 @@ where
struct FetchArgs {
method: Option<String>,
url: String,
base_url: Option<String>,
headers: Vec<(String, String)>,
client_rid: Option<u32>,
}
let args: FetchArgs = serde_json::from_value(args)?;
let url = args.url;
let client = if let Some(rid) = args.client_rid {
let state_ = state.borrow();
@ -125,10 +125,16 @@ where
None => Method::GET,
};
let url_ = Url::parse(&url)?;
let base_url = match args.base_url {
Some(base_url) => Some(Url::parse(&base_url)?),
_ => None,
};
let url = Url::options()
.base_url(base_url.as_ref())
.parse(&args.url)?;
// Check scheme before asking for net permission
let scheme = url_.scheme();
let scheme = url.scheme();
if scheme != "http" && scheme != "https" {
return Err(type_error(format!("scheme '{}' not supported", scheme)));
}
@ -136,10 +142,10 @@ where
{
let state_ = state.borrow();
let permissions = state_.borrow::<FP>();
permissions.check_net_url(&url_)?;
permissions.check_net_url(&url)?;
}
let mut request = client.request(method, url_);
let mut request = client.request(method, url);
match data.len() {
0 => {}

View file

@ -0,0 +1,227 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
const { URL } = window.__bootstrap.url;
const locationConstructorKey = Symbol("locationConstuctorKey");
class Location {
constructor(href, key) {
if (key != locationConstructorKey) {
throw new TypeError("Illegal constructor.");
}
const url = new URL(href);
Object.defineProperties(this, {
hash: {
get() {
return url.hash;
},
set() {
throw new DOMException(
`Cannot set "location.hash".`,
"NotSupportedError",
);
},
enumerable: true,
},
host: {
get() {
return url.host;
},
set() {
throw new DOMException(
`Cannot set "location.host".`,
"NotSupportedError",
);
},
enumerable: true,
},
hostname: {
get() {
return url.hostname;
},
set() {
throw new DOMException(
`Cannot set "location.hostname".`,
"NotSupportedError",
);
},
enumerable: true,
},
href: {
get() {
return href;
},
set() {
throw new DOMException(
`Cannot set "location.href".`,
"NotSupportedError",
);
},
enumerable: true,
},
origin: {
get() {
return url.origin;
},
enumerable: true,
},
password: {
get() {
return url.password;
},
set() {
throw new DOMException(
`Cannot set "location.password".`,
"NotSupportedError",
);
},
enumerable: true,
},
pathname: {
get() {
return url.pathname;
},
set() {
throw new DOMException(
`Cannot set "location.pathname".`,
"NotSupportedError",
);
},
enumerable: true,
},
port: {
get() {
return url.port;
},
set() {
throw new DOMException(
`Cannot set "location.port".`,
"NotSupportedError",
);
},
enumerable: true,
},
protocol: {
get() {
return url.protocol;
},
set() {
throw new DOMException(
`Cannot set "location.protocol".`,
"NotSupportedError",
);
},
enumerable: true,
},
search: {
get() {
return url.search;
},
set() {
throw new DOMException(
`Cannot set "location.search".`,
"NotSupportedError",
);
},
enumerable: true,
},
username: {
get() {
return url.username;
},
set() {
throw new DOMException(
`Cannot set "location.username".`,
"NotSupportedError",
);
},
enumerable: true,
},
ancestorOrigins: {
get() {
// TODO(nayeemrmn): Replace with a `DOMStringList` instance.
return {
length: 0,
item: () => null,
contains: () => false,
};
},
enumerable: true,
},
assign: {
value: function assign() {
throw new DOMException(
`Cannot call "location.assign()".`,
"NotSupportedError",
);
},
enumerable: true,
},
reload: {
value: function reload() {
throw new DOMException(
`Cannot call "location.reload()".`,
"NotSupportedError",
);
},
enumerable: true,
},
replace: {
value: function replace() {
throw new DOMException(
`Cannot call "location.replace()".`,
"NotSupportedError",
);
},
enumerable: true,
},
toString: {
value: function toString() {
return href;
},
enumerable: true,
},
});
}
}
Object.defineProperties(Location.prototype, {
[Symbol.toStringTag]: {
value: "Location",
configurable: true,
},
});
let location = null;
function setLocationHref(href) {
location = new Location(href, locationConstructorKey);
}
window.__bootstrap = (window.__bootstrap || {});
window.__bootstrap.location = {
locationConstructorDescriptor: {
value: Location,
configurable: true,
writable: true,
},
locationDescriptor: {
get() {
if (location == null) {
throw new ReferenceError(
`Access to "location", run again with --location <href>.`,
);
}
return location;
},
set() {
throw new DOMException(`Cannot set "location".`, "NotSupportedError");
},
enumerable: true,
},
setLocationHref,
getLocationHref() {
return location?.href;
},
};
})(this);

View file

@ -312,3 +312,69 @@ declare var FileReader: {
readonly EMPTY: number;
readonly LOADING: number;
};
/** The location (URL) of the object it is linked to. Changes done on it are
* reflected on the object it relates to. Accessible via
* `globalThis.location`. */
declare class Location {
constructor();
/** Returns a DOMStringList object listing the origins of the ancestor
* browsing contexts, from the parent browsing context to the top-level
* browsing context.
*
* Always empty in Deno. */
readonly ancestorOrigins: DOMStringList;
/** Returns the Location object's URL's fragment (includes leading "#" if non-empty).
*
* Cannot be set in Deno. */
hash: string;
/** Returns the Location object's URL's host and port (if different from the default port for the scheme).
*
* Cannot be set in Deno. */
host: string;
/** Returns the Location object's URL's host.
*
* Cannot be set in Deno. */
hostname: string;
/** Returns the Location object's URL.
*
* Cannot be set in Deno. */
href: string;
toString(): string;
/** Returns the Location object's URL's origin. */
readonly origin: string;
/** Returns the Location object's URL's path.
*
* Cannot be set in Deno. */
pathname: string;
/** Returns the Location object's URL's port.
*
* Cannot be set in Deno. */
port: string;
/** Returns the Location object's URL's scheme.
*
* Cannot be set in Deno. */
protocol: string;
/** Returns the Location object's URL's query (includes leading "?" if
* non-empty).
*
* Cannot be set in Deno. */
search: string;
/** Navigates to the given URL.
*
* Cannot be set in Deno. */
assign(url: string): void;
/** Reloads the current page.
*
* Disabled in Deno. */
reload(): void;
/** @deprecated */
reload(forcedReload: boolean): void;
/** Removes the current page from the session history and navigates to the
* given URL.
*
* Disabled in Deno. */
replace(url: string): void;
}
declare var location: Location;

View file

@ -61,6 +61,10 @@ pub fn init(isolate: &mut JsRuntime) {
include_str!("08_text_encoding.js"),
),
("deno:op_crates/web/11_url.js", include_str!("11_url.js")),
(
"deno:op_crates/web/12_location.js",
include_str!("12_location.js"),
),
(
"deno:op_crates/web/21_filereader.js",
include_str!("21_filereader.js"),

View file

@ -39,6 +39,7 @@ async fn main() -> Result<(), AnyError> {
ts_version: "x".to_string(),
no_color: false,
get_error_class_fn: Some(&get_error_class_name),
location: None,
};
let js_path =

View file

@ -3,6 +3,7 @@
((window) => {
const core = window.Deno.core;
const { Window } = window.__bootstrap.globalInterfaces;
const { getLocationHref } = window.__bootstrap.location;
const { log, pathFromURL } = window.__bootstrap.util;
const { defineEventHandler } = window.__bootstrap.webUtil;
const build = window.__bootstrap.build.build;
@ -127,6 +128,7 @@
constructor(specifier, options = {}) {
super();
specifier = String(specifier);
const {
deno = {},
name = "unknown",
@ -177,6 +179,16 @@
const hasSourceCode = false;
const sourceCode = decoder.decode(new Uint8Array());
if (
specifier.startsWith("./") || specifier.startsWith("../") ||
specifier.startsWith("/") || type == "classic"
) {
const baseUrl = getLocationHref();
if (baseUrl != null) {
specifier = new URL(specifier, baseUrl).href;
}
}
const { id } = createWorker(
specifier,
hasSourceCode,

View file

@ -9,6 +9,7 @@ delete Object.prototype.__proto__;
const util = window.__bootstrap.util;
const eventTarget = window.__bootstrap.eventTarget;
const globalInterfaces = window.__bootstrap.globalInterfaces;
const location = window.__bootstrap.location;
const dispatchMinimal = window.__bootstrap.dispatchMinimal;
const build = window.__bootstrap.build;
const version = window.__bootstrap.version;
@ -196,6 +197,8 @@ delete Object.prototype.__proto__;
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
const windowOrWorkerGlobalScope = {
Location: location.locationConstructorDescriptor,
location: location.locationDescriptor,
Blob: util.nonEnumerable(fetch.Blob),
ByteLengthQueuingStrategy: util.nonEnumerable(
streams.ByteLengthQueuingStrategy,
@ -290,7 +293,19 @@ delete Object.prototype.__proto__;
defineEventHandler(window, "unload", null);
runtimeStart(runtimeOptions);
const { args, noColor, pid, ppid, unstableFlag } = runtimeOptions;
const {
args,
location: locationHref,
noColor,
pid,
ppid,
unstableFlag,
} = runtimeOptions;
if (locationHref != null) {
location.setLocationHref(locationHref);
fetch.setBaseUrl(locationHref);
}
registerErrors();
@ -349,8 +364,11 @@ delete Object.prototype.__proto__;
runtimeOptions,
internalName ?? name,
);
const { unstableFlag, pid, noColor, args } = runtimeOptions;
const { unstableFlag, pid, noColor, args, location: locationHref } =
runtimeOptions;
location.setLocationHref(locationHref);
fetch.setBaseUrl(locationHref);
registerErrors();
const finalDenoNs = {

View file

@ -38,6 +38,8 @@ Some Web APIs are using ops under the hood, eg. `console`, `performance`.
[Body](https://developer.mozilla.org/en-US/docs/Web/API/Body) and
[Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers): modern
Promise-based HTTP Request API.
- [location](https://developer.mozilla.org/en-US/docs/Web/API/Window/location)
and [Location](https://developer.mozilla.org/en-US/docs/Web/API/Location).
- [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData): access
to a `multipart/form-data` serialization.
- [Performance](https://developer.mozilla.org/en-US/docs/Web/API/Performance):

View file

@ -130,6 +130,7 @@ pub struct WebWorker {
terminate_rx: mpsc::Receiver<()>,
handle: WebWorkerHandle,
pub use_deno_namespace: bool,
pub main_module: ModuleSpecifier,
}
pub struct WebWorkerOptions {
@ -197,6 +198,7 @@ impl WebWorker {
terminate_rx,
handle,
use_deno_namespace: options.use_deno_namespace,
main_module: main_module.clone(),
};
{
@ -286,6 +288,7 @@ impl WebWorker {
"tsVersion": options.ts_version,
"unstableFlag": options.unstable,
"v8Version": deno_core::v8_version(),
"location": self.main_module,
});
let runtime_options_str =

View file

@ -63,6 +63,7 @@ pub struct WorkerOptions {
/// Sets `Deno.noColor` in JS runtime.
pub no_color: bool,
pub get_error_class_fn: Option<GetErrorClassFn>,
pub location: Option<Url>,
}
impl MainWorker {
@ -179,6 +180,7 @@ impl MainWorker {
"tsVersion": options.ts_version,
"unstableFlag": options.unstable,
"v8Version": deno_core::v8_version(),
"location": options.location,
});
let script = format!(
@ -282,6 +284,7 @@ mod tests {
ts_version: "x".to_string(),
no_color: true,
get_error_class_fn: None,
location: None,
};
MainWorker::from_options(main_module, permissions, &options)