summaryrefslogtreecommitdiff
path: root/ext/net/ops.rs
diff options
context:
space:
mode:
authorLeo Kettmeir <crowlkats@toaxl.com>2024-10-17 09:43:04 -0700
committerGitHub <noreply@github.com>2024-10-17 09:43:04 -0700
commited13efc4ac3ed5262d025bd7228785553fecff1c (patch)
treeb4a29cbfb75e91a6e16fdc0763b1d2000db2db98 /ext/net/ops.rs
parent3b62e05062805d45fd626ac8e413e9b7aee7c3a1 (diff)
refactor(ext/net): use concrete error type (#26227)
Diffstat (limited to 'ext/net/ops.rs')
-rw-r--r--ext/net/ops.rs218
1 files changed, 137 insertions, 81 deletions
diff --git a/ext/net/ops.rs b/ext/net/ops.rs
index 5248493f4..0f92dead0 100644
--- a/ext/net/ops.rs
+++ b/ext/net/ops.rs
@@ -6,10 +6,6 @@ use crate::resolve_addr::resolve_addr;
use crate::resolve_addr::resolve_addr_sync;
use crate::tcp::TcpListener;
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::CancelFuture;
@@ -43,6 +39,7 @@ use trust_dns_proto::rr::record_type::RecordType;
use trust_dns_resolver::config::NameServerConfigGroup;
use trust_dns_resolver::config::ResolverConfig;
use trust_dns_resolver::config::ResolverOpts;
+use trust_dns_resolver::error::ResolveError;
use trust_dns_resolver::error::ResolveErrorKind;
use trust_dns_resolver::system_conf;
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() {
- bad_resource("Listener has been closed")
+ NetError::ListenerClosed
} 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(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
-) -> Result<(ResourceId, IpAddr, IpAddr), AnyError> {
+) -> Result<(ResourceId, IpAddr, IpAddr), NetError> {
let resource = state
.borrow()
.resource_table
.get::<NetworkListenerResource<TcpListener>>(rid)
- .map_err(|_| bad_resource("Listener has been closed"))?;
+ .map_err(|_| NetError::ListenerClosed)?;
let listener = RcRef::map(&resource, |r| &r.listener)
.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 (tcp_stream, _socket_addr) = listener
.accept()
@@ -112,12 +167,12 @@ pub async fn op_net_recv_udp(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
#[buffer] mut buf: JsBuffer,
-) -> Result<(usize, IpAddr), AnyError> {
+) -> Result<(usize, IpAddr), NetError> {
let resource = state
.borrow_mut()
.resource_table
.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 cancel_handle = RcRef::map(&resource, |r| &r.cancel);
let (nread, remote_addr) = socket
@@ -134,27 +189,29 @@ pub async fn op_net_send_udp<NP>(
#[smi] rid: ResourceId,
#[serde] addr: IpAddr,
#[buffer] zero_copy: JsBuffer,
-) -> Result<usize, AnyError>
+) -> Result<usize, NetError>
where
NP: NetPermissions + 'static,
{
{
let mut s = state.borrow_mut();
- s.borrow_mut::<NP>().check_net(
- &(&addr.hostname, Some(addr.port)),
- "Deno.DatagramConn.send()",
- )?;
+ s.borrow_mut::<NP>()
+ .check_net(
+ &(&addr.hostname, Some(addr.port)),
+ "Deno.DatagramConn.send()",
+ )
+ .map_err(NetError::Permission)?;
}
let addr = resolve_addr(&addr.hostname, addr.port)
.await?
.next()
- .ok_or_else(|| generic_error("No resolved address found"))?;
+ .ok_or(NetError::NoResolvedAddress)?;
let resource = state
.borrow_mut()
.resource_table
.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 nwritten = socket.send_to(&zero_copy, &addr).await?;
@@ -167,12 +224,12 @@ pub async fn op_net_join_multi_v4_udp(
#[smi] rid: ResourceId,
#[string] address: String,
#[string] multi_interface: String,
-) -> Result<(), AnyError> {
+) -> Result<(), NetError> {
let resource = state
.borrow_mut()
.resource_table
.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 addr = Ipv4Addr::from_str(address.as_str())?;
@@ -189,12 +246,12 @@ pub async fn op_net_join_multi_v6_udp(
#[smi] rid: ResourceId,
#[string] address: String,
#[smi] multi_interface: u32,
-) -> Result<(), AnyError> {
+) -> Result<(), NetError> {
let resource = state
.borrow_mut()
.resource_table
.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 addr = Ipv6Addr::from_str(address.as_str())?;
@@ -210,12 +267,12 @@ pub async fn op_net_leave_multi_v4_udp(
#[smi] rid: ResourceId,
#[string] address: String,
#[string] multi_interface: String,
-) -> Result<(), AnyError> {
+) -> Result<(), NetError> {
let resource = state
.borrow_mut()
.resource_table
.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 addr = Ipv4Addr::from_str(address.as_str())?;
@@ -232,12 +289,12 @@ pub async fn op_net_leave_multi_v6_udp(
#[smi] rid: ResourceId,
#[string] address: String,
#[smi] multi_interface: u32,
-) -> Result<(), AnyError> {
+) -> Result<(), NetError> {
let resource = state
.borrow_mut()
.resource_table
.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 addr = Ipv6Addr::from_str(address.as_str())?;
@@ -253,16 +310,16 @@ pub async fn op_net_set_multi_loopback_udp(
#[smi] rid: ResourceId,
is_v4_membership: bool,
loopback: bool,
-) -> Result<(), AnyError> {
+) -> Result<(), NetError> {
let resource = state
.borrow_mut()
.resource_table
.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;
if is_v4_membership {
- socket.set_multicast_loop_v4(loopback)?
+ socket.set_multicast_loop_v4(loopback)?;
} else {
socket.set_multicast_loop_v6(loopback)?;
}
@@ -275,12 +332,12 @@ pub async fn op_net_set_multi_ttl_udp(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
#[smi] ttl: u32,
-) -> Result<(), AnyError> {
+) -> Result<(), NetError> {
let resource = state
.borrow_mut()
.resource_table
.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;
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>(
state: Rc<RefCell<OpState>>,
#[serde] addr: IpAddr,
-) -> Result<(ResourceId, IpAddr, IpAddr), AnyError>
+) -> Result<(ResourceId, IpAddr, IpAddr), NetError>
where
NP: NetPermissions + 'static,
{
@@ -304,7 +361,7 @@ where
pub async fn op_net_connect_tcp_inner<NP>(
state: Rc<RefCell<OpState>>,
addr: IpAddr,
-) -> Result<(ResourceId, IpAddr, IpAddr), AnyError>
+) -> Result<(ResourceId, IpAddr, IpAddr), NetError>
where
NP: NetPermissions + 'static,
{
@@ -312,13 +369,14 @@ where
let mut state_ = state.borrow_mut();
state_
.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)
.await?
.next()
- .ok_or_else(|| generic_error("No resolved address found"))?;
+ .ok_or_else(|| NetError::NoResolvedAddress)?;
let tcp_stream = TcpStream::connect(&addr).await?;
let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?;
@@ -353,7 +411,7 @@ pub fn op_net_listen_tcp<NP>(
#[serde] addr: IpAddr,
reuse_port: bool,
load_balanced: bool,
-) -> Result<(ResourceId, IpAddr), AnyError>
+) -> Result<(ResourceId, IpAddr), NetError>
where
NP: NetPermissions + 'static,
{
@@ -362,10 +420,11 @@ where
}
state
.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)?
.next()
- .ok_or_else(|| generic_error("No resolved address found"))?;
+ .ok_or_else(|| NetError::NoResolvedAddress)?;
let listener = if load_balanced {
TcpListener::bind_load_balanced(addr)
@@ -384,16 +443,17 @@ fn net_listen_udp<NP>(
addr: IpAddr,
reuse_address: bool,
loopback: bool,
-) -> Result<(ResourceId, IpAddr), AnyError>
+) -> Result<(ResourceId, IpAddr), NetError>
where
NP: NetPermissions + 'static,
{
state
.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)?
.next()
- .ok_or_else(|| generic_error("No resolved address found"))?;
+ .ok_or_else(|| NetError::NoResolvedAddress)?;
let domain = if addr.is_ipv4() {
Domain::IPV4
@@ -453,7 +513,7 @@ pub fn op_net_listen_udp<NP>(
#[serde] addr: IpAddr,
reuse_address: bool,
loopback: bool,
-) -> Result<(ResourceId, IpAddr), AnyError>
+) -> Result<(ResourceId, IpAddr), NetError>
where
NP: NetPermissions + 'static,
{
@@ -468,7 +528,7 @@ pub fn op_node_unstable_net_listen_udp<NP>(
#[serde] addr: IpAddr,
reuse_address: bool,
loopback: bool,
-) -> Result<(ResourceId, IpAddr), AnyError>
+) -> Result<(ResourceId, IpAddr), NetError>
where
NP: NetPermissions + 'static,
{
@@ -551,7 +611,7 @@ pub struct NameServer {
pub async fn op_dns_resolve<NP>(
state: Rc<RefCell<OpState>>,
#[serde] args: ResolveAddrArgs,
-) -> Result<Vec<DnsReturnRecord>, AnyError>
+) -> Result<Vec<DnsReturnRecord>, NetError>
where
NP: NetPermissions + 'static,
{
@@ -587,7 +647,9 @@ where
let socker_addr = &ns.socket_addr;
let ip = socker_addr.ip().to_string();
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
- .map_err(|e| {
- let message = format!("{e}");
- match e.kind() {
- ResolveErrorKind::NoRecordsFound { .. } => {
- custom_error("NotFound", message)
- }
- ResolveErrorKind::Message("No connections available") => {
- custom_error("NotConnected", message)
- }
- ResolveErrorKind::Timeout => custom_error("TimedOut", message),
- _ => generic_error(message),
+ .map_err(|e| match e.kind() {
+ ResolveErrorKind::NoRecordsFound { .. } => NetError::DnsNotFound(e),
+ ResolveErrorKind::Message("No connections available") => {
+ NetError::DnsNotConnected(e)
}
+ ResolveErrorKind::Timeout => NetError::DnsTimedOut(e),
+ _ => NetError::Dns(e),
})?
.iter()
.filter_map(|rdata| rdata_to_return_record(record_type)(rdata).transpose())
- .collect::<Result<Vec<DnsReturnRecord>, AnyError>>()
+ .collect::<Result<Vec<DnsReturnRecord>, NetError>>()
}
#[op2(fast)]
@@ -641,7 +698,7 @@ pub fn op_set_nodelay(
state: &mut OpState,
#[smi] rid: ResourceId,
nodelay: bool,
-) -> Result<(), AnyError> {
+) -> Result<(), NetError> {
op_set_nodelay_inner(state, rid, nodelay)
}
@@ -650,10 +707,12 @@ pub fn op_set_nodelay_inner(
state: &mut OpState,
rid: ResourceId,
nodelay: bool,
-) -> Result<(), AnyError> {
- let resource: Rc<TcpStreamResource> =
- state.resource_table.get::<TcpStreamResource>(rid)?;
- resource.set_nodelay(nodelay)
+) -> Result<(), NetError> {
+ let resource: Rc<TcpStreamResource> = state
+ .resource_table
+ .get::<TcpStreamResource>(rid)
+ .map_err(NetError::Resource)?;
+ resource.set_nodelay(nodelay).map_err(NetError::Map)
}
#[op2(fast)]
@@ -661,7 +720,7 @@ pub fn op_set_keepalive(
state: &mut OpState,
#[smi] rid: ResourceId,
keepalive: bool,
-) -> Result<(), AnyError> {
+) -> Result<(), NetError> {
op_set_keepalive_inner(state, rid, keepalive)
}
@@ -670,17 +729,19 @@ pub fn op_set_keepalive_inner(
state: &mut OpState,
rid: ResourceId,
keepalive: bool,
-) -> Result<(), AnyError> {
- let resource: Rc<TcpStreamResource> =
- state.resource_table.get::<TcpStreamResource>(rid)?;
- resource.set_keepalive(keepalive)
+) -> Result<(), NetError> {
+ let resource: Rc<TcpStreamResource> = state
+ .resource_table
+ .get::<TcpStreamResource>(rid)
+ .map_err(NetError::Resource)?;
+ resource.set_keepalive(keepalive).map_err(NetError::Map)
}
fn rdata_to_return_record(
ty: RecordType,
-) -> impl Fn(&RData) -> Result<Option<DnsReturnRecord>, AnyError> {
+) -> impl Fn(&RData) -> Result<Option<DnsReturnRecord>, NetError> {
use RecordType::*;
- move |r: &RData| -> Result<Option<DnsReturnRecord>, AnyError> {
+ move |r: &RData| -> Result<Option<DnsReturnRecord>, NetError> {
let record = match ty {
A => r.as_a().map(ToString::to_string).map(DnsReturnRecord::A),
AAAA => r
@@ -761,12 +822,7 @@ fn rdata_to_return_record(
.collect();
DnsReturnRecord::Txt(texts)
}),
- _ => {
- return Err(custom_error(
- "NotSupported",
- "Provided record type is not supported",
- ))
- }
+ _ => return Err(NetError::UnsupportedRecordType),
};
Ok(record)
}
@@ -985,7 +1041,7 @@ mod tests {
&mut self,
_host: &(T, Option<u16>),
_api_name: &str,
- ) -> Result<(), AnyError> {
+ ) -> Result<(), deno_core::error::AnyError> {
Ok(())
}
@@ -993,7 +1049,7 @@ mod tests {
&mut self,
p: &str,
_api_name: &str,
- ) -> Result<PathBuf, AnyError> {
+ ) -> Result<PathBuf, deno_core::error::AnyError> {
Ok(PathBuf::from(p))
}
@@ -1001,7 +1057,7 @@ mod tests {
&mut self,
p: &str,
_api_name: &str,
- ) -> Result<PathBuf, AnyError> {
+ ) -> Result<PathBuf, deno_core::error::AnyError> {
Ok(PathBuf::from(p))
}
@@ -1009,7 +1065,7 @@ mod tests {
&mut self,
p: &'a Path,
_api_name: &str,
- ) -> Result<Cow<'a, Path>, AnyError> {
+ ) -> Result<Cow<'a, Path>, deno_core::error::AnyError> {
Ok(Cow::Borrowed(p))
}
}
@@ -1091,7 +1147,7 @@ mod tests {
let vals = result.unwrap();
rid = rid.or(Some(vals.0));
}
- };
+ }
let rid = rid.unwrap();
let state = runtime.op_state();