mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05:00
feat(serve): support --port 0
to use an open port (#23846)
Closes https://github.com/denoland/deno/issues/23845
This commit is contained in:
parent
2b560be83f
commit
20cb0e8863
9 changed files with 96 additions and 16 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -705,6 +705,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"os_pipe",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"serde",
|
||||
"test_server",
|
||||
"tokio",
|
||||
|
|
|
@ -26,7 +26,6 @@ use serde::Serialize;
|
|||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::net::SocketAddr;
|
||||
use std::num::NonZeroU16;
|
||||
use std::num::NonZeroU32;
|
||||
use std::num::NonZeroU8;
|
||||
use std::num::NonZeroUsize;
|
||||
|
@ -283,7 +282,7 @@ impl RunFlags {
|
|||
pub struct ServeFlags {
|
||||
pub script: String,
|
||||
pub watch: Option<WatchFlagsWithPaths>,
|
||||
pub port: NonZeroU16,
|
||||
pub port: u16,
|
||||
pub host: String,
|
||||
}
|
||||
|
||||
|
@ -293,7 +292,7 @@ impl ServeFlags {
|
|||
Self {
|
||||
script,
|
||||
watch: None,
|
||||
port: NonZeroU16::new(port).unwrap(),
|
||||
port,
|
||||
host: host.to_owned(),
|
||||
}
|
||||
}
|
||||
|
@ -2464,8 +2463,8 @@ fn serve_subcommand() -> Command {
|
|||
.arg(
|
||||
Arg::new("port")
|
||||
.long("port")
|
||||
.help("The TCP port to serve on, defaulting to 8000.")
|
||||
.value_parser(value_parser!(NonZeroU16)),
|
||||
.help("The TCP port to serve on, defaulting to 8000. Pass 0 to pick a random free port.")
|
||||
.value_parser(value_parser!(u16)),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("host")
|
||||
|
@ -4127,9 +4126,7 @@ fn serve_parse(
|
|||
app: Command,
|
||||
) -> clap::error::Result<()> {
|
||||
// deno serve implies --allow-net=host:port
|
||||
let port = matches
|
||||
.remove_one::<NonZeroU16>("port")
|
||||
.unwrap_or(NonZeroU16::new(8000).unwrap());
|
||||
let port = matches.remove_one::<u16>("port").unwrap_or(8000);
|
||||
let host = matches
|
||||
.remove_one::<String>("host")
|
||||
.unwrap_or_else(|| "0.0.0.0".to_owned());
|
||||
|
@ -5322,6 +5319,32 @@ mod tests {
|
|||
..Flags::default()
|
||||
}
|
||||
);
|
||||
|
||||
let r = flags_from_vec(svec![
|
||||
"deno",
|
||||
"serve",
|
||||
"--port",
|
||||
"0",
|
||||
"--host",
|
||||
"example.com",
|
||||
"main.ts"
|
||||
]);
|
||||
assert_eq!(
|
||||
r.unwrap(),
|
||||
Flags {
|
||||
subcommand: DenoSubcommand::Serve(ServeFlags::new_default(
|
||||
"main.ts".to_string(),
|
||||
0,
|
||||
"example.com"
|
||||
)),
|
||||
permissions: PermissionFlags {
|
||||
allow_net: Some(vec!["example.com:0".to_owned()]),
|
||||
..Default::default()
|
||||
},
|
||||
code_cache_enabled: true,
|
||||
..Flags::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -62,7 +62,6 @@ use std::env;
|
|||
use std::io::BufReader;
|
||||
use std::io::Cursor;
|
||||
use std::net::SocketAddr;
|
||||
use std::num::NonZeroU16;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
@ -1036,7 +1035,7 @@ impl CliOptions {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn serve_port(&self) -> Option<NonZeroU16> {
|
||||
pub fn serve_port(&self) -> Option<u16> {
|
||||
if let DenoSubcommand::Serve(flags) = self.sub_command() {
|
||||
Some(flags.port)
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::num::NonZeroU16;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
@ -148,7 +147,7 @@ struct SharedWorkerState {
|
|||
disable_deprecated_api_warning: bool,
|
||||
verbose_deprecated_api_warning: bool,
|
||||
code_cache: Option<Arc<dyn code_cache::CodeCache>>,
|
||||
serve_port: Option<NonZeroU16>,
|
||||
serve_port: Option<u16>,
|
||||
serve_host: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -418,7 +417,7 @@ impl CliMainWorkerFactory {
|
|||
feature_checker: Arc<FeatureChecker>,
|
||||
options: CliMainWorkerOptions,
|
||||
node_ipc: Option<i64>,
|
||||
serve_port: Option<NonZeroU16>,
|
||||
serve_port: Option<u16>,
|
||||
serve_host: Option<String>,
|
||||
enable_future_features: bool,
|
||||
disable_deprecated_api_warning: bool,
|
||||
|
|
|
@ -4,7 +4,6 @@ use deno_core::v8;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use serde::Serialize;
|
||||
use std::cell::RefCell;
|
||||
use std::num::NonZeroU16;
|
||||
use std::thread;
|
||||
|
||||
use deno_terminal::colors;
|
||||
|
@ -93,7 +92,7 @@ pub struct BootstrapOptions {
|
|||
pub future: bool,
|
||||
pub mode: WorkerExecutionMode,
|
||||
// Used by `deno serve`
|
||||
pub serve_port: Option<NonZeroU16>,
|
||||
pub serve_port: Option<u16>,
|
||||
pub serve_host: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -198,7 +197,7 @@ impl BootstrapOptions {
|
|||
self.verbose_deprecated_api_warning,
|
||||
self.future,
|
||||
self.mode as u8 as _,
|
||||
self.serve_port.map(|x| x.into()).unwrap_or_default(),
|
||||
self.serve_port.unwrap_or_default(),
|
||||
self.serve_host.as_deref(),
|
||||
);
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ hyper-util.workspace = true
|
|||
once_cell.workspace = true
|
||||
os_pipe.workspace = true
|
||||
pretty_assertions.workspace = true
|
||||
regex.workspace = true
|
||||
serde.workspace = true
|
||||
test_util.workspace = true
|
||||
tokio.workspace = true
|
||||
|
|
|
@ -60,6 +60,8 @@ mod publish;
|
|||
mod repl;
|
||||
#[path = "run_tests.rs"]
|
||||
mod run;
|
||||
#[path = "serve_tests.rs"]
|
||||
mod serve;
|
||||
#[path = "shared_library_tests.rs"]
|
||||
mod shared_library_tests;
|
||||
#[path = "task_tests.rs"]
|
||||
|
|
51
tests/integration/serve_tests.rs
Normal file
51
tests/integration/serve_tests.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use deno_fetch::reqwest;
|
||||
use pretty_assertions::assert_eq;
|
||||
use regex::Regex;
|
||||
use test_util as util;
|
||||
|
||||
#[tokio::test]
|
||||
async fn deno_serve_port_0() {
|
||||
let mut child = util::deno_cmd()
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("serve")
|
||||
.arg("--port")
|
||||
.arg("0")
|
||||
.arg("./serve.ts")
|
||||
.stdout_piped()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
let stdout = child.stdout.as_mut().unwrap();
|
||||
let mut buffer = [0; 50];
|
||||
let _read = stdout.read(&mut buffer).unwrap();
|
||||
let msg = std::str::from_utf8(&buffer).unwrap();
|
||||
let port_regex = Regex::new(r"(\d+)").unwrap();
|
||||
let port = port_regex.find(msg).unwrap().as_str();
|
||||
|
||||
let cert = reqwest::Certificate::from_pem(include_bytes!(
|
||||
"../testdata/tls/RootCA.crt"
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let client = reqwest::Client::builder()
|
||||
.add_root_certificate(cert)
|
||||
.http2_prior_knowledge()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let res = client
|
||||
.get(&format!("http://127.0.0.1:{port}"))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(200, res.status());
|
||||
|
||||
let body = res.text().await.unwrap();
|
||||
assert_eq!(body, "deno serve --port 0 works!");
|
||||
|
||||
child.kill().unwrap();
|
||||
child.wait().unwrap();
|
||||
}
|
5
tests/testdata/serve.ts
vendored
Normal file
5
tests/testdata/serve.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
export default {
|
||||
fetch(_req: Request) {
|
||||
return new Response("deno serve --port 0 works!");
|
||||
},
|
||||
};
|
Loading…
Reference in a new issue