1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

refactor(ext/net): use concrete error type (#26227)

This commit is contained in:
Leo Kettmeir 2024-10-17 09:43:04 -07:00 committed by GitHub
parent 3b62e05062
commit ed13efc4ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 317 additions and 191 deletions

13
Cargo.lock generated
View file

@ -1423,9 +1423,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_core" name = "deno_core"
version = "0.313.0" version = "0.314.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29f36be738d78e39b6603a6b07f1cf91e28baf3681f87205f07482999e0d0bc2" checksum = "1fcd11ab87426c611b7170138a768dad7170c8fb66d8095b773d25e58fd254ea"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1797,6 +1797,7 @@ dependencies = [
"rustls-tokio-stream", "rustls-tokio-stream",
"serde", "serde",
"socket2", "socket2",
"thiserror",
"tokio", "tokio",
"trust-dns-proto", "trust-dns-proto",
"trust-dns-resolver", "trust-dns-resolver",
@ -1913,9 +1914,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_ops" name = "deno_ops"
version = "0.189.0" version = "0.190.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8f998ad1d5b36064109367ffe67b1088385eb3d8025efc95e445bc013a147a2" checksum = "a48a3e06cace18a2c49e148da067678c6af80e70757a8c3991301397cf6b9919"
dependencies = [ dependencies = [
"proc-macro-rules", "proc-macro-rules",
"proc-macro2", "proc-macro2",
@ -6211,9 +6212,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_v8" name = "serde_v8"
version = "0.222.0" version = "0.223.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27130b5cd87f6f06228940a1f3a7ecc988ea13d1bede1398a48d74cb59dabc9a" checksum = "c127bb9f2024433d06789b242477c808fd7f7dc4c3278576dd5bc99c4e5c75ff"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"serde", "serde",

View file

@ -46,7 +46,7 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies] [workspace.dependencies]
deno_ast = { version = "=0.42.2", features = ["transpiling"] } deno_ast = { version = "=0.42.2", features = ["transpiling"] }
deno_core = { version = "0.313.0" } deno_core = { version = "0.314.1" }
deno_bench_util = { version = "0.166.0", path = "./bench_util" } deno_bench_util = { version = "0.166.0", path = "./bench_util" }
deno_lockfile = "=0.23.1" deno_lockfile = "=0.23.1"

2
ext/cache/lib.rs vendored
View file

@ -28,7 +28,7 @@ pub enum CacheError {
Resource(deno_core::error::AnyError), Resource(deno_core::error::AnyError),
#[error(transparent)] #[error(transparent)]
Other(deno_core::error::AnyError), Other(deno_core::error::AnyError),
#[error(transparent)] #[error("{0}")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
} }

View file

@ -21,6 +21,7 @@ pin-project.workspace = true
rustls-tokio-stream.workspace = true rustls-tokio-stream.workspace = true
serde.workspace = true serde.workspace = true
socket2.workspace = true socket2.workspace = true
thiserror.workspace = true
tokio.workspace = true tokio.workspace = true
trust-dns-proto = "0.23" trust-dns-proto = "0.23"
trust-dns-resolver = { version = "0.23", features = ["tokio-runtime", "serde-config"] } trust-dns-resolver = { version = "0.23", features = ["tokio-runtime", "serde-config"] }

View file

@ -1,7 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::generic_error; use deno_core::futures::TryFutureExt;
use deno_core::error::AnyError;
use deno_core::AsyncMutFuture; use deno_core::AsyncMutFuture;
use deno_core::AsyncRefCell; use deno_core::AsyncRefCell;
use deno_core::AsyncResult; use deno_core::AsyncResult;
@ -69,25 +68,36 @@ where
pub async fn read( pub async fn read(
self: Rc<Self>, self: Rc<Self>,
data: &mut [u8], data: &mut [u8],
) -> Result<usize, AnyError> { ) -> Result<usize, std::io::Error> {
let mut rd = self.rd_borrow_mut().await; let mut rd = self.rd_borrow_mut().await;
let nread = rd.read(data).try_or_cancel(self.cancel_handle()).await?; let nread = rd.read(data).try_or_cancel(self.cancel_handle()).await?;
Ok(nread) Ok(nread)
} }
pub async fn write(self: Rc<Self>, data: &[u8]) -> Result<usize, AnyError> { pub async fn write(
self: Rc<Self>,
data: &[u8],
) -> Result<usize, std::io::Error> {
let mut wr = self.wr_borrow_mut().await; let mut wr = self.wr_borrow_mut().await;
let nwritten = wr.write(data).await?; let nwritten = wr.write(data).await?;
Ok(nwritten) Ok(nwritten)
} }
pub async fn shutdown(self: Rc<Self>) -> Result<(), AnyError> { pub async fn shutdown(self: Rc<Self>) -> Result<(), std::io::Error> {
let mut wr = self.wr_borrow_mut().await; let mut wr = self.wr_borrow_mut().await;
wr.shutdown().await?; wr.shutdown().await?;
Ok(()) Ok(())
} }
} }
#[derive(Debug, thiserror::Error)]
pub enum MapError {
#[error("{0}")]
Io(std::io::Error),
#[error("Unable to get resources")]
NoResources,
}
pub type TcpStreamResource = pub type TcpStreamResource =
FullDuplexResource<tcp::OwnedReadHalf, tcp::OwnedWriteHalf>; FullDuplexResource<tcp::OwnedReadHalf, tcp::OwnedWriteHalf>;
@ -100,7 +110,7 @@ impl Resource for TcpStreamResource {
} }
fn shutdown(self: Rc<Self>) -> AsyncResult<()> { fn shutdown(self: Rc<Self>) -> AsyncResult<()> {
Box::pin(self.shutdown()) Box::pin(self.shutdown().map_err(Into::into))
} }
fn close(self: Rc<Self>) { fn close(self: Rc<Self>) {
@ -109,31 +119,30 @@ impl Resource for TcpStreamResource {
} }
impl TcpStreamResource { impl TcpStreamResource {
pub fn set_nodelay(self: Rc<Self>, nodelay: bool) -> Result<(), AnyError> { pub fn set_nodelay(self: Rc<Self>, nodelay: bool) -> Result<(), MapError> {
self.map_socket(Box::new(move |socket| Ok(socket.set_nodelay(nodelay)?))) self.map_socket(Box::new(move |socket| socket.set_nodelay(nodelay)))
} }
pub fn set_keepalive( pub fn set_keepalive(
self: Rc<Self>, self: Rc<Self>,
keepalive: bool, keepalive: bool,
) -> Result<(), AnyError> { ) -> Result<(), MapError> {
self self.map_socket(Box::new(move |socket| socket.set_keepalive(keepalive)))
.map_socket(Box::new(move |socket| Ok(socket.set_keepalive(keepalive)?)))
} }
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn map_socket( fn map_socket(
self: Rc<Self>, self: Rc<Self>,
map: Box<dyn FnOnce(SockRef) -> Result<(), AnyError>>, map: Box<dyn FnOnce(SockRef) -> Result<(), std::io::Error>>,
) -> Result<(), AnyError> { ) -> Result<(), MapError> {
if let Some(wr) = RcRef::map(self, |r| &r.wr).try_borrow() { if let Some(wr) = RcRef::map(self, |r| &r.wr).try_borrow() {
let stream = wr.as_ref().as_ref(); let stream = wr.as_ref().as_ref();
let socket = socket2::SockRef::from(stream); let socket = socket2::SockRef::from(stream);
return map(socket); return map(socket).map_err(MapError::Io);
} }
Err(generic_error("Unable to get resources")) Err(MapError::NoResources)
} }
} }
@ -153,7 +162,9 @@ impl UnixStreamResource {
unreachable!() unreachable!()
} }
#[allow(clippy::unused_async)] #[allow(clippy::unused_async)]
pub async fn shutdown(self: Rc<Self>) -> Result<(), AnyError> { pub async fn shutdown(
self: Rc<Self>,
) -> Result<(), deno_core::error::AnyError> {
unreachable!() unreachable!()
} }
pub fn cancel_read_ops(&self) { pub fn cancel_read_ops(&self) {
@ -170,7 +181,7 @@ impl Resource for UnixStreamResource {
} }
fn shutdown(self: Rc<Self>) -> AsyncResult<()> { fn shutdown(self: Rc<Self>) -> AsyncResult<()> {
Box::pin(self.shutdown()) Box::pin(self.shutdown().map_err(Into::into))
} }
fn close(self: Rc<Self>) { fn close(self: Rc<Self>) {

View file

@ -6,10 +6,6 @@ use crate::resolve_addr::resolve_addr;
use crate::resolve_addr::resolve_addr_sync; use crate::resolve_addr::resolve_addr_sync;
use crate::tcp::TcpListener; use crate::tcp::TcpListener;
use crate::NetPermissions; use crate::NetPermissions;
use deno_core::error::bad_resource;
use deno_core::error::custom_error;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::op2; use deno_core::op2;
use deno_core::CancelFuture; use deno_core::CancelFuture;
@ -43,6 +39,7 @@ use trust_dns_proto::rr::record_type::RecordType;
use trust_dns_resolver::config::NameServerConfigGroup; use trust_dns_resolver::config::NameServerConfigGroup;
use trust_dns_resolver::config::ResolverConfig; use trust_dns_resolver::config::ResolverConfig;
use trust_dns_resolver::config::ResolverOpts; use trust_dns_resolver::config::ResolverOpts;
use trust_dns_resolver::error::ResolveError;
use trust_dns_resolver::error::ResolveErrorKind; use trust_dns_resolver::error::ResolveErrorKind;
use trust_dns_resolver::system_conf; use trust_dns_resolver::system_conf;
use trust_dns_resolver::AsyncResolver; use trust_dns_resolver::AsyncResolver;
@ -68,11 +65,69 @@ impl From<SocketAddr> for IpAddr {
} }
} }
pub(crate) fn accept_err(e: std::io::Error) -> AnyError { #[derive(Debug, thiserror::Error)]
pub enum NetError {
#[error("Listener has been closed")]
ListenerClosed,
#[error("Listener already in use")]
ListenerBusy,
#[error("Socket has been closed")]
SocketClosed,
#[error("Socket has been closed")]
SocketClosedNotConnected,
#[error("Socket already in use")]
SocketBusy,
#[error("{0}")]
Io(#[from] std::io::Error),
#[error("Another accept task is ongoing")]
AcceptTaskOngoing,
#[error("{0}")]
Permission(deno_core::error::AnyError),
#[error("{0}")]
Resource(deno_core::error::AnyError),
#[error("No resolved address found")]
NoResolvedAddress,
#[error("{0}")]
AddrParse(#[from] std::net::AddrParseError),
#[error("{0}")]
Map(crate::io::MapError),
#[error("{0}")]
Canceled(#[from] deno_core::Canceled),
#[error("{0}")]
DnsNotFound(ResolveError),
#[error("{0}")]
DnsNotConnected(ResolveError),
#[error("{0}")]
DnsTimedOut(ResolveError),
#[error("{0}")]
Dns(#[from] ResolveError),
#[error("Provided record type is not supported")]
UnsupportedRecordType,
#[error("File name or path {0:?} is not valid UTF-8")]
InvalidUtf8(std::ffi::OsString),
#[error("unexpected key type")]
UnexpectedKeyType,
#[error("Invalid hostname: '{0}'")]
InvalidHostname(String), // TypeError
#[error("TCP stream is currently in use")]
TcpStreamBusy,
#[error("{0}")]
Rustls(#[from] deno_tls::rustls::Error),
#[error("{0}")]
Tls(#[from] deno_tls::TlsError),
#[error("Error creating TLS certificate: Deno.listenTls requires a key")]
ListenTlsRequiresKey, // InvalidData
#[error("{0}")]
RootCertStore(deno_core::anyhow::Error),
#[error("{0}")]
Reunite(tokio::net::tcp::ReuniteError),
}
pub(crate) fn accept_err(e: std::io::Error) -> NetError {
if let std::io::ErrorKind::Interrupted = e.kind() { if let std::io::ErrorKind::Interrupted = e.kind() {
bad_resource("Listener has been closed") NetError::ListenerClosed
} else { } else {
e.into() NetError::Io(e)
} }
} }
@ -81,15 +136,15 @@ pub(crate) fn accept_err(e: std::io::Error) -> AnyError {
pub async fn op_net_accept_tcp( pub async fn op_net_accept_tcp(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
) -> Result<(ResourceId, IpAddr, IpAddr), AnyError> { ) -> Result<(ResourceId, IpAddr, IpAddr), NetError> {
let resource = state let resource = state
.borrow() .borrow()
.resource_table .resource_table
.get::<NetworkListenerResource<TcpListener>>(rid) .get::<NetworkListenerResource<TcpListener>>(rid)
.map_err(|_| bad_resource("Listener has been closed"))?; .map_err(|_| NetError::ListenerClosed)?;
let listener = RcRef::map(&resource, |r| &r.listener) let listener = RcRef::map(&resource, |r| &r.listener)
.try_borrow_mut() .try_borrow_mut()
.ok_or_else(|| custom_error("Busy", "Another accept task is ongoing"))?; .ok_or_else(|| NetError::AcceptTaskOngoing)?;
let cancel = RcRef::map(resource, |r| &r.cancel); let cancel = RcRef::map(resource, |r| &r.cancel);
let (tcp_stream, _socket_addr) = listener let (tcp_stream, _socket_addr) = listener
.accept() .accept()
@ -112,12 +167,12 @@ pub async fn op_net_recv_udp(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
#[buffer] mut buf: JsBuffer, #[buffer] mut buf: JsBuffer,
) -> Result<(usize, IpAddr), AnyError> { ) -> Result<(usize, IpAddr), NetError> {
let resource = state let resource = state
.borrow_mut() .borrow_mut()
.resource_table .resource_table
.get::<UdpSocketResource>(rid) .get::<UdpSocketResource>(rid)
.map_err(|_| bad_resource("Socket has been closed"))?; .map_err(|_| NetError::SocketClosed)?;
let socket = RcRef::map(&resource, |r| &r.socket).borrow().await; let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
let cancel_handle = RcRef::map(&resource, |r| &r.cancel); let cancel_handle = RcRef::map(&resource, |r| &r.cancel);
let (nread, remote_addr) = socket let (nread, remote_addr) = socket
@ -134,27 +189,29 @@ pub async fn op_net_send_udp<NP>(
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
#[serde] addr: IpAddr, #[serde] addr: IpAddr,
#[buffer] zero_copy: JsBuffer, #[buffer] zero_copy: JsBuffer,
) -> Result<usize, AnyError> ) -> Result<usize, NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
{ {
let mut s = state.borrow_mut(); let mut s = state.borrow_mut();
s.borrow_mut::<NP>().check_net( s.borrow_mut::<NP>()
&(&addr.hostname, Some(addr.port)), .check_net(
"Deno.DatagramConn.send()", &(&addr.hostname, Some(addr.port)),
)?; "Deno.DatagramConn.send()",
)
.map_err(NetError::Permission)?;
} }
let addr = resolve_addr(&addr.hostname, addr.port) let addr = resolve_addr(&addr.hostname, addr.port)
.await? .await?
.next() .next()
.ok_or_else(|| generic_error("No resolved address found"))?; .ok_or(NetError::NoResolvedAddress)?;
let resource = state let resource = state
.borrow_mut() .borrow_mut()
.resource_table .resource_table
.get::<UdpSocketResource>(rid) .get::<UdpSocketResource>(rid)
.map_err(|_| bad_resource("Socket has been closed"))?; .map_err(|_| NetError::SocketClosed)?;
let socket = RcRef::map(&resource, |r| &r.socket).borrow().await; let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
let nwritten = socket.send_to(&zero_copy, &addr).await?; let nwritten = socket.send_to(&zero_copy, &addr).await?;
@ -167,12 +224,12 @@ pub async fn op_net_join_multi_v4_udp(
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
#[string] address: String, #[string] address: String,
#[string] multi_interface: String, #[string] multi_interface: String,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
let resource = state let resource = state
.borrow_mut() .borrow_mut()
.resource_table .resource_table
.get::<UdpSocketResource>(rid) .get::<UdpSocketResource>(rid)
.map_err(|_| bad_resource("Socket has been closed"))?; .map_err(|_| NetError::SocketClosed)?;
let socket = RcRef::map(&resource, |r| &r.socket).borrow().await; let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
let addr = Ipv4Addr::from_str(address.as_str())?; let addr = Ipv4Addr::from_str(address.as_str())?;
@ -189,12 +246,12 @@ pub async fn op_net_join_multi_v6_udp(
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
#[string] address: String, #[string] address: String,
#[smi] multi_interface: u32, #[smi] multi_interface: u32,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
let resource = state let resource = state
.borrow_mut() .borrow_mut()
.resource_table .resource_table
.get::<UdpSocketResource>(rid) .get::<UdpSocketResource>(rid)
.map_err(|_| bad_resource("Socket has been closed"))?; .map_err(|_| NetError::SocketClosed)?;
let socket = RcRef::map(&resource, |r| &r.socket).borrow().await; let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
let addr = Ipv6Addr::from_str(address.as_str())?; let addr = Ipv6Addr::from_str(address.as_str())?;
@ -210,12 +267,12 @@ pub async fn op_net_leave_multi_v4_udp(
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
#[string] address: String, #[string] address: String,
#[string] multi_interface: String, #[string] multi_interface: String,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
let resource = state let resource = state
.borrow_mut() .borrow_mut()
.resource_table .resource_table
.get::<UdpSocketResource>(rid) .get::<UdpSocketResource>(rid)
.map_err(|_| bad_resource("Socket has been closed"))?; .map_err(|_| NetError::SocketClosed)?;
let socket = RcRef::map(&resource, |r| &r.socket).borrow().await; let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
let addr = Ipv4Addr::from_str(address.as_str())?; let addr = Ipv4Addr::from_str(address.as_str())?;
@ -232,12 +289,12 @@ pub async fn op_net_leave_multi_v6_udp(
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
#[string] address: String, #[string] address: String,
#[smi] multi_interface: u32, #[smi] multi_interface: u32,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
let resource = state let resource = state
.borrow_mut() .borrow_mut()
.resource_table .resource_table
.get::<UdpSocketResource>(rid) .get::<UdpSocketResource>(rid)
.map_err(|_| bad_resource("Socket has been closed"))?; .map_err(|_| NetError::SocketClosed)?;
let socket = RcRef::map(&resource, |r| &r.socket).borrow().await; let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
let addr = Ipv6Addr::from_str(address.as_str())?; let addr = Ipv6Addr::from_str(address.as_str())?;
@ -253,16 +310,16 @@ pub async fn op_net_set_multi_loopback_udp(
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
is_v4_membership: bool, is_v4_membership: bool,
loopback: bool, loopback: bool,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
let resource = state let resource = state
.borrow_mut() .borrow_mut()
.resource_table .resource_table
.get::<UdpSocketResource>(rid) .get::<UdpSocketResource>(rid)
.map_err(|_| bad_resource("Socket has been closed"))?; .map_err(|_| NetError::SocketClosed)?;
let socket = RcRef::map(&resource, |r| &r.socket).borrow().await; let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
if is_v4_membership { if is_v4_membership {
socket.set_multicast_loop_v4(loopback)? socket.set_multicast_loop_v4(loopback)?;
} else { } else {
socket.set_multicast_loop_v6(loopback)?; socket.set_multicast_loop_v6(loopback)?;
} }
@ -275,12 +332,12 @@ pub async fn op_net_set_multi_ttl_udp(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
#[smi] ttl: u32, #[smi] ttl: u32,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
let resource = state let resource = state
.borrow_mut() .borrow_mut()
.resource_table .resource_table
.get::<UdpSocketResource>(rid) .get::<UdpSocketResource>(rid)
.map_err(|_| bad_resource("Socket has been closed"))?; .map_err(|_| NetError::SocketClosed)?;
let socket = RcRef::map(&resource, |r| &r.socket).borrow().await; let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
socket.set_multicast_ttl_v4(ttl)?; socket.set_multicast_ttl_v4(ttl)?;
@ -293,7 +350,7 @@ pub async fn op_net_set_multi_ttl_udp(
pub async fn op_net_connect_tcp<NP>( pub async fn op_net_connect_tcp<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[serde] addr: IpAddr, #[serde] addr: IpAddr,
) -> Result<(ResourceId, IpAddr, IpAddr), AnyError> ) -> Result<(ResourceId, IpAddr, IpAddr), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -304,7 +361,7 @@ where
pub async fn op_net_connect_tcp_inner<NP>( pub async fn op_net_connect_tcp_inner<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
addr: IpAddr, addr: IpAddr,
) -> Result<(ResourceId, IpAddr, IpAddr), AnyError> ) -> Result<(ResourceId, IpAddr, IpAddr), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -312,13 +369,14 @@ where
let mut state_ = state.borrow_mut(); let mut state_ = state.borrow_mut();
state_ state_
.borrow_mut::<NP>() .borrow_mut::<NP>()
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.connect()")?; .check_net(&(&addr.hostname, Some(addr.port)), "Deno.connect()")
.map_err(NetError::Permission)?;
} }
let addr = resolve_addr(&addr.hostname, addr.port) let addr = resolve_addr(&addr.hostname, addr.port)
.await? .await?
.next() .next()
.ok_or_else(|| generic_error("No resolved address found"))?; .ok_or_else(|| NetError::NoResolvedAddress)?;
let tcp_stream = TcpStream::connect(&addr).await?; let tcp_stream = TcpStream::connect(&addr).await?;
let local_addr = tcp_stream.local_addr()?; let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?; let remote_addr = tcp_stream.peer_addr()?;
@ -353,7 +411,7 @@ pub fn op_net_listen_tcp<NP>(
#[serde] addr: IpAddr, #[serde] addr: IpAddr,
reuse_port: bool, reuse_port: bool,
load_balanced: bool, load_balanced: bool,
) -> Result<(ResourceId, IpAddr), AnyError> ) -> Result<(ResourceId, IpAddr), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -362,10 +420,11 @@ where
} }
state state
.borrow_mut::<NP>() .borrow_mut::<NP>()
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.listen()")?; .check_net(&(&addr.hostname, Some(addr.port)), "Deno.listen()")
.map_err(NetError::Permission)?;
let addr = resolve_addr_sync(&addr.hostname, addr.port)? let addr = resolve_addr_sync(&addr.hostname, addr.port)?
.next() .next()
.ok_or_else(|| generic_error("No resolved address found"))?; .ok_or_else(|| NetError::NoResolvedAddress)?;
let listener = if load_balanced { let listener = if load_balanced {
TcpListener::bind_load_balanced(addr) TcpListener::bind_load_balanced(addr)
@ -384,16 +443,17 @@ fn net_listen_udp<NP>(
addr: IpAddr, addr: IpAddr,
reuse_address: bool, reuse_address: bool,
loopback: bool, loopback: bool,
) -> Result<(ResourceId, IpAddr), AnyError> ) -> Result<(ResourceId, IpAddr), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
state state
.borrow_mut::<NP>() .borrow_mut::<NP>()
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenDatagram()")?; .check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenDatagram()")
.map_err(NetError::Permission)?;
let addr = resolve_addr_sync(&addr.hostname, addr.port)? let addr = resolve_addr_sync(&addr.hostname, addr.port)?
.next() .next()
.ok_or_else(|| generic_error("No resolved address found"))?; .ok_or_else(|| NetError::NoResolvedAddress)?;
let domain = if addr.is_ipv4() { let domain = if addr.is_ipv4() {
Domain::IPV4 Domain::IPV4
@ -453,7 +513,7 @@ pub fn op_net_listen_udp<NP>(
#[serde] addr: IpAddr, #[serde] addr: IpAddr,
reuse_address: bool, reuse_address: bool,
loopback: bool, loopback: bool,
) -> Result<(ResourceId, IpAddr), AnyError> ) -> Result<(ResourceId, IpAddr), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -468,7 +528,7 @@ pub fn op_node_unstable_net_listen_udp<NP>(
#[serde] addr: IpAddr, #[serde] addr: IpAddr,
reuse_address: bool, reuse_address: bool,
loopback: bool, loopback: bool,
) -> Result<(ResourceId, IpAddr), AnyError> ) -> Result<(ResourceId, IpAddr), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -551,7 +611,7 @@ pub struct NameServer {
pub async fn op_dns_resolve<NP>( pub async fn op_dns_resolve<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[serde] args: ResolveAddrArgs, #[serde] args: ResolveAddrArgs,
) -> Result<Vec<DnsReturnRecord>, AnyError> ) -> Result<Vec<DnsReturnRecord>, NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -587,7 +647,9 @@ where
let socker_addr = &ns.socket_addr; let socker_addr = &ns.socket_addr;
let ip = socker_addr.ip().to_string(); let ip = socker_addr.ip().to_string();
let port = socker_addr.port(); let port = socker_addr.port();
perm.check_net(&(ip, Some(port)), "Deno.resolveDns()")?; perm
.check_net(&(ip, Some(port)), "Deno.resolveDns()")
.map_err(NetError::Permission)?;
} }
} }
@ -618,22 +680,17 @@ where
}; };
lookup lookup
.map_err(|e| { .map_err(|e| match e.kind() {
let message = format!("{e}"); ResolveErrorKind::NoRecordsFound { .. } => NetError::DnsNotFound(e),
match e.kind() { ResolveErrorKind::Message("No connections available") => {
ResolveErrorKind::NoRecordsFound { .. } => { NetError::DnsNotConnected(e)
custom_error("NotFound", message)
}
ResolveErrorKind::Message("No connections available") => {
custom_error("NotConnected", message)
}
ResolveErrorKind::Timeout => custom_error("TimedOut", message),
_ => generic_error(message),
} }
ResolveErrorKind::Timeout => NetError::DnsTimedOut(e),
_ => NetError::Dns(e),
})? })?
.iter() .iter()
.filter_map(|rdata| rdata_to_return_record(record_type)(rdata).transpose()) .filter_map(|rdata| rdata_to_return_record(record_type)(rdata).transpose())
.collect::<Result<Vec<DnsReturnRecord>, AnyError>>() .collect::<Result<Vec<DnsReturnRecord>, NetError>>()
} }
#[op2(fast)] #[op2(fast)]
@ -641,7 +698,7 @@ pub fn op_set_nodelay(
state: &mut OpState, state: &mut OpState,
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
nodelay: bool, nodelay: bool,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
op_set_nodelay_inner(state, rid, nodelay) op_set_nodelay_inner(state, rid, nodelay)
} }
@ -650,10 +707,12 @@ pub fn op_set_nodelay_inner(
state: &mut OpState, state: &mut OpState,
rid: ResourceId, rid: ResourceId,
nodelay: bool, nodelay: bool,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
let resource: Rc<TcpStreamResource> = let resource: Rc<TcpStreamResource> = state
state.resource_table.get::<TcpStreamResource>(rid)?; .resource_table
resource.set_nodelay(nodelay) .get::<TcpStreamResource>(rid)
.map_err(NetError::Resource)?;
resource.set_nodelay(nodelay).map_err(NetError::Map)
} }
#[op2(fast)] #[op2(fast)]
@ -661,7 +720,7 @@ pub fn op_set_keepalive(
state: &mut OpState, state: &mut OpState,
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
keepalive: bool, keepalive: bool,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
op_set_keepalive_inner(state, rid, keepalive) op_set_keepalive_inner(state, rid, keepalive)
} }
@ -670,17 +729,19 @@ pub fn op_set_keepalive_inner(
state: &mut OpState, state: &mut OpState,
rid: ResourceId, rid: ResourceId,
keepalive: bool, keepalive: bool,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
let resource: Rc<TcpStreamResource> = let resource: Rc<TcpStreamResource> = state
state.resource_table.get::<TcpStreamResource>(rid)?; .resource_table
resource.set_keepalive(keepalive) .get::<TcpStreamResource>(rid)
.map_err(NetError::Resource)?;
resource.set_keepalive(keepalive).map_err(NetError::Map)
} }
fn rdata_to_return_record( fn rdata_to_return_record(
ty: RecordType, ty: RecordType,
) -> impl Fn(&RData) -> Result<Option<DnsReturnRecord>, AnyError> { ) -> impl Fn(&RData) -> Result<Option<DnsReturnRecord>, NetError> {
use RecordType::*; use RecordType::*;
move |r: &RData| -> Result<Option<DnsReturnRecord>, AnyError> { move |r: &RData| -> Result<Option<DnsReturnRecord>, NetError> {
let record = match ty { let record = match ty {
A => r.as_a().map(ToString::to_string).map(DnsReturnRecord::A), A => r.as_a().map(ToString::to_string).map(DnsReturnRecord::A),
AAAA => r AAAA => r
@ -761,12 +822,7 @@ fn rdata_to_return_record(
.collect(); .collect();
DnsReturnRecord::Txt(texts) DnsReturnRecord::Txt(texts)
}), }),
_ => { _ => return Err(NetError::UnsupportedRecordType),
return Err(custom_error(
"NotSupported",
"Provided record type is not supported",
))
}
}; };
Ok(record) Ok(record)
} }
@ -985,7 +1041,7 @@ mod tests {
&mut self, &mut self,
_host: &(T, Option<u16>), _host: &(T, Option<u16>),
_api_name: &str, _api_name: &str,
) -> Result<(), AnyError> { ) -> Result<(), deno_core::error::AnyError> {
Ok(()) Ok(())
} }
@ -993,7 +1049,7 @@ mod tests {
&mut self, &mut self,
p: &str, p: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, deno_core::error::AnyError> {
Ok(PathBuf::from(p)) Ok(PathBuf::from(p))
} }
@ -1001,7 +1057,7 @@ mod tests {
&mut self, &mut self,
p: &str, p: &str,
_api_name: &str, _api_name: &str,
) -> Result<PathBuf, AnyError> { ) -> Result<PathBuf, deno_core::error::AnyError> {
Ok(PathBuf::from(p)) Ok(PathBuf::from(p))
} }
@ -1009,7 +1065,7 @@ mod tests {
&mut self, &mut self,
p: &'a Path, p: &'a Path,
_api_name: &str, _api_name: &str,
) -> Result<Cow<'a, Path>, AnyError> { ) -> Result<Cow<'a, Path>, deno_core::error::AnyError> {
Ok(Cow::Borrowed(p)) Ok(Cow::Borrowed(p))
} }
} }
@ -1091,7 +1147,7 @@ mod tests {
let vals = result.unwrap(); let vals = result.unwrap();
rid = rid.or(Some(vals.0)); rid = rid.or(Some(vals.0));
} }
}; }
let rid = rid.unwrap(); let rid = rid.unwrap();
let state = runtime.op_state(); let state = runtime.op_state();

