summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2022-08-24 16:38:51 +0200
committerGitHub <noreply@github.com>2022-08-24 16:38:51 +0200
commita4cc09447e73d27b15201e7240fa056f06e34b9f (patch)
tree630e06ce3228a7b8a413afd7555764d9a437cb06
parent5268fa0e0f34571f0fc615eb665747863aca311e (diff)
fix(unstable): Deno.serve() can parse hostnames (#15579)
-rw-r--r--cli/tests/unit/flash_test.ts31
-rw-r--r--ext/flash/lib.rs33
2 files changed, 49 insertions, 15 deletions
diff --git a/cli/tests/unit/flash_test.ts b/cli/tests/unit/flash_test.ts
index c718c1b2e..89e91fd7a 100644
--- a/cli/tests/unit/flash_test.ts
+++ b/cli/tests/unit/flash_test.ts
@@ -34,16 +34,27 @@ function onListen<T>(
};
}
-Deno.test(async function httpServerInvalidHostname() {
- await assertRejects(
- () =>
- Deno.serve({
- handler: (_req) => new Response("ok"),
- hostname: "localhost",
- }),
- TypeError,
- "hostname could not be parsed as an IP address",
- );
+Deno.test(async function httpServerCanResolveHostnames() {
+ const ac = new AbortController();
+ const listeningPromise = deferred();
+
+ const server = Deno.serve({
+ handler: (_req) => new Response("ok"),
+ hostname: "localhost",
+ port: 4501,
+ signal: ac.signal,
+ onListen: onListen(listeningPromise),
+ onError: createOnErrorCb(ac),
+ });
+
+ await listeningPromise;
+ const resp = await fetch("http://localhost:4501/", {
+ headers: { "connection": "close" },
+ });
+ const text = await resp.text();
+ assertEquals(text, "ok");
+ ac.abort();
+ await server;
});
Deno.test({ permissions: { net: true } }, async function httpServerBasic() {
diff --git a/ext/flash/lib.rs b/ext/flash/lib.rs
index 5d6275155..2c76c450f 100644
--- a/ext/flash/lib.rs
+++ b/ext/flash/lib.rs
@@ -4,6 +4,7 @@
// https://github.com/rust-lang/rust-clippy/issues/6446
#![allow(clippy::await_holding_lock)]
+use deno_core::error::generic_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op;
@@ -47,6 +48,7 @@ use std::io::Write;
use std::marker::PhantomPinned;
use std::mem::replace;
use std::net::SocketAddr;
+use std::net::ToSocketAddrs;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
@@ -1232,6 +1234,28 @@ fn run_server(
Ok(())
}
+fn make_addr_port_pair(hostname: &str, port: u16) -> (&str, u16) {
+ // Default to localhost if given just the port. Example: ":80"
+ if hostname.is_empty() {
+ return ("0.0.0.0", port);
+ }
+
+ // If this looks like an ipv6 IP address. Example: "[2001:db8::1]"
+ // Then we remove the brackets.
+ let addr = hostname.trim_start_matches('[').trim_end_matches(']');
+ (addr, port)
+}
+
+/// Resolve network address *synchronously*.
+pub fn resolve_addr_sync(
+ hostname: &str,
+ port: u16,
+) -> Result<impl Iterator<Item = SocketAddr>, AnyError> {
+ let addr_port_pair = make_addr_port_pair(hostname, port);
+ let result = addr_port_pair.to_socket_addrs()?;
+ Ok(result)
+}
+
#[op]
fn op_flash_serve<P>(
state: &mut OpState,
@@ -1244,11 +1268,10 @@ where
state
.borrow_mut::<P>()
.check_net(&(&opts.hostname, Some(opts.port)))?;
- let parsed_hostname = opts
- .hostname
- .parse()
- .map_err(|_| type_error("hostname could not be parsed as an IP address"))?;
- let addr = SocketAddr::new(parsed_hostname, opts.port);
+
+ let addr = resolve_addr_sync(&opts.hostname, opts.port)?
+ .next()
+ .ok_or_else(|| generic_error("No resolved address found"))?;
let (tx, rx) = mpsc::channel(100);
let (close_tx, close_rx) = mpsc::channel(1);
let (listening_tx, listening_rx) = mpsc::channel(1);