mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 00:29:09 -05:00
feat: add --cert flag for http client (#3972)
This commit is contained in:
parent
98e585a284
commit
2e7d449623
16 changed files with 654 additions and 21 deletions
|
@ -112,7 +112,8 @@ impl SourceFileFetcher {
|
||||||
cache_blacklist: Vec<String>,
|
cache_blacklist: Vec<String>,
|
||||||
no_remote: bool,
|
no_remote: bool,
|
||||||
cached_only: bool,
|
cached_only: bool,
|
||||||
) -> std::io::Result<Self> {
|
ca_file: Option<String>,
|
||||||
|
) -> Result<Self, ErrBox> {
|
||||||
let file_fetcher = Self {
|
let file_fetcher = Self {
|
||||||
deps_cache,
|
deps_cache,
|
||||||
progress,
|
progress,
|
||||||
|
@ -121,7 +122,7 @@ impl SourceFileFetcher {
|
||||||
use_disk_cache,
|
use_disk_cache,
|
||||||
no_remote,
|
no_remote,
|
||||||
cached_only,
|
cached_only,
|
||||||
http_client: create_http_client(),
|
http_client: create_http_client(ca_file)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(file_fetcher)
|
Ok(file_fetcher)
|
||||||
|
@ -862,6 +863,7 @@ mod tests {
|
||||||
vec![],
|
vec![],
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.expect("setup fail")
|
.expect("setup fail")
|
||||||
}
|
}
|
||||||
|
|
188
cli/flags.rs
188
cli/flags.rs
|
@ -102,6 +102,7 @@ pub struct DenoFlags {
|
||||||
|
|
||||||
pub lock: Option<String>,
|
pub lock: Option<String>,
|
||||||
pub lock_write: bool,
|
pub lock_write: bool,
|
||||||
|
pub ca_file: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn join_paths(whitelist: &[PathBuf], d: &str) -> String {
|
fn join_paths(whitelist: &[PathBuf], d: &str) -> String {
|
||||||
|
@ -313,6 +314,7 @@ fn fmt_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
|
|
||||||
fn install_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
fn install_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
permission_args_parse(flags, matches);
|
permission_args_parse(flags, matches);
|
||||||
|
ca_file_arg_parse(flags, matches);
|
||||||
|
|
||||||
let dir = if matches.is_present("dir") {
|
let dir = if matches.is_present("dir") {
|
||||||
let install_dir = matches.value_of("dir").unwrap();
|
let install_dir = matches.value_of("dir").unwrap();
|
||||||
|
@ -343,6 +345,8 @@ fn install_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bundle_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
fn bundle_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
|
ca_file_arg_parse(flags, matches);
|
||||||
|
|
||||||
let source_file = matches.value_of("source_file").unwrap().to_string();
|
let source_file = matches.value_of("source_file").unwrap().to_string();
|
||||||
|
|
||||||
let out_file = if let Some(out_file) = matches.value_of("out_file") {
|
let out_file = if let Some(out_file) = matches.value_of("out_file") {
|
||||||
|
@ -375,6 +379,7 @@ fn completions_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
|
|
||||||
fn repl_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
fn repl_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
v8_flags_arg_parse(flags, matches);
|
v8_flags_arg_parse(flags, matches);
|
||||||
|
ca_file_arg_parse(flags, matches);
|
||||||
flags.subcommand = DenoSubcommand::Repl;
|
flags.subcommand = DenoSubcommand::Repl;
|
||||||
flags.allow_net = true;
|
flags.allow_net = true;
|
||||||
flags.allow_env = true;
|
flags.allow_env = true;
|
||||||
|
@ -387,6 +392,7 @@ fn repl_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
|
|
||||||
fn eval_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
fn eval_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
v8_flags_arg_parse(flags, matches);
|
v8_flags_arg_parse(flags, matches);
|
||||||
|
ca_file_arg_parse(flags, matches);
|
||||||
flags.allow_net = true;
|
flags.allow_net = true;
|
||||||
flags.allow_env = true;
|
flags.allow_env = true;
|
||||||
flags.allow_run = true;
|
flags.allow_run = true;
|
||||||
|
@ -399,6 +405,8 @@ fn eval_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn info_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
fn info_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
|
ca_file_arg_parse(flags, matches);
|
||||||
|
|
||||||
flags.subcommand = DenoSubcommand::Info {
|
flags.subcommand = DenoSubcommand::Info {
|
||||||
file: matches.value_of("file").map(|f| f.to_string()),
|
file: matches.value_of("file").map(|f| f.to_string()),
|
||||||
};
|
};
|
||||||
|
@ -410,6 +418,7 @@ fn fetch_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
importmap_arg_parse(flags, matches);
|
importmap_arg_parse(flags, matches);
|
||||||
config_arg_parse(flags, matches);
|
config_arg_parse(flags, matches);
|
||||||
no_remote_arg_parse(flags, matches);
|
no_remote_arg_parse(flags, matches);
|
||||||
|
ca_file_arg_parse(flags, matches);
|
||||||
let files = matches
|
let files = matches
|
||||||
.values_of("file")
|
.values_of("file")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -444,6 +453,7 @@ fn run_test_args_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
v8_flags_arg_parse(flags, matches);
|
v8_flags_arg_parse(flags, matches);
|
||||||
no_remote_arg_parse(flags, matches);
|
no_remote_arg_parse(flags, matches);
|
||||||
permission_args_parse(flags, matches);
|
permission_args_parse(flags, matches);
|
||||||
|
ca_file_arg_parse(flags, matches);
|
||||||
|
|
||||||
if matches.is_present("cached-only") {
|
if matches.is_present("cached-only") {
|
||||||
flags.cached_only = true;
|
flags.cached_only = true;
|
||||||
|
@ -558,6 +568,7 @@ fn repl_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
SubCommand::with_name("repl")
|
SubCommand::with_name("repl")
|
||||||
.about("Read Eval Print Loop")
|
.about("Read Eval Print Loop")
|
||||||
.arg(v8_flags_arg())
|
.arg(v8_flags_arg())
|
||||||
|
.arg(ca_file_arg())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_subcommand<'a, 'b>() -> App<'a, 'b> {
|
fn install_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
|
@ -586,6 +597,7 @@ fn install_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.allow_hyphen_values(true)
|
.allow_hyphen_values(true)
|
||||||
)
|
)
|
||||||
|
.arg(ca_file_arg())
|
||||||
.about("Install script as executable")
|
.about("Install script as executable")
|
||||||
.long_about(
|
.long_about(
|
||||||
"Installs a script as executable. The default installation directory is
|
"Installs a script as executable. The default installation directory is
|
||||||
|
@ -608,6 +620,7 @@ fn bundle_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
.required(true),
|
.required(true),
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("out_file").takes_value(true).required(false))
|
.arg(Arg::with_name("out_file").takes_value(true).required(false))
|
||||||
|
.arg(ca_file_arg())
|
||||||
.about("Bundle module and dependencies into single file")
|
.about("Bundle module and dependencies into single file")
|
||||||
.long_about(
|
.long_about(
|
||||||
"Output a single JavaScript file with all dependencies.
|
"Output a single JavaScript file with all dependencies.
|
||||||
|
@ -642,6 +655,7 @@ Example:
|
||||||
|
|
||||||
fn eval_subcommand<'a, 'b>() -> App<'a, 'b> {
|
fn eval_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
SubCommand::with_name("eval")
|
SubCommand::with_name("eval")
|
||||||
|
.arg(ca_file_arg())
|
||||||
.about("Eval script")
|
.about("Eval script")
|
||||||
.long_about(
|
.long_about(
|
||||||
"Evaluate JavaScript from command-line
|
"Evaluate JavaScript from command-line
|
||||||
|
@ -677,6 +691,7 @@ Remote modules cache: directory containing remote modules
|
||||||
TypeScript compiler cache: directory containing TS compiler output",
|
TypeScript compiler cache: directory containing TS compiler output",
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("file").takes_value(true).required(false))
|
.arg(Arg::with_name("file").takes_value(true).required(false))
|
||||||
|
.arg(ca_file_arg())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_subcommand<'a, 'b>() -> App<'a, 'b> {
|
fn fetch_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
|
@ -693,6 +708,7 @@ fn fetch_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
.required(true)
|
.required(true)
|
||||||
.min_values(1),
|
.min_values(1),
|
||||||
)
|
)
|
||||||
|
.arg(ca_file_arg())
|
||||||
.about("Fetch the dependencies")
|
.about("Fetch the dependencies")
|
||||||
.long_about(
|
.long_about(
|
||||||
"Fetch and compile remote dependencies recursively.
|
"Fetch and compile remote dependencies recursively.
|
||||||
|
@ -777,6 +793,7 @@ fn run_test_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||||
.arg(lock_write_arg())
|
.arg(lock_write_arg())
|
||||||
.arg(no_remote_arg())
|
.arg(no_remote_arg())
|
||||||
.arg(v8_flags_arg())
|
.arg(v8_flags_arg())
|
||||||
|
.arg(ca_file_arg())
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("cached-only")
|
Arg::with_name("cached-only")
|
||||||
.long("cached-only")
|
.long("cached-only")
|
||||||
|
@ -896,6 +913,17 @@ fn config_arg_parse(flags: &mut DenoFlags, matches: &ArgMatches) {
|
||||||
flags.config_path = matches.value_of("config").map(ToOwned::to_owned);
|
flags.config_path = matches.value_of("config").map(ToOwned::to_owned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ca_file_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||||
|
Arg::with_name("cert")
|
||||||
|
.long("cert")
|
||||||
|
.value_name("FILE")
|
||||||
|
.help("Load certificate authority from PEM encoded file")
|
||||||
|
.takes_value(true)
|
||||||
|
}
|
||||||
|
fn ca_file_arg_parse(flags: &mut DenoFlags, matches: &clap::ArgMatches) {
|
||||||
|
flags.ca_file = matches.value_of("cert").map(ToOwned::to_owned);
|
||||||
|
}
|
||||||
|
|
||||||
fn reload_arg<'a, 'b>() -> Arg<'a, 'b> {
|
fn reload_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||||
Arg::with_name("reload")
|
Arg::with_name("reload")
|
||||||
.short("r")
|
.short("r")
|
||||||
|
@ -2045,3 +2073,163 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run_with_cafile() {
|
||||||
|
let r = flags_from_vec_safe(svec![
|
||||||
|
"deno",
|
||||||
|
"run",
|
||||||
|
"--cert",
|
||||||
|
"example.crt",
|
||||||
|
"script.ts"
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
r.unwrap(),
|
||||||
|
DenoFlags {
|
||||||
|
subcommand: DenoSubcommand::Run {
|
||||||
|
script: "script.ts".to_string(),
|
||||||
|
},
|
||||||
|
ca_file: Some("example.crt".to_owned()),
|
||||||
|
..DenoFlags::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bundle_with_cafile() {
|
||||||
|
let r = flags_from_vec_safe(svec![
|
||||||
|
"deno",
|
||||||
|
"bundle",
|
||||||
|
"--cert",
|
||||||
|
"example.crt",
|
||||||
|
"source.ts"
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
r.unwrap(),
|
||||||
|
DenoFlags {
|
||||||
|
subcommand: DenoSubcommand::Bundle {
|
||||||
|
source_file: "source.ts".to_string(),
|
||||||
|
out_file: None,
|
||||||
|
},
|
||||||
|
ca_file: Some("example.crt".to_owned()),
|
||||||
|
..DenoFlags::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_with_cafile() {
|
||||||
|
let r = flags_from_vec_safe(svec![
|
||||||
|
"deno",
|
||||||
|
"eval",
|
||||||
|
"--cert",
|
||||||
|
"example.crt",
|
||||||
|
"console.log('hello world')"
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
r.unwrap(),
|
||||||
|
DenoFlags {
|
||||||
|
subcommand: DenoSubcommand::Eval {
|
||||||
|
code: "console.log('hello world')".to_string(),
|
||||||
|
},
|
||||||
|
ca_file: Some("example.crt".to_owned()),
|
||||||
|
allow_net: true,
|
||||||
|
allow_env: true,
|
||||||
|
allow_run: true,
|
||||||
|
allow_read: true,
|
||||||
|
allow_write: true,
|
||||||
|
allow_plugin: true,
|
||||||
|
allow_hrtime: true,
|
||||||
|
..DenoFlags::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fetch_with_cafile() {
|
||||||
|
let r = flags_from_vec_safe(svec![
|
||||||
|
"deno",
|
||||||
|
"fetch",
|
||||||
|
"--cert",
|
||||||
|
"example.crt",
|
||||||
|
"script.ts",
|
||||||
|
"script_two.ts"
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
r.unwrap(),
|
||||||
|
DenoFlags {
|
||||||
|
subcommand: DenoSubcommand::Fetch {
|
||||||
|
files: svec!["script.ts", "script_two.ts"],
|
||||||
|
},
|
||||||
|
ca_file: Some("example.crt".to_owned()),
|
||||||
|
..DenoFlags::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn info_with_cafile() {
|
||||||
|
let r = flags_from_vec_safe(svec![
|
||||||
|
"deno",
|
||||||
|
"info",
|
||||||
|
"--cert",
|
||||||
|
"example.crt",
|
||||||
|
"https://example.com"
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
r.unwrap(),
|
||||||
|
DenoFlags {
|
||||||
|
subcommand: DenoSubcommand::Info {
|
||||||
|
file: Some("https://example.com".to_string()),
|
||||||
|
},
|
||||||
|
ca_file: Some("example.crt".to_owned()),
|
||||||
|
..DenoFlags::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn install_with_cafile() {
|
||||||
|
let r = flags_from_vec_safe(svec![
|
||||||
|
"deno",
|
||||||
|
"install",
|
||||||
|
"--cert",
|
||||||
|
"example.crt",
|
||||||
|
"deno_colors",
|
||||||
|
"https://deno.land/std/examples/colors.ts"
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
r.unwrap(),
|
||||||
|
DenoFlags {
|
||||||
|
subcommand: DenoSubcommand::Install {
|
||||||
|
dir: None,
|
||||||
|
exe_name: "deno_colors".to_string(),
|
||||||
|
module_url: "https://deno.land/std/examples/colors.ts".to_string(),
|
||||||
|
args: vec![],
|
||||||
|
force: false,
|
||||||
|
},
|
||||||
|
ca_file: Some("example.crt".to_owned()),
|
||||||
|
..DenoFlags::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn repl_with_cafile() {
|
||||||
|
let r = flags_from_vec_safe(svec!["deno", "repl", "--cert", "example.crt"]);
|
||||||
|
assert_eq!(
|
||||||
|
r.unwrap(),
|
||||||
|
DenoFlags {
|
||||||
|
subcommand: DenoSubcommand::Repl {},
|
||||||
|
ca_file: Some("example.crt".to_owned()),
|
||||||
|
allow_read: true,
|
||||||
|
allow_write: true,
|
||||||
|
allow_net: true,
|
||||||
|
allow_env: true,
|
||||||
|
allow_run: true,
|
||||||
|
allow_plugin: true,
|
||||||
|
allow_hrtime: true,
|
||||||
|
..DenoFlags::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@ impl GlobalState {
|
||||||
flags.cache_blacklist.clone(),
|
flags.cache_blacklist.clone(),
|
||||||
flags.no_remote,
|
flags.no_remote,
|
||||||
flags.cached_only,
|
flags.cached_only,
|
||||||
|
flags.ca_file.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let ts_compiler = TsCompiler::new(
|
let ts_compiler = TsCompiler::new(
|
||||||
|
|
164
cli/http_util.rs
164
cli/http_util.rs
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
use crate::deno_error;
|
use crate::deno_error;
|
||||||
use crate::deno_error::DenoError;
|
use crate::deno_error::DenoError;
|
||||||
|
use crate::deno_error::ErrorKind;
|
||||||
use crate::version;
|
use crate::version;
|
||||||
use brotli2::read::BrotliDecoder;
|
use brotli2::read::BrotliDecoder;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
@ -21,6 +22,7 @@ use reqwest::Client;
|
||||||
use reqwest::Response;
|
use reqwest::Response;
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
use std::fs::File;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
@ -32,20 +34,31 @@ use url::Url;
|
||||||
|
|
||||||
/// Create new instance of async reqwest::Client. This client supports
|
/// Create new instance of async reqwest::Client. This client supports
|
||||||
/// proxies and doesn't follow redirects.
|
/// proxies and doesn't follow redirects.
|
||||||
pub fn create_http_client() -> Client {
|
pub fn create_http_client(ca_file: Option<String>) -> Result<Client, ErrBox> {
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers.insert(
|
||||||
USER_AGENT,
|
USER_AGENT,
|
||||||
format!("Deno/{}", version::DENO).parse().unwrap(),
|
format!("Deno/{}", version::DENO).parse().unwrap(),
|
||||||
);
|
);
|
||||||
Client::builder()
|
let mut builder = Client::builder()
|
||||||
.redirect(Policy::none())
|
.redirect(Policy::none())
|
||||||
.default_headers(headers)
|
.default_headers(headers)
|
||||||
.use_rustls_tls()
|
.use_rustls_tls();
|
||||||
.build()
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if let Some(ca_file) = ca_file {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
File::open(ca_file)?.read_to_end(&mut buf)?;
|
||||||
|
let cert = reqwest::Certificate::from_pem(&buf)?;
|
||||||
|
builder = builder.add_root_certificate(cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.build().map_err(|_| {
|
||||||
|
ErrBox::from(DenoError::new(
|
||||||
|
ErrorKind::Other,
|
||||||
|
"Unable to build http client".to_string(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
/// Construct the next uri based on base uri and location header fragment
|
/// Construct the next uri based on base uri and location header fragment
|
||||||
/// See <https://tools.ietf.org/html/rfc3986#section-4.2>
|
/// See <https://tools.ietf.org/html/rfc3986#section-4.2>
|
||||||
fn resolve_url_from_location(base_url: &Url, location: &str) -> Url {
|
fn resolve_url_from_location(base_url: &Url, location: &str) -> Url {
|
||||||
|
@ -276,7 +289,7 @@ mod tests {
|
||||||
// Relies on external http server. See tools/http_server.py
|
// Relies on external http server. See tools/http_server.py
|
||||||
let url =
|
let url =
|
||||||
Url::parse("http://127.0.0.1:4545/cli/tests/fixture.json").unwrap();
|
Url::parse("http://127.0.0.1:4545/cli/tests/fixture.json").unwrap();
|
||||||
let client = create_http_client();
|
let client = create_http_client(None).unwrap();
|
||||||
let result = fetch_once(client, &url, None).await;
|
let result = fetch_once(client, &url, None).await;
|
||||||
if let Ok(FetchOnceResult::Code(payload)) = result {
|
if let Ok(FetchOnceResult::Code(payload)) = result {
|
||||||
assert!(!payload.body.is_empty());
|
assert!(!payload.body.is_empty());
|
||||||
|
@ -297,7 +310,7 @@ mod tests {
|
||||||
"http://127.0.0.1:4545/cli/tests/053_import_compression/gziped",
|
"http://127.0.0.1:4545/cli/tests/053_import_compression/gziped",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let client = create_http_client();
|
let client = create_http_client(None).unwrap();
|
||||||
let result = fetch_once(client, &url, None).await;
|
let result = fetch_once(client, &url, None).await;
|
||||||
if let Ok(FetchOnceResult::Code(payload)) = result {
|
if let Ok(FetchOnceResult::Code(payload)) = result {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -320,7 +333,7 @@ mod tests {
|
||||||
async fn test_fetch_with_etag() {
|
async fn test_fetch_with_etag() {
|
||||||
let http_server_guard = crate::test_util::http_server();
|
let http_server_guard = crate::test_util::http_server();
|
||||||
let url = Url::parse("http://127.0.0.1:4545/etag_script.ts").unwrap();
|
let url = Url::parse("http://127.0.0.1:4545/etag_script.ts").unwrap();
|
||||||
let client = create_http_client();
|
let client = create_http_client(None).unwrap();
|
||||||
let result = fetch_once(client.clone(), &url, None).await;
|
let result = fetch_once(client.clone(), &url, None).await;
|
||||||
if let Ok(FetchOnceResult::Code(ResultPayload {
|
if let Ok(FetchOnceResult::Code(ResultPayload {
|
||||||
body,
|
body,
|
||||||
|
@ -353,7 +366,7 @@ mod tests {
|
||||||
"http://127.0.0.1:4545/cli/tests/053_import_compression/brotli",
|
"http://127.0.0.1:4545/cli/tests/053_import_compression/brotli",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let client = create_http_client();
|
let client = create_http_client(None).unwrap();
|
||||||
let result = fetch_once(client, &url, None).await;
|
let result = fetch_once(client, &url, None).await;
|
||||||
if let Ok(FetchOnceResult::Code(payload)) = result {
|
if let Ok(FetchOnceResult::Code(payload)) = result {
|
||||||
assert!(!payload.body.is_empty());
|
assert!(!payload.body.is_empty());
|
||||||
|
@ -382,7 +395,7 @@ mod tests {
|
||||||
// Dns resolver substitutes `127.0.0.1` with `localhost`
|
// Dns resolver substitutes `127.0.0.1` with `localhost`
|
||||||
let target_url =
|
let target_url =
|
||||||
Url::parse("http://localhost:4545/cli/tests/fixture.json").unwrap();
|
Url::parse("http://localhost:4545/cli/tests/fixture.json").unwrap();
|
||||||
let client = create_http_client();
|
let client = create_http_client(None).unwrap();
|
||||||
let result = fetch_once(client, &url, None).await;
|
let result = fetch_once(client, &url, None).await;
|
||||||
if let Ok(FetchOnceResult::Redirect(url)) = result {
|
if let Ok(FetchOnceResult::Redirect(url)) = result {
|
||||||
assert_eq!(url, target_url);
|
assert_eq!(url, target_url);
|
||||||
|
@ -429,4 +442,133 @@ mod tests {
|
||||||
assert_eq!(new_uri.host_str().unwrap(), "deno.land");
|
assert_eq!(new_uri.host_str().unwrap(), "deno.land");
|
||||||
assert_eq!(new_uri.path(), "/z");
|
assert_eq!(new_uri.path(), "/z");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_fetch_with_cafile_sync_string() {
|
||||||
|
let http_server_guard = crate::test_util::http_server();
|
||||||
|
// Relies on external http server. See tools/http_server.py
|
||||||
|
let url =
|
||||||
|
Url::parse("https://localhost:5545/cli/tests/fixture.json").unwrap();
|
||||||
|
|
||||||
|
let client = create_http_client(Some(String::from(
|
||||||
|
crate::test_util::root_path()
|
||||||
|
.join("std/http/testdata/tls/RootCA.pem")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
let result = fetch_once(client, &url, None).await;
|
||||||
|
|
||||||
|
if let Ok(FetchOnceResult::Code(payload)) = result {
|
||||||
|
assert!(!payload.body.is_empty());
|
||||||
|
assert_eq!(payload.content_type, Some("application/json".to_string()));
|
||||||
|
assert_eq!(payload.etag, None);
|
||||||
|
assert_eq!(payload.x_typescript_types, None);
|
||||||
|
} else {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
drop(http_server_guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_fetch_with_cafile_gzip() {
|
||||||
|
let http_server_guard = crate::test_util::http_server();
|
||||||
|
// Relies on external http server. See tools/http_server.py
|
||||||
|
let url = Url::parse(
|
||||||
|
"https://localhost:5545/cli/tests/053_import_compression/gziped",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let client = create_http_client(Some(String::from(
|
||||||
|
crate::test_util::root_path()
|
||||||
|
.join("std/http/testdata/tls/RootCA.pem")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
let result = fetch_once(client, &url, None).await;
|
||||||
|
if let Ok(FetchOnceResult::Code(payload)) = result {
|
||||||
|
assert_eq!(
|
||||||
|
String::from_utf8(payload.body).unwrap(),
|
||||||
|
"console.log('gzip')"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
payload.content_type,
|
||||||
|
Some("application/javascript".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(payload.etag, None);
|
||||||
|
assert_eq!(payload.x_typescript_types, None);
|
||||||
|
} else {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
drop(http_server_guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_fetch_with_cafile_with_etag() {
|
||||||
|
let http_server_guard = crate::test_util::http_server();
|
||||||
|
let url = Url::parse("https://localhost:5545/etag_script.ts").unwrap();
|
||||||
|
let client = create_http_client(Some(String::from(
|
||||||
|
crate::test_util::root_path()
|
||||||
|
.join("std/http/testdata/tls/RootCA.pem")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
let result = fetch_once(client.clone(), &url, None).await;
|
||||||
|
if let Ok(FetchOnceResult::Code(ResultPayload {
|
||||||
|
body,
|
||||||
|
content_type,
|
||||||
|
etag,
|
||||||
|
x_typescript_types,
|
||||||
|
})) = result
|
||||||
|
{
|
||||||
|
assert!(!body.is_empty());
|
||||||
|
assert_eq!(String::from_utf8(body).unwrap(), "console.log('etag')");
|
||||||
|
assert_eq!(content_type, Some("application/typescript".to_string()));
|
||||||
|
assert_eq!(etag, Some("33a64df551425fcc55e".to_string()));
|
||||||
|
assert_eq!(x_typescript_types, None);
|
||||||
|
} else {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
let res =
|
||||||
|
fetch_once(client, &url, Some("33a64df551425fcc55e".to_string())).await;
|
||||||
|
assert_eq!(res.unwrap(), FetchOnceResult::NotModified);
|
||||||
|
|
||||||
|
drop(http_server_guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_fetch_with_cafile_brotli() {
|
||||||
|
let http_server_guard = crate::test_util::http_server();
|
||||||
|
// Relies on external http server. See tools/http_server.py
|
||||||
|
let url = Url::parse(
|
||||||
|
"https://localhost:5545/cli/tests/053_import_compression/brotli",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let client = create_http_client(Some(String::from(
|
||||||
|
crate::test_util::root_path()
|
||||||
|
.join("std/http/testdata/tls/RootCA.pem")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
let result = fetch_once(client, &url, None).await;
|
||||||
|
if let Ok(FetchOnceResult::Code(payload)) = result {
|
||||||
|
assert!(!payload.body.is_empty());
|
||||||
|
assert_eq!(
|
||||||
|
String::from_utf8(payload.body).unwrap(),
|
||||||
|
"console.log('brotli');"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
payload.content_type,
|
||||||
|
Some("application/javascript".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(payload.etag, None);
|
||||||
|
assert_eq!(payload.x_typescript_types, None);
|
||||||
|
} else {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
drop(http_server_guard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,6 +155,10 @@ pub fn install(
|
||||||
|
|
||||||
let mut executable_args = vec!["run".to_string()];
|
let mut executable_args = vec!["run".to_string()];
|
||||||
executable_args.extend_from_slice(&flags.to_permission_args());
|
executable_args.extend_from_slice(&flags.to_permission_args());
|
||||||
|
if let Some(ca_file) = flags.ca_file {
|
||||||
|
executable_args.push("--cert".to_string());
|
||||||
|
executable_args.push(ca_file)
|
||||||
|
}
|
||||||
executable_args.push(module_url.to_string());
|
executable_args.push(module_url.to_string());
|
||||||
executable_args.extend_from_slice(&args);
|
executable_args.extend_from_slice(&args);
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,8 @@ pub fn op_fetch(
|
||||||
let args: FetchArgs = serde_json::from_value(args)?;
|
let args: FetchArgs = serde_json::from_value(args)?;
|
||||||
let url = args.url;
|
let url = args.url;
|
||||||
|
|
||||||
let client = create_http_client();
|
let client =
|
||||||
|
create_http_client(state.borrow().global_state.flags.ca_file.clone())?;
|
||||||
|
|
||||||
let method = match args.method {
|
let method = match args.method {
|
||||||
Some(method_str) => Method::from_bytes(method_str.as_bytes())?,
|
Some(method_str) => Method::from_bytes(method_str.as_bytes())?,
|
||||||
|
|
|
@ -74,7 +74,20 @@ pub fn http_server() -> HttpServerGuard {
|
||||||
println!("tools/http_server.py starting...");
|
println!("tools/http_server.py starting...");
|
||||||
let mut child = Command::new("python")
|
let mut child = Command::new("python")
|
||||||
.current_dir(root_path())
|
.current_dir(root_path())
|
||||||
.args(&["-u", "tools/http_server.py"])
|
.args(&[
|
||||||
|
"-u",
|
||||||
|
"tools/http_server.py",
|
||||||
|
"--certfile",
|
||||||
|
root_path()
|
||||||
|
.join("std/http/testdata/tls/localhost.crt")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
"--keyfile",
|
||||||
|
root_path()
|
||||||
|
.join("std/http/testdata/tls/localhost.key")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
])
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("failed to execute child");
|
.expect("failed to execute child");
|
||||||
|
|
24
cli/tests/cafile_info.ts
Normal file
24
cli/tests/cafile_info.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// When run against the test HTTP server, it will serve different media types
|
||||||
|
// based on the URL containing `.t#.` strings, which exercises the different
|
||||||
|
// mapping of media types end to end.
|
||||||
|
|
||||||
|
import { loaded as loadedTs1 } from "https://localhost:5545/cli/tests/subdir/mt_text_typescript.t1.ts";
|
||||||
|
import { loaded as loadedTs2 } from "https://localhost:5545/cli/tests/subdir/mt_video_vdn.t2.ts";
|
||||||
|
import { loaded as loadedTs3 } from "https://localhost:5545/cli/tests/subdir/mt_video_mp2t.t3.ts";
|
||||||
|
import { loaded as loadedTs4 } from "https://localhost:5545/cli/tests/subdir/mt_application_x_typescript.t4.ts";
|
||||||
|
import { loaded as loadedJs1 } from "https://localhost:5545/cli/tests/subdir/mt_text_javascript.j1.js";
|
||||||
|
import { loaded as loadedJs2 } from "https://localhost:5545/cli/tests/subdir/mt_application_ecmascript.j2.js";
|
||||||
|
import { loaded as loadedJs3 } from "https://localhost:5545/cli/tests/subdir/mt_text_ecmascript.j3.js";
|
||||||
|
import { loaded as loadedJs4 } from "https://localhost:5545/cli/tests/subdir/mt_application_x_javascript.j4.js";
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"success",
|
||||||
|
loadedTs1,
|
||||||
|
loadedTs2,
|
||||||
|
loadedTs3,
|
||||||
|
loadedTs4,
|
||||||
|
loadedJs1,
|
||||||
|
loadedJs2,
|
||||||
|
loadedJs3,
|
||||||
|
loadedJs4
|
||||||
|
);
|
14
cli/tests/cafile_info.ts.out
Normal file
14
cli/tests/cafile_info.ts.out
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
local: [WILDCARD]cafile_info.ts
|
||||||
|
type: TypeScript
|
||||||
|
compiled: [WILDCARD].js
|
||||||
|
map: [WILDCARD].js.map
|
||||||
|
deps:
|
||||||
|
https://localhost:5545/cli/tests/cafile_info.ts
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_text_typescript.t1.ts
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_video_vdn.t2.ts
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_video_mp2t.t3.ts
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_application_x_typescript.t4.ts
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_text_javascript.j1.js
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_application_ecmascript.j2.js
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_text_ecmascript.j3.js
|
||||||
|
└── https://localhost:5545/cli/tests/subdir/mt_application_x_javascript.j4.js
|
3
cli/tests/cafile_ts_fetch.ts
Normal file
3
cli/tests/cafile_ts_fetch.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fetch("https://localhost:5545/cli/tests/cafile_ts_fetch.ts.out")
|
||||||
|
.then(r => r.text())
|
||||||
|
.then(t => console.log(t.trimEnd()));
|
1
cli/tests/cafile_ts_fetch.ts.out
Normal file
1
cli/tests/cafile_ts_fetch.ts.out
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Hello
|
3
cli/tests/cafile_url_imports.ts
Normal file
3
cli/tests/cafile_url_imports.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import { printHello } from "https://localhost:5545/cli/tests/subdir/mod2.ts";
|
||||||
|
printHello();
|
||||||
|
console.log("success");
|
2
cli/tests/cafile_url_imports.ts.out
Normal file
2
cli/tests/cafile_url_imports.ts.out
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Hello
|
||||||
|
success
|
|
@ -929,6 +929,174 @@ itest!(import_wasm_via_network {
|
||||||
http_server: true,
|
http_server: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itest!(cafile_url_imports {
|
||||||
|
args: "run --reload --cert tls/RootCA.pem cafile_url_imports.ts",
|
||||||
|
output: "cafile_url_imports.ts.out",
|
||||||
|
http_server: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(cafile_ts_fetch {
|
||||||
|
args: "run --reload --allow-net --cert tls/RootCA.pem cafile_ts_fetch.ts",
|
||||||
|
output: "cafile_ts_fetch.ts.out",
|
||||||
|
http_server: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(cafile_eval {
|
||||||
|
args: "eval --cert tls/RootCA.pem fetch('https://localhost:5545/cli/tests/cafile_ts_fetch.ts.out').then(r=>r.text()).then(t=>console.log(t.trimEnd()))",
|
||||||
|
output: "cafile_ts_fetch.ts.out",
|
||||||
|
http_server: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
itest!(cafile_info {
|
||||||
|
args:
|
||||||
|
"info --cert tls/RootCA.pem https://localhost:5545/cli/tests/cafile_info.ts",
|
||||||
|
output: "cafile_info.ts.out",
|
||||||
|
http_server: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cafile_fetch() {
|
||||||
|
pub use deno::test_util::*;
|
||||||
|
use std::process::Command;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
let g = util::http_server();
|
||||||
|
|
||||||
|
let deno_dir = TempDir::new().expect("tempdir fail");
|
||||||
|
let t = util::root_path().join("cli/tests/cafile_url_imports.ts");
|
||||||
|
let cafile = util::root_path().join("cli/tests/tls/RootCA.pem");
|
||||||
|
let output = Command::new(deno_exe_path())
|
||||||
|
.env("DENO_DIR", deno_dir.path())
|
||||||
|
.current_dir(util::root_path())
|
||||||
|
.arg("fetch")
|
||||||
|
.arg("--cert")
|
||||||
|
.arg(cafile)
|
||||||
|
.arg(t)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to spawn script");
|
||||||
|
|
||||||
|
let code = output.status.code();
|
||||||
|
let out = std::str::from_utf8(&output.stdout).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(Some(0), code);
|
||||||
|
assert_eq!(out, "");
|
||||||
|
|
||||||
|
let expected_path = deno_dir
|
||||||
|
.path()
|
||||||
|
.join("deps/https/localhost_PORT5545/cli/tests/subdir/mod2.ts");
|
||||||
|
assert_eq!(expected_path.exists(), true);
|
||||||
|
|
||||||
|
drop(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cafile_install_remote_module() {
|
||||||
|
pub use deno::test_util::*;
|
||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
let g = util::http_server();
|
||||||
|
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||||
|
let deno_dir = TempDir::new().expect("tempdir fail");
|
||||||
|
let cafile = util::root_path().join("cli/tests/tls/RootCA.pem");
|
||||||
|
|
||||||
|
let install_output = Command::new(deno_exe_path())
|
||||||
|
.env("DENO_DIR", deno_dir.path())
|
||||||
|
.current_dir(util::root_path())
|
||||||
|
.arg("install")
|
||||||
|
.arg("--cert")
|
||||||
|
.arg(cafile)
|
||||||
|
.arg("--dir")
|
||||||
|
.arg(temp_dir.path())
|
||||||
|
.arg("echo_test")
|
||||||
|
.arg("https://localhost:5545/cli/tests/echo.ts")
|
||||||
|
.output()
|
||||||
|
.expect("Failed to spawn script");
|
||||||
|
|
||||||
|
let code = install_output.status.code();
|
||||||
|
assert_eq!(Some(0), code);
|
||||||
|
|
||||||
|
let mut file_path = temp_dir.path().join("echo_test");
|
||||||
|
if cfg!(windows) {
|
||||||
|
file_path = file_path.with_extension(".cmd");
|
||||||
|
}
|
||||||
|
assert!(file_path.exists());
|
||||||
|
|
||||||
|
let path_var_name = if cfg!(windows) { "Path" } else { "PATH" };
|
||||||
|
let paths_var = env::var_os(path_var_name).expect("PATH not set");
|
||||||
|
let mut paths: Vec<PathBuf> = env::split_paths(&paths_var).collect();
|
||||||
|
paths.push(temp_dir.path().to_owned());
|
||||||
|
paths.push(util::target_dir());
|
||||||
|
let path_var_value = env::join_paths(paths).expect("Can't create PATH");
|
||||||
|
|
||||||
|
let output = Command::new(file_path)
|
||||||
|
.current_dir(temp_dir.path())
|
||||||
|
.arg("foo")
|
||||||
|
.env(path_var_name, path_var_value)
|
||||||
|
.output()
|
||||||
|
.expect("failed to spawn script");
|
||||||
|
assert!(std::str::from_utf8(&output.stdout)
|
||||||
|
.unwrap()
|
||||||
|
.trim()
|
||||||
|
.ends_with("foo"));
|
||||||
|
|
||||||
|
drop(deno_dir);
|
||||||
|
drop(temp_dir);
|
||||||
|
drop(g)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cafile_bundle_remote_exports() {
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
let g = util::http_server();
|
||||||
|
|
||||||
|
// First we have to generate a bundle of some remote module that has exports.
|
||||||
|
let mod1 = "https://localhost:5545/cli/tests/subdir/mod1.ts";
|
||||||
|
let cafile = util::root_path().join("cli/tests/tls/RootCA.pem");
|
||||||
|
let t = TempDir::new().expect("tempdir fail");
|
||||||
|
let bundle = t.path().join("mod1.bundle.js");
|
||||||
|
let mut deno = util::deno_cmd()
|
||||||
|
.current_dir(util::root_path())
|
||||||
|
.arg("bundle")
|
||||||
|
.arg("--cert")
|
||||||
|
.arg(cafile)
|
||||||
|
.arg(mod1)
|
||||||
|
.arg(&bundle)
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to spawn script");
|
||||||
|
let status = deno.wait().expect("failed to wait for the child process");
|
||||||
|
assert!(status.success());
|
||||||
|
assert!(bundle.is_file());
|
||||||
|
|
||||||
|
// Now we try to use that bundle from another module.
|
||||||
|
let test = t.path().join("test.js");
|
||||||
|
std::fs::write(
|
||||||
|
&test,
|
||||||
|
"
|
||||||
|
import { printHello3 } from \"./mod1.bundle.js\";
|
||||||
|
printHello3(); ",
|
||||||
|
)
|
||||||
|
.expect("error writing file");
|
||||||
|
|
||||||
|
let output = util::deno_cmd()
|
||||||
|
.current_dir(util::root_path())
|
||||||
|
.arg("run")
|
||||||
|
.arg(&test)
|
||||||
|
.output()
|
||||||
|
.expect("failed to spawn script");
|
||||||
|
// check the output of the test.ts program.
|
||||||
|
assert!(std::str::from_utf8(&output.stdout)
|
||||||
|
.unwrap()
|
||||||
|
.trim()
|
||||||
|
.ends_with("Hello"));
|
||||||
|
assert_eq!(output.stderr, b"");
|
||||||
|
|
||||||
|
drop(g)
|
||||||
|
}
|
||||||
|
|
||||||
mod util {
|
mod util {
|
||||||
use deno::colors::strip_ansi_codes;
|
use deno::colors::strip_ansi_codes;
|
||||||
pub use deno::test_util::*;
|
pub use deno::test_util::*;
|
||||||
|
|
|
@ -5,7 +5,7 @@ https://gist.github.com/cecilemuller/9492b848eb8fe46d462abeb26656c4f8
|
||||||
|
|
||||||
## Certificate authority (CA)
|
## Certificate authority (CA)
|
||||||
|
|
||||||
Generate RootCA.pem, RootCA.key & RootCA.crt:
|
Generate RootCA.pem, RootCA.key, RootCA.crt:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
openssl req -x509 -nodes -new -sha256 -days 36135 -newkey rsa:2048 -keyout RootCA.key -out RootCA.pem -subj "/C=US/CN=Example-Root-CA"
|
openssl req -x509 -nodes -new -sha256 -days 36135 -newkey rsa:2048 -keyout RootCA.key -out RootCA.pem -subj "/C=US/CN=Example-Root-CA"
|
||||||
|
|
|
@ -12,6 +12,9 @@ import sys
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from util import root_path
|
from util import root_path
|
||||||
|
import ssl
|
||||||
|
import getopt
|
||||||
|
import argparse
|
||||||
|
|
||||||
PORT = 4545
|
PORT = 4545
|
||||||
REDIRECT_PORT = 4546
|
REDIRECT_PORT = 4546
|
||||||
|
@ -19,7 +22,52 @@ ANOTHER_REDIRECT_PORT = 4547
|
||||||
DOUBLE_REDIRECTS_PORT = 4548
|
DOUBLE_REDIRECTS_PORT = 4548
|
||||||
INF_REDIRECTS_PORT = 4549
|
INF_REDIRECTS_PORT = 4549
|
||||||
|
|
||||||
QUIET = '-v' not in sys.argv and '--verbose' not in sys.argv
|
HTTPS_PORT = 5545
|
||||||
|
|
||||||
|
|
||||||
|
def create_http_arg_parser():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--certfile')
|
||||||
|
parser.add_argument('--keyfile')
|
||||||
|
parser.add_argument('--verbose', '-v', action='store_true')
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
HttpArgParser = create_http_arg_parser()
|
||||||
|
|
||||||
|
args, unknown = HttpArgParser.parse_known_args(sys.argv[1:])
|
||||||
|
CERT_FILE = args.certfile
|
||||||
|
KEY_FILE = args.keyfile
|
||||||
|
QUIET = not args.verbose
|
||||||
|
|
||||||
|
|
||||||
|
class SSLTCPServer(SocketServer.TCPServer):
|
||||||
|
def __init__(self,
|
||||||
|
server_address,
|
||||||
|
request_handler,
|
||||||
|
certfile,
|
||||||
|
keyfile,
|
||||||
|
ssl_version=ssl.PROTOCOL_TLSv1_2,
|
||||||
|
bind_and_activate=True):
|
||||||
|
SocketServer.TCPServer.__init__(self, server_address, request_handler,
|
||||||
|
bind_and_activate)
|
||||||
|
self.certfile = certfile
|
||||||
|
self.keyfile = keyfile
|
||||||
|
self.ssl_version = ssl_version
|
||||||
|
|
||||||
|
def get_request(self):
|
||||||
|
newsocket, fromaddr = self.socket.accept()
|
||||||
|
connstream = ssl.wrap_socket(
|
||||||
|
newsocket,
|
||||||
|
server_side=True,
|
||||||
|
certfile=self.certfile,
|
||||||
|
keyfile=self.keyfile,
|
||||||
|
ssl_version=self.ssl_version)
|
||||||
|
return connstream, fromaddr
|
||||||
|
|
||||||
|
|
||||||
|
class SSLThreadingTCPServer(SocketServer.ThreadingMixIn, SSLTCPServer):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class QuietSimpleHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
class QuietSimpleHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||||
|
@ -169,7 +217,7 @@ class ContentTypeHandler(QuietSimpleHTTPRequestHandler):
|
||||||
RunningServer = namedtuple("RunningServer", ["server", "thread"])
|
RunningServer = namedtuple("RunningServer", ["server", "thread"])
|
||||||
|
|
||||||
|
|
||||||
def get_socket(port, handler):
|
def get_socket(port, handler, use_https):
|
||||||
SocketServer.TCPServer.allow_reuse_address = True
|
SocketServer.TCPServer.allow_reuse_address = True
|
||||||
if os.name != "nt":
|
if os.name != "nt":
|
||||||
# We use AF_INET6 to avoid flaky test issue, particularly with
|
# We use AF_INET6 to avoid flaky test issue, particularly with
|
||||||
|
@ -177,6 +225,9 @@ def get_socket(port, handler):
|
||||||
# flaky tests, but it does appear to...
|
# flaky tests, but it does appear to...
|
||||||
# See https://github.com/denoland/deno/issues/3332
|
# See https://github.com/denoland/deno/issues/3332
|
||||||
SocketServer.TCPServer.address_family = socket.AF_INET6
|
SocketServer.TCPServer.address_family = socket.AF_INET6
|
||||||
|
|
||||||
|
if use_https:
|
||||||
|
return SSLThreadingTCPServer(("", port), handler, CERT_FILE, KEY_FILE)
|
||||||
return SocketServer.TCPServer(("", port), handler)
|
return SocketServer.TCPServer(("", port), handler)
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,7 +241,7 @@ def server():
|
||||||
".jsx": "application/javascript",
|
".jsx": "application/javascript",
|
||||||
".json": "application/json",
|
".json": "application/json",
|
||||||
})
|
})
|
||||||
s = get_socket(PORT, Handler)
|
s = get_socket(PORT, Handler, False)
|
||||||
if not QUIET:
|
if not QUIET:
|
||||||
print "Deno test server http://localhost:%d/" % PORT
|
print "Deno test server http://localhost:%d/" % PORT
|
||||||
return RunningServer(s, start(s))
|
return RunningServer(s, start(s))
|
||||||
|
@ -207,7 +258,7 @@ def base_redirect_server(host_port, target_port, extra_path_segment=""):
|
||||||
target_host + extra_path_segment + self.path)
|
target_host + extra_path_segment + self.path)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
s = get_socket(host_port, RedirectHandler)
|
s = get_socket(host_port, RedirectHandler, False)
|
||||||
if not QUIET:
|
if not QUIET:
|
||||||
print "redirect server http://localhost:%d/ -> http://localhost:%d/" % (
|
print "redirect server http://localhost:%d/ -> http://localhost:%d/" % (
|
||||||
host_port, target_port)
|
host_port, target_port)
|
||||||
|
@ -236,6 +287,22 @@ def inf_redirects_server():
|
||||||
return base_redirect_server(INF_REDIRECTS_PORT, INF_REDIRECTS_PORT)
|
return base_redirect_server(INF_REDIRECTS_PORT, INF_REDIRECTS_PORT)
|
||||||
|
|
||||||
|
|
||||||
|
def https_server():
|
||||||
|
os.chdir(root_path) # Hopefully the main thread doesn't also chdir.
|
||||||
|
Handler = ContentTypeHandler
|
||||||
|
Handler.extensions_map.update({
|
||||||
|
".ts": "application/typescript",
|
||||||
|
".js": "application/javascript",
|
||||||
|
".tsx": "application/typescript",
|
||||||
|
".jsx": "application/javascript",
|
||||||
|
".json": "application/json",
|
||||||
|
})
|
||||||
|
s = get_socket(HTTPS_PORT, Handler, True)
|
||||||
|
if not QUIET:
|
||||||
|
print "Deno https test server https://localhost:%d/" % HTTPS_PORT
|
||||||
|
return RunningServer(s, start(s))
|
||||||
|
|
||||||
|
|
||||||
def start(s):
|
def start(s):
|
||||||
thread = Thread(target=s.serve_forever, kwargs={"poll_interval": 0.05})
|
thread = Thread(target=s.serve_forever, kwargs={"poll_interval": 0.05})
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
|
@ -246,7 +313,7 @@ def start(s):
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def spawn():
|
def spawn():
|
||||||
servers = (server(), redirect_server(), another_redirect_server(),
|
servers = (server(), redirect_server(), another_redirect_server(),
|
||||||
double_redirects_server())
|
double_redirects_server(), https_server())
|
||||||
while any(not s.thread.is_alive() for s in servers):
|
while any(not s.thread.is_alive() for s in servers):
|
||||||
sleep(0.01)
|
sleep(0.01)
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in a new issue