View file

@ -2,6 +2,7 @@
use crate::io::TcpStreamResource; use crate::io::TcpStreamResource;
use crate::ops::IpAddr; use crate::ops::IpAddr;
use crate::ops::NetError;
use crate::ops::TlsHandshakeInfo; use crate::ops::TlsHandshakeInfo;
use crate::raw::NetworkListenerResource; use crate::raw::NetworkListenerResource;
use crate::resolve_addr::resolve_addr; use crate::resolve_addr::resolve_addr;
@ -10,13 +11,7 @@ use crate::tcp::TcpListener;
use crate::DefaultTlsOptions; use crate::DefaultTlsOptions;
use crate::NetPermissions; use crate::NetPermissions;
use crate::UnsafelyIgnoreCertificateErrors; use crate::UnsafelyIgnoreCertificateErrors;
use deno_core::anyhow::anyhow; use deno_core::futures::TryFutureExt;
use deno_core::anyhow::bail;
use deno_core::error::bad_resource;
use deno_core::error::custom_error;
use deno_core::error::generic_error;
use deno_core::error::invalid_hostname;
use deno_core::error::AnyError;
use deno_core::op2; use deno_core::op2;
use deno_core::v8; use deno_core::v8;
use deno_core::AsyncRefCell; use deno_core::AsyncRefCell;
@ -118,20 +113,23 @@ impl TlsStreamResource {
pub async fn read( pub async fn read(
self: Rc<Self>, self: Rc<Self>,
data: &mut [u8], data: &mut [u8],
) -> Result<usize, AnyError> { ) -> Result<usize, std::io::Error> {
let mut rd = RcRef::map(&self, |r| &r.rd).borrow_mut().await; let mut rd = RcRef::map(&self, |r| &r.rd).borrow_mut().await;
let cancel_handle = RcRef::map(&self, |r| &r.cancel_handle); let cancel_handle = RcRef::map(&self, |r| &r.cancel_handle);
Ok(rd.read(data).try_or_cancel(cancel_handle).await?) rd.read(data).try_or_cancel(cancel_handle).await
} }
pub async fn write(self: Rc<Self>, data: &[u8]) -> Result<usize, AnyError> { pub async fn write(
self: Rc<Self>,
data: &[u8],
) -> Result<usize, std::io::Error> {
let mut wr = RcRef::map(self, |r| &r.wr).borrow_mut().await; let mut wr = RcRef::map(self, |r| &r.wr).borrow_mut().await;
let nwritten = wr.write(data).await?; let nwritten = wr.write(data).await?;
wr.flush().await?; wr.flush().await?;
Ok(nwritten) Ok(nwritten)
} }
pub async fn shutdown(self: Rc<Self>) -> Result<(), AnyError> { pub async fn shutdown(self: Rc<Self>) -> Result<(), std::io::Error> {
let mut wr = RcRef::map(self, |r| &r.wr).borrow_mut().await; let mut wr = RcRef::map(self, |r| &r.wr).borrow_mut().await;
wr.shutdown().await?; wr.shutdown().await?;
Ok(()) Ok(())
@ -139,7 +137,7 @@ impl TlsStreamResource {
pub async fn handshake( pub async fn handshake(
self: &Rc<Self>, self: &Rc<Self>,
) -> Result<TlsHandshakeInfo, AnyError> { ) -> Result<TlsHandshakeInfo, std::io::Error> {
if let Some(tls_info) = &*self.handshake_info.borrow() { if let Some(tls_info) = &*self.handshake_info.borrow() {
return Ok(tls_info.clone()); return Ok(tls_info.clone());
} }
@ -164,7 +162,7 @@ impl Resource for TlsStreamResource {
} }
fn shutdown(self: Rc<Self>) -> AsyncResult<()> { fn shutdown(self: Rc<Self>) -> AsyncResult<()> {
Box::pin(self.shutdown()) Box::pin(self.shutdown().map_err(Into::into))
} }
fn close(self: Rc<Self>) { fn close(self: Rc<Self>) {
@ -201,7 +199,7 @@ pub fn op_tls_key_null() -> TlsKeysHolder {
pub fn op_tls_key_static( pub fn op_tls_key_static(
#[string] cert: &str, #[string] cert: &str,
#[string] key: &str, #[string] key: &str,
) -> Result<TlsKeysHolder, AnyError> { ) -> Result<TlsKeysHolder, deno_tls::TlsError> {
let cert = load_certs(&mut BufReader::new(cert.as_bytes()))?; let cert = load_certs(&mut BufReader::new(cert.as_bytes()))?;
let key = load_private_keys(key.as_bytes())? let key = load_private_keys(key.as_bytes())?
.into_iter() .into_iter()
@ -236,9 +234,9 @@ pub fn op_tls_cert_resolver_resolve(
#[cppgc] lookup: &TlsKeyLookup, #[cppgc] lookup: &TlsKeyLookup,
#[string] sni: String, #[string] sni: String,
#[cppgc] key: &TlsKeysHolder, #[cppgc] key: &TlsKeysHolder,
) -> Result<(), AnyError> { ) -> Result<(), NetError> {
let TlsKeys::Static(key) = key.take() else { let TlsKeys::Static(key) = key.take() else {
bail!("unexpected key type"); return Err(NetError::UnexpectedKeyType);
}; };
lookup.resolve(sni, Ok(key)); lookup.resolve(sni, Ok(key));
Ok(()) Ok(())
@ -258,7 +256,7 @@ pub fn op_tls_cert_resolver_resolve_error(
pub fn op_tls_start<NP>( pub fn op_tls_start<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[serde] args: StartTlsArgs, #[serde] args: StartTlsArgs,
) -> Result<(ResourceId, IpAddr, IpAddr), AnyError> ) -> Result<(ResourceId, IpAddr, IpAddr), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -271,7 +269,9 @@ where
{ {
let mut s = state.borrow_mut(); let mut s = state.borrow_mut();
let permissions = s.borrow_mut::<NP>(); let permissions = s.borrow_mut::<NP>();
permissions.check_net(&(&hostname, Some(0)), "Deno.startTls()")?; permissions
.check_net(&(&hostname, Some(0)), "Deno.startTls()")
.map_err(NetError::Permission)?;
} }
let ca_certs = args let ca_certs = args
@ -281,7 +281,7 @@ where
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let hostname_dns = ServerName::try_from(hostname.to_string()) let hostname_dns = ServerName::try_from(hostname.to_string())
.map_err(|_| invalid_hostname(&hostname))?; .map_err(|_| NetError::InvalidHostname(hostname))?;
let unsafely_ignore_certificate_errors = state let unsafely_ignore_certificate_errors = state
.borrow() .borrow()
@ -291,19 +291,21 @@ where
let root_cert_store = state let root_cert_store = state
.borrow() .borrow()
.borrow::<DefaultTlsOptions>() .borrow::<DefaultTlsOptions>()
.root_cert_store()?; .root_cert_store()
.map_err(NetError::RootCertStore)?;
let resource_rc = state let resource_rc = state
.borrow_mut() .borrow_mut()
.resource_table .resource_table
.take::<TcpStreamResource>(rid)?; .take::<TcpStreamResource>(rid)
.map_err(NetError::Resource)?;
// This TCP connection might be used somewhere else. If it's the case, we cannot proceed with the // This TCP connection might be used somewhere else. If it's the case, we cannot proceed with the
// process of starting a TLS connection on top of this TCP connection, so we just return a Busy error. // process of starting a TLS connection on top of this TCP connection, so we just return a Busy error.
// See also: https://github.com/denoland/deno/pull/16242 // See also: https://github.com/denoland/deno/pull/16242
let resource = Rc::try_unwrap(resource_rc) let resource =
.map_err(|_| custom_error("Busy", "TCP stream is currently in use"))?; Rc::try_unwrap(resource_rc).map_err(|_| NetError::TcpStreamBusy)?;
let (read_half, write_half) = resource.into_inner(); let (read_half, write_half) = resource.into_inner();
let tcp_stream = read_half.reunite(write_half)?; let tcp_stream = read_half.reunite(write_half).map_err(NetError::Reunite)?;
let local_addr = tcp_stream.local_addr()?; let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?; let remote_addr = tcp_stream.peer_addr()?;
@ -345,7 +347,7 @@ pub async fn op_net_connect_tls<NP>(
#[serde] addr: IpAddr, #[serde] addr: IpAddr,
#[serde] args: ConnectTlsArgs, #[serde] args: ConnectTlsArgs,
#[cppgc] key_pair: &TlsKeysHolder, #[cppgc] key_pair: &TlsKeysHolder,
) -> Result<(ResourceId, IpAddr, IpAddr), AnyError> ) -> Result<(ResourceId, IpAddr, IpAddr), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -359,9 +361,14 @@ where
let mut s = state.borrow_mut(); let mut s = state.borrow_mut();
let permissions = s.borrow_mut::<NP>(); let permissions = s.borrow_mut::<NP>();
permissions permissions
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.connectTls()")?; .check_net(&(&addr.hostname, Some(addr.port)), "Deno.connectTls()")
.map_err(NetError::Permission)?;
if let Some(path) = cert_file { if let Some(path) = cert_file {
Some(permissions.check_read(path, "Deno.connectTls()")?) Some(
permissions
.check_read(path, "Deno.connectTls()")
.map_err(NetError::Permission)?,
)
} else { } else {
None None
} }
@ -382,17 +389,18 @@ where
let root_cert_store = state let root_cert_store = state
.borrow() .borrow()
.borrow::<DefaultTlsOptions>() .borrow::<DefaultTlsOptions>()
.root_cert_store()?; .root_cert_store()
.map_err(NetError::RootCertStore)?;
let hostname_dns = if let Some(server_name) = args.server_name { let hostname_dns = if let Some(server_name) = args.server_name {
ServerName::try_from(server_name) ServerName::try_from(server_name)
} else { } else {
ServerName::try_from(addr.hostname.clone()) ServerName::try_from(addr.hostname.clone())
} }
.map_err(|_| invalid_hostname(&addr.hostname))?; .map_err(|_| NetError::InvalidHostname(addr.hostname.clone()))?;
let connect_addr = resolve_addr(&addr.hostname, addr.port) let connect_addr = resolve_addr(&addr.hostname, addr.port)
.await? .await?
.next() .next()
.ok_or_else(|| generic_error("No resolved address found"))?; .ok_or_else(|| NetError::NoResolvedAddress)?;
let tcp_stream = TcpStream::connect(connect_addr).await?; let tcp_stream = TcpStream::connect(connect_addr).await?;
let local_addr = tcp_stream.local_addr()?; let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?; let remote_addr = tcp_stream.peer_addr()?;
@ -444,7 +452,7 @@ pub fn op_net_listen_tls<NP>(
#[serde] addr: IpAddr, #[serde] addr: IpAddr,
#[serde] args: ListenTlsArgs, #[serde] args: ListenTlsArgs,
#[cppgc] keys: &TlsKeysHolder, #[cppgc] keys: &TlsKeysHolder,
) -> Result<(ResourceId, IpAddr), AnyError> ) -> Result<(ResourceId, IpAddr), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -455,12 +463,13 @@ where
{ {
let permissions = state.borrow_mut::<NP>(); let permissions = state.borrow_mut::<NP>();
permissions permissions
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenTls()")?; .check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenTls()")
.map_err(NetError::Permission)?;
} }
let bind_addr = resolve_addr_sync(&addr.hostname, addr.port)? let bind_addr = resolve_addr_sync(&addr.hostname, addr.port)?
.next() .next()
.ok_or_else(|| generic_error("No resolved address found"))?; .ok_or(NetError::NoResolvedAddress)?;
let tcp_listener = if args.load_balanced { let tcp_listener = if args.load_balanced {
TcpListener::bind_load_balanced(bind_addr) TcpListener::bind_load_balanced(bind_addr)
@ -475,28 +484,24 @@ where
.map(|s| s.into_bytes()) .map(|s| s.into_bytes())
.collect(); .collect();
let listener = match keys.take() { let listener = match keys.take() {
TlsKeys::Null => Err(anyhow!("Deno.listenTls requires a key")), TlsKeys::Null => return Err(NetError::ListenTlsRequiresKey),
TlsKeys::Static(TlsKey(cert, key)) => { TlsKeys::Static(TlsKey(cert, key)) => {
let mut tls_config = ServerConfig::builder() let mut tls_config = ServerConfig::builder()
.with_no_client_auth() .with_no_client_auth()
.with_single_cert(cert, key) .with_single_cert(cert, key)?;
.map_err(|e| anyhow!(e))?;
tls_config.alpn_protocols = alpn; tls_config.alpn_protocols = alpn;
Ok(TlsListener { TlsListener {
tcp_listener, tcp_listener,
tls_config: Some(tls_config.into()), tls_config: Some(tls_config.into()),
server_config_provider: None, server_config_provider: None,
}) }
} }
TlsKeys::Resolver(resolver) => Ok(TlsListener { TlsKeys::Resolver(resolver) => TlsListener {
tcp_listener, tcp_listener,
tls_config: None, tls_config: None,
server_config_provider: Some(resolver.into_server_config_provider(alpn)), server_config_provider: Some(resolver.into_server_config_provider(alpn)),
}), },
} };
.map_err(|e| {
custom_error("InvalidData", "Error creating TLS certificate").context(e)
})?;
let tls_listener_resource = NetworkListenerResource::new(listener); let tls_listener_resource = NetworkListenerResource::new(listener);
@ -510,23 +515,23 @@ where
pub async fn op_net_accept_tls( pub async fn op_net_accept_tls(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
) -> Result<(ResourceId, IpAddr, IpAddr), AnyError> { ) -> Result<(ResourceId, IpAddr, IpAddr), NetError> {
let resource = state let resource = state
.borrow() .borrow()
.resource_table .resource_table
.get::<NetworkListenerResource<TlsListener>>(rid) .get::<NetworkListenerResource<TlsListener>>(rid)
.map_err(|_| bad_resource("Listener has been closed"))?; .map_err(|_| NetError::ListenerClosed)?;
let cancel_handle = RcRef::map(&resource, |r| &r.cancel); let cancel_handle = RcRef::map(&resource, |r| &r.cancel);
let listener = RcRef::map(&resource, |r| &r.listener) let listener = RcRef::map(&resource, |r| &r.listener)
.try_borrow_mut() .try_borrow_mut()
.ok_or_else(|| custom_error("Busy", "Another accept task is ongoing"))?; .ok_or_else(|| NetError::AcceptTaskOngoing)?;
let (tls_stream, remote_addr) = let (tls_stream, remote_addr) =
match listener.accept().try_or_cancel(&cancel_handle).await { match listener.accept().try_or_cancel(&cancel_handle).await {
Ok(tuple) => tuple, Ok(tuple) => tuple,
Err(err) if err.kind() == ErrorKind::Interrupted => { Err(err) if err.kind() == ErrorKind::Interrupted => {
return Err(bad_resource("Listener has been closed")); return Err(NetError::ListenerClosed);
} }
Err(err) => return Err(err.into()), Err(err) => return Err(err.into()),
}; };
@ -547,11 +552,11 @@ pub async fn op_net_accept_tls(
pub async fn op_tls_handshake( pub async fn op_tls_handshake(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
) -> Result<TlsHandshakeInfo, AnyError> { ) -> Result<TlsHandshakeInfo, NetError> {
let resource = state let resource = state
.borrow() .borrow()
.resource_table .resource_table
.get::<TlsStreamResource>(rid) .get::<TlsStreamResource>(rid)
.map_err(|_| bad_resource("Listener has been closed"))?; .map_err(|_| NetError::ListenerClosed)?;
resource.handshake().await resource.handshake().await.map_err(Into::into)
} }

View file

@ -1,11 +1,9 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::io::UnixStreamResource; use crate::io::UnixStreamResource;
use crate::ops::NetError;
use crate::raw::NetworkListenerResource; use crate::raw::NetworkListenerResource;
use crate::NetPermissions; use crate::NetPermissions;
use deno_core::error::bad_resource;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::op2; use deno_core::op2;
use deno_core::AsyncRefCell; use deno_core::AsyncRefCell;
use deno_core::CancelHandle; use deno_core::CancelHandle;
@ -26,11 +24,8 @@ use tokio::net::UnixListener;
pub use tokio::net::UnixStream; pub use tokio::net::UnixStream;
/// A utility function to map OsStrings to Strings /// A utility function to map OsStrings to Strings
pub fn into_string(s: std::ffi::OsString) -> Result<String, AnyError> { pub fn into_string(s: std::ffi::OsString) -> Result<String, NetError> {
s.into_string().map_err(|s| { s.into_string().map_err(NetError::InvalidUtf8)
let message = format!("File name or path {s:?} is not valid UTF-8");
custom_error("InvalidData", message)
})
} }
pub struct UnixDatagramResource { pub struct UnixDatagramResource {
@ -63,15 +58,15 @@ pub struct UnixListenArgs {
pub async fn op_net_accept_unix( pub async fn op_net_accept_unix(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
) -> Result<(ResourceId, Option<String>, Option<String>), AnyError> { ) -> Result<(ResourceId, Option<String>, Option<String>), NetError> {
let resource = state let resource = state
.borrow() .borrow()
.resource_table .resource_table
.get::<NetworkListenerResource<UnixListener>>(rid) .get::<NetworkListenerResource<UnixListener>>(rid)
.map_err(|_| bad_resource("Listener has been closed"))?; .map_err(|_| NetError::ListenerClosed)?;
let listener = RcRef::map(&resource, |r| &r.listener) let listener = RcRef::map(&resource, |r| &r.listener)
.try_borrow_mut() .try_borrow_mut()
.ok_or_else(|| custom_error("Busy", "Listener already in use"))?; .ok_or(NetError::ListenerBusy)?;
let cancel = RcRef::map(resource, |r| &r.cancel); let cancel = RcRef::map(resource, |r| &r.cancel);
let (unix_stream, _socket_addr) = listener let (unix_stream, _socket_addr) = listener
.accept() .accept()
@ -95,7 +90,7 @@ pub async fn op_net_accept_unix(
pub async fn op_net_connect_unix<NP>( pub async fn op_net_connect_unix<NP>(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[string] address_path: String, #[string] address_path: String,
) -> Result<(ResourceId, Option<String>, Option<String>), AnyError> ) -> Result<(ResourceId, Option<String>, Option<String>), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -103,10 +98,12 @@ where
let mut state_ = state.borrow_mut(); let mut state_ = state.borrow_mut();
let address_path = state_ let address_path = state_
.borrow_mut::<NP>() .borrow_mut::<NP>()
.check_read(&address_path, "Deno.connect()")?; .check_read(&address_path, "Deno.connect()")
.map_err(NetError::Permission)?;
_ = state_ _ = state_
.borrow_mut::<NP>() .borrow_mut::<NP>()
.check_write_path(&address_path, "Deno.connect()")?; .check_write_path(&address_path, "Deno.connect()")
.map_err(NetError::Permission)?;
address_path address_path
}; };
let unix_stream = UnixStream::connect(&address_path).await?; let unix_stream = UnixStream::connect(&address_path).await?;
@ -127,15 +124,15 @@ pub async fn op_net_recv_unixpacket(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
#[buffer] mut buf: JsBuffer, #[buffer] mut buf: JsBuffer,
) -> Result<(usize, Option<String>), AnyError> { ) -> Result<(usize, Option<String>), NetError> {
let resource = state let resource = state
.borrow() .borrow()
.resource_table .resource_table
.get::<UnixDatagramResource>(rid) .get::<UnixDatagramResource>(rid)
.map_err(|_| bad_resource("Socket has been closed"))?; .map_err(|_| NetError::SocketClosed)?;
let socket = RcRef::map(&resource, |r| &r.socket) let socket = RcRef::map(&resource, |r| &r.socket)
.try_borrow_mut() .try_borrow_mut()
.ok_or_else(|| custom_error("Busy", "Socket already in use"))?; .ok_or(NetError::SocketBusy)?;
let cancel = RcRef::map(resource, |r| &r.cancel); let cancel = RcRef::map(resource, |r| &r.cancel);
let (nread, remote_addr) = let (nread, remote_addr) =
socket.recv_from(&mut buf).try_or_cancel(cancel).await?; socket.recv_from(&mut buf).try_or_cancel(cancel).await?;
@ -150,24 +147,25 @@ pub async fn op_net_send_unixpacket<NP>(
#[smi] rid: ResourceId, #[smi] rid: ResourceId,
#[string] address_path: String, #[string] address_path: String,
#[buffer] zero_copy: JsBuffer, #[buffer] zero_copy: JsBuffer,
) -> Result<usize, AnyError> ) -> Result<usize, NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
let address_path = { let address_path = {
let mut s = state.borrow_mut(); let mut s = state.borrow_mut();
s.borrow_mut::<NP>() s.borrow_mut::<NP>()
.check_write(&address_path, "Deno.DatagramConn.send()")? .check_write(&address_path, "Deno.DatagramConn.send()")
.map_err(NetError::Permission)?
}; };
let resource = state let resource = state
.borrow() .borrow()
.resource_table .resource_table
.get::<UnixDatagramResource>(rid) .get::<UnixDatagramResource>(rid)
.map_err(|_| custom_error("NotConnected", "Socket has been closed"))?; .map_err(|_| NetError::SocketClosedNotConnected)?;
let socket = RcRef::map(&resource, |r| &r.socket) let socket = RcRef::map(&resource, |r| &r.socket)
.try_borrow_mut() .try_borrow_mut()
.ok_or_else(|| custom_error("Busy", "Socket already in use"))?; .ok_or(NetError::SocketBusy)?;
let nwritten = socket.send_to(&zero_copy, address_path).await?; let nwritten = socket.send_to(&zero_copy, address_path).await?;
Ok(nwritten) Ok(nwritten)
@ -179,14 +177,18 @@ pub fn op_net_listen_unix<NP>(
state: &mut OpState, state: &mut OpState,
#[string] address_path: String, #[string] address_path: String,
#[string] api_name: String, #[string] api_name: String,
) -> Result<(ResourceId, Option<String>), AnyError> ) -> Result<(ResourceId, Option<String>), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
let permissions = state.borrow_mut::<NP>(); let permissions = state.borrow_mut::<NP>();
let api_call_expr = format!("{}()", api_name); let api_call_expr = format!("{}()", api_name);
let address_path = permissions.check_read(&address_path, &api_call_expr)?; let address_path = permissions
_ = permissions.check_write_path(&address_path, &api_call_expr)?; .check_read(&address_path, &api_call_expr)
.map_err(NetError::Permission)?;
_ = permissions
.check_write_path(&address_path, &api_call_expr)
.map_err(NetError::Permission)?;
let listener = UnixListener::bind(address_path)?; let listener = UnixListener::bind(address_path)?;
let local_addr = listener.local_addr()?; let local_addr = listener.local_addr()?;
let pathname = local_addr.as_pathname().map(pathstring).transpose()?; let pathname = local_addr.as_pathname().map(pathstring).transpose()?;
@ -198,14 +200,17 @@ where
pub fn net_listen_unixpacket<NP>( pub fn net_listen_unixpacket<NP>(
state: &mut OpState, state: &mut OpState,
address_path: String, address_path: String,
) -> Result<(ResourceId, Option<String>), AnyError> ) -> Result<(ResourceId, Option<String>), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
let permissions = state.borrow_mut::<NP>(); let permissions = state.borrow_mut::<NP>();
let address_path = let address_path = permissions
permissions.check_read(&address_path, "Deno.listenDatagram()")?; .check_read(&address_path, "Deno.listenDatagram()")
_ = permissions.check_write_path(&address_path, "Deno.listenDatagram()")?; .map_err(NetError::Permission)?;
_ = permissions
.check_write_path(&address_path, "Deno.listenDatagram()")
.map_err(NetError::Permission)?;
let socket = UnixDatagram::bind(address_path)?; let socket = UnixDatagram::bind(address_path)?;
let local_addr = socket.local_addr()?; let local_addr = socket.local_addr()?;
let pathname = local_addr.as_pathname().map(pathstring).transpose()?; let pathname = local_addr.as_pathname().map(pathstring).transpose()?;
@ -222,7 +227,7 @@ where
pub fn op_net_listen_unixpacket<NP>( pub fn op_net_listen_unixpacket<NP>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
) -> Result<(ResourceId, Option<String>), AnyError> ) -> Result<(ResourceId, Option<String>), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
@ -235,13 +240,13 @@ where
pub fn op_node_unstable_net_listen_unixpacket<NP>( pub fn op_node_unstable_net_listen_unixpacket<NP>(
state: &mut OpState, state: &mut OpState,
#[string] path: String, #[string] path: String,
) -> Result<(ResourceId, Option<String>), AnyError> ) -> Result<(ResourceId, Option<String>), NetError>
where where
NP: NetPermissions + 'static, NP: NetPermissions + 'static,
{ {
net_listen_unixpacket::<NP>(state, path) net_listen_unixpacket::<NP>(state, path)
} }
pub fn pathstring(pathname: &Path) -> Result<String, AnyError> { pub fn pathstring(pathname: &Path) -> Result<String, NetError> {
into_string(pathname.into()) into_string(pathname.into())
} }

View file

@ -1,6 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use tokio::net::lookup_host; use tokio::net::lookup_host;
@ -9,7 +8,7 @@ use tokio::net::lookup_host;
pub async fn resolve_addr( pub async fn resolve_addr(
hostname: &str, hostname: &str,
port: u16, port: u16,
) -> Result<impl Iterator<Item = SocketAddr> + '_, AnyError> { ) -> Result<impl Iterator<Item = SocketAddr> + '_, std::io::Error> {
let addr_port_pair = make_addr_port_pair(hostname, port); let addr_port_pair = make_addr_port_pair(hostname, port);
let result = lookup_host(addr_port_pair).await?; let result = lookup_host(addr_port_pair).await?;
Ok(result) Ok(result)
@ -19,7 +18,7 @@ pub async fn resolve_addr(
pub fn resolve_addr_sync( pub fn resolve_addr_sync(
hostname: &str, hostname: &str,
port: u16, port: u16,
) -> Result<impl Iterator<Item = SocketAddr>, AnyError> { ) -> Result<impl Iterator<Item = SocketAddr>, std::io::Error> {
let addr_port_pair = make_addr_port_pair(hostname, port); let addr_port_pair = make_addr_port_pair(hostname, port);
let result = addr_port_pair.to_socket_addrs()?; let result = addr_port_pair.to_socket_addrs()?;
Ok(result) Ok(result)

View file

@ -23,6 +23,7 @@ use deno_ffi::DlfcnError;
use deno_ffi::IRError; use deno_ffi::IRError;
use deno_ffi::ReprError; use deno_ffi::ReprError;
use deno_ffi::StaticError; use deno_ffi::StaticError;
use deno_net::ops::NetError;
use deno_tls::TlsError; use deno_tls::TlsError;
use deno_webstorage::WebStorageError; use deno_webstorage::WebStorageError;
use std::env; use std::env;
@ -292,6 +293,48 @@ fn get_broadcast_channel_error(error: &BroadcastChannelError) -> &'static str {
} }
} }
fn get_net_error(error: &NetError) -> &'static str {
match error {
NetError::ListenerClosed => "BadResource",
NetError::ListenerBusy => "Busy",
NetError::SocketClosed => "BadResource",
NetError::SocketClosedNotConnected => "NotConnected",
NetError::SocketBusy => "Busy",
NetError::Io(e) => get_io_error_class(e),
NetError::AcceptTaskOngoing => "Busy",
NetError::RootCertStore(e)
| NetError::Permission(e)
| NetError::Resource(e) => get_error_class_name(e).unwrap_or("Error"),
NetError::NoResolvedAddress => "Error",
NetError::AddrParse(_) => "Error",
NetError::Map(e) => get_net_map_error(e),
NetError::Canceled(e) => {
let io_err: io::Error = e.to_owned().into();
get_io_error_class(&io_err)
}
NetError::DnsNotFound(_) => "NotFound",
NetError::DnsNotConnected(_) => "NotConnected",
NetError::DnsTimedOut(_) => "TimedOut",
NetError::Dns(_) => "Error",
NetError::UnsupportedRecordType => "NotSupported",
NetError::InvalidUtf8(_) => "InvalidData",
NetError::UnexpectedKeyType => "Error",
NetError::InvalidHostname(_) => "TypeError",
NetError::TcpStreamBusy => "Busy",
NetError::Rustls(_) => "Error",
NetError::Tls(e) => get_tls_error_class(e),
NetError::ListenTlsRequiresKey => "InvalidData",
NetError::Reunite(_) => "Error",
}
}
fn get_net_map_error(error: &deno_net::io::MapError) -> &'static str {
match error {
deno_net::io::MapError::Io(e) => get_io_error_class(e),
deno_net::io::MapError::NoResources => "Error",
}
}
pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> { pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
deno_core::error::get_custom_error_class(e) deno_core::error::get_custom_error_class(e)
.or_else(|| deno_webgpu::error::get_error_class_name(e)) .or_else(|| deno_webgpu::error::get_error_class_name(e))
@ -316,6 +359,11 @@ pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
.or_else(|| e.downcast_ref::<CronError>().map(get_cron_error_class)) .or_else(|| e.downcast_ref::<CronError>().map(get_cron_error_class))
.or_else(|| e.downcast_ref::<CanvasError>().map(get_canvas_error)) .or_else(|| e.downcast_ref::<CanvasError>().map(get_canvas_error))
.or_else(|| e.downcast_ref::<CacheError>().map(get_cache_error)) .or_else(|| e.downcast_ref::<CacheError>().map(get_cache_error))
.or_else(|| e.downcast_ref::<NetError>().map(get_net_error))
.or_else(|| {
e.downcast_ref::<deno_net::io::MapError>()
.map(get_net_map_error)
})
.or_else(|| { .or_else(|| {
e.downcast_ref::<BroadcastChannelError>() e.downcast_ref::<BroadcastChannelError>()
.map(get_broadcast_channel_error) .map(get_broadcast_channel_error)