summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSatya Rohith <me@satyarohith.com>2024-05-17 11:08:50 +0530
committerGitHub <noreply@github.com>2024-05-17 05:38:50 +0000
commit20cb0e8863beb0d709adc2f41905ce3f1f465447 (patch)
tree4a07e3bf67905e14513d8372db84169d493dfc8f
parent2b560be83f621af5cab1ff09fa0e76c826e6870a (diff)
feat(serve): support `--port 0` to use an open port (#23846)
Closes https://github.com/denoland/deno/issues/23845
-rw-r--r--Cargo.lock1
-rw-r--r--cli/args/flags.rs39
-rw-r--r--cli/args/mod.rs3
-rw-r--r--cli/worker.rs5
-rw-r--r--runtime/worker_bootstrap.rs5
-rw-r--r--tests/Cargo.toml1
-rw-r--r--tests/integration/mod.rs2
-rw-r--r--tests/integration/serve_tests.rs51
-rw-r--r--tests/testdata/serve.ts5
9 files changed, 96 insertions, 16 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 14ee88169..39b0c00e6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -705,6 +705,7 @@ dependencies = [
"once_cell",
"os_pipe",
"pretty_assertions",
+ "regex",
"serde",
"test_server",
"tokio",
diff --git a/cli/args/flags.rs b/cli/args/flags.rs
index dca9cfa49..9de1c6057 100644
--- a/cli/args/flags.rs
+++ b/cli/args/flags.rs
@@ -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]
diff --git a/cli/args/mod.rs b/cli/args/mod.rs
index 0a0f7d704..b3d508e18 100644
--- a/cli/args/mod.rs
+++ b/cli/args/mod.rs
@@ -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 {
diff --git a/cli/worker.rs b/cli/worker.rs
index 151a4ec4f..bfdeb3568 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -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,
diff --git a/runtime/worker_bootstrap.rs b/runtime/worker_bootstrap.rs
index e1abf87fc..0838da2d1 100644
--- a/runtime/worker_bootstrap.rs
+++ b/runtime/worker_bootstrap.rs
@@ -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(),
);
diff --git a/tests/Cargo.toml b/tests/Cargo.toml
index fa633f607..af220aae7 100644
--- a/tests/Cargo.toml
+++ b/tests/Cargo.toml
@@ -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
diff --git a/tests/integration/mod.rs b/tests/integration/mod.rs
index 59bf0db37..d35fabc02 100644
--- a/tests/integration/mod.rs
+++ b/tests/integration/mod.rs
@@ -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"]
diff --git a/tests/integration/serve_tests.rs b/tests/integration/serve_tests.rs
new file mode 100644
index 000000000..92b0576ed
--- /dev/null
+++ b/tests/integration/serve_tests.rs
@@ -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();
+}
diff --git a/tests/testdata/serve.ts b/tests/testdata/serve.ts
new file mode 100644
index 000000000..cdd8476eb
--- /dev/null
+++ b/tests/testdata/serve.ts
@@ -0,0 +1,5 @@
+export default {
+ fetch(_req: Request) {
+ return new Response("deno serve --port 0 works!");
+ },
+};