diff options
author | Leo Kettmeir <crowlkats@toaxl.com> | 2024-10-17 09:43:04 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-17 09:43:04 -0700 |
commit | ed13efc4ac3ed5262d025bd7228785553fecff1c (patch) | |
tree | b4a29cbfb75e91a6e16fdc0763b1d2000db2db98 /ext/net | |
parent | 3b62e05062805d45fd626ac8e413e9b7aee7c3a1 (diff) |
refactor(ext/net): use concrete error type (#26227)
Diffstat (limited to 'ext/net')
-rw-r--r-- | ext/net/Cargo.toml | 1 | ||||
-rw-r--r-- | ext/net/io.rs | 45 | ||||
-rw-r--r-- | ext/net/ops.rs | 218 | ||||
-rw-r--r-- | ext/net/ops_tls.rs | 107 | ||||
-rw-r--r-- | ext/net/ops_unix.rs | 67 | ||||
-rw-r--r-- | ext/net/resolve_addr.rs | 5 |
6 files changed, 260 insertions, 183 deletions
diff --git a/ext/net/Cargo.toml b/ext/net/Cargo.toml index 4ba4fb315..a57862072 100644 --- a/ext/net/Cargo.toml +++ b/ext/net/Cargo.toml @@ -21,6 +21,7 @@ pin-project.workspace = true rustls-tokio-stream.workspace = true serde.workspace = true socket2.workspace = true +thiserror.workspace = true tokio.workspace = true trust-dns-proto = "0.23" trust-dns-resolver = { version = "0.23", features = ["tokio-runtime", "serde-config"] } diff --git a/ext/net/io.rs b/ext/net/io.rs index f3aed3fcb..2907fa398 100644 --- a/ext/net/io.rs +++ b/ext/net/io.rs @@ -1,7 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::generic_error; -use deno_core::error::AnyError; +use deno_core::futures::TryFutureExt; use deno_core::AsyncMutFuture; use deno_core::AsyncRefCell; use deno_core::AsyncResult; @@ -69,25 +68,36 @@ where pub async fn read( self: Rc<Self>, data: &mut [u8], - ) -> Result<usize, AnyError> { + ) -> Result<usize, std::io::Error> { let mut rd = self.rd_borrow_mut().await; let nread = rd.read(data).try_or_cancel(self.cancel_handle()).await?; 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 nwritten = wr.write(data).await?; 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; wr.shutdown().await?; Ok(()) } } +#[derive(Debug, thiserror::Error)] +pub enum MapError { + #[error("{0}")] + Io(std::io::Error), + #[error("Unable to get resources")] + NoResources, +} + pub type TcpStreamResource = FullDuplexResource<tcp::OwnedReadHalf, tcp::OwnedWriteHalf>; @@ -100,7 +110,7 @@ impl Resource for TcpStreamResource { } fn shutdown(self: Rc<Self>) -> AsyncResult<()> { - Box::pin(self.shutdown()) + Box::pin(self.shutdown().map_err(Into::into)) } fn close(self: Rc<Self>) { @@ -109,31 +119,30 @@ impl Resource for TcpStreamResource { } impl TcpStreamResource { - pub fn set_nodelay(self: Rc<Self>, nodelay: bool) -> Result<(), AnyError> { - self.map_socket(Box::new(move |socket| Ok(socket.set_nodelay(nodelay)?))) + pub fn set_nodelay(self: Rc<Self>, nodelay: bool) -> Result<(), MapError> { + self.map_socket(Box::new(move |socket| socket.set_nodelay(nodelay))) } pub fn set_keepalive( self: Rc<Self>, keepalive: bool, - ) -> Result<(), AnyError> { - self - .map_socket(Box::new(move |socket| Ok(socket.set_keepalive(keepalive)?))) + ) -> Result<(), MapError> { + self.map_socket(Box::new(move |socket| socket.set_keepalive(keepalive))) } #[allow(clippy::type_complexity)] fn map_socket( self: Rc<Self>, - map: Box<dyn FnOnce(SockRef) -> Result<(), AnyError>>, - ) -> Result<(), AnyError> { + map: Box<dyn FnOnce(SockRef) -> Result<(), std::io::Error>>, + ) -> Result<(), MapError> { if let Some(wr) = RcRef::map(self, |r| &r.wr).try_borrow() { let stream = wr.as_ref().as_ref(); 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!() } #[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!() } pub fn cancel_read_ops(&self) { @@ -170,7 +181,7 @@ impl Resource for UnixStreamResource { } fn shutdown(self: Rc<Self>) -> AsyncResult<()> { - Box::pin(self.shutdown()) + Box::pin(self.shutdown().map_err(Into::into)) } fn close(self: Rc<Self>) { 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(); diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs index a68d144b5..c7d65dd85 100644 --- a/ext/net/ops_tls.rs +++ b/ext/net/ops_tls.rs @@ -2,6 +2,7 @@ use crate::io::TcpStreamResource; use crate::ops::IpAddr; +use crate::ops::NetError; use crate::ops::TlsHandshakeInfo; use crate::raw::NetworkListenerResource; use crate::resolve_addr::resolve_addr; @@ -10,13 +11,7 @@ use crate::tcp::TcpListener; use crate::DefaultTlsOptions; use crate::NetPermissions; use crate::UnsafelyIgnoreCertificateErrors; -use deno_core::anyhow::anyhow; -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::futures::TryFutureExt; use deno_core::op2; use deno_core::v8; use deno_core::AsyncRefCell; @@ -118,20 +113,23 @@ impl TlsStreamResource { pub async fn read( self: Rc<Self>, data: &mut [u8], - ) -> Result<usize, AnyError> { + ) -> Result<usize, std::io::Error> { let mut rd = RcRef::map(&self, |r| &r.rd).borrow_mut().await; 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 nwritten = wr.write(data).await?; wr.flush().await?; 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; wr.shutdown().await?; Ok(()) @@ -139,7 +137,7 @@ impl TlsStreamResource { pub async fn handshake( self: &Rc<Self>, - ) -> Result<TlsHandshakeInfo, AnyError> { + ) -> Result<TlsHandshakeInfo, std::io::Error> { if let Some(tls_info) = &*self.handshake_info.borrow() { return Ok(tls_info.clone()); } @@ -164,7 +162,7 @@ impl Resource for TlsStreamResource { } fn shutdown(self: Rc<Self>) -> AsyncResult<()> { - Box::pin(self.shutdown()) + Box::pin(self.shutdown().map_err(Into::into)) } fn close(self: Rc<Self>) { @@ -201,7 +199,7 @@ pub fn op_tls_key_null() -> TlsKeysHolder { pub fn op_tls_key_static( #[string] cert: &str, #[string] key: &str, -) -> Result<TlsKeysHolder, AnyError> { +) -> Result<TlsKeysHolder, deno_tls::TlsError> { let cert = load_certs(&mut BufReader::new(cert.as_bytes()))?; let key = load_private_keys(key.as_bytes())? .into_iter() @@ -236,9 +234,9 @@ pub fn op_tls_cert_resolver_resolve( #[cppgc] lookup: &TlsKeyLookup, #[string] sni: String, #[cppgc] key: &TlsKeysHolder, -) -> Result<(), AnyError> { +) -> Result<(), NetError> { let TlsKeys::Static(key) = key.take() else { - bail!("unexpected key type"); + return Err(NetError::UnexpectedKeyType); }; lookup.resolve(sni, Ok(key)); Ok(()) @@ -258,7 +256,7 @@ pub fn op_tls_cert_resolver_resolve_error( pub fn op_tls_start<NP>( state: Rc<RefCell<OpState>>, #[serde] args: StartTlsArgs, -) -> Result<(ResourceId, IpAddr, IpAddr), AnyError> +) -> Result<(ResourceId, IpAddr, IpAddr), NetError> where NP: NetPermissions + 'static, { @@ -271,7 +269,9 @@ where { let mut s = state.borrow_mut(); 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 @@ -281,7 +281,7 @@ where .collect::<Vec<_>>(); 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 .borrow() @@ -291,19 +291,21 @@ where let root_cert_store = state .borrow() .borrow::<DefaultTlsOptions>() - .root_cert_store()?; + .root_cert_store() + .map_err(NetError::RootCertStore)?; let resource_rc = state .borrow_mut() .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 // 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 - let resource = Rc::try_unwrap(resource_rc) - .map_err(|_| custom_error("Busy", "TCP stream is currently in use"))?; + let resource = + Rc::try_unwrap(resource_rc).map_err(|_| NetError::TcpStreamBusy)?; 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 remote_addr = tcp_stream.peer_addr()?; @@ -345,7 +347,7 @@ pub async fn op_net_connect_tls<NP>( #[serde] addr: IpAddr, #[serde] args: ConnectTlsArgs, #[cppgc] key_pair: &TlsKeysHolder, -) -> Result<(ResourceId, IpAddr, IpAddr), AnyError> +) -> Result<(ResourceId, IpAddr, IpAddr), NetError> where NP: NetPermissions + 'static, { @@ -359,9 +361,14 @@ where let mut s = state.borrow_mut(); let permissions = s.borrow_mut::<NP>(); 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 { - Some(permissions.check_read(path, "Deno.connectTls()")?) + Some( + permissions + .check_read(path, "Deno.connectTls()") + .map_err(NetError::Permission)?, + ) } else { None } @@ -382,17 +389,18 @@ where let root_cert_store = state .borrow() .borrow::<DefaultTlsOptions>() - .root_cert_store()?; + .root_cert_store() + .map_err(NetError::RootCertStore)?; let hostname_dns = if let Some(server_name) = args.server_name { ServerName::try_from(server_name) } else { 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) .await? .next() - .ok_or_else(|| generic_error("No resolved address found"))?; + .ok_or_else(|| NetError::NoResolvedAddress)?; let tcp_stream = TcpStream::connect(connect_addr).await?; let local_addr = tcp_stream.local_addr()?; let remote_addr = tcp_stream.peer_addr()?; @@ -444,7 +452,7 @@ pub fn op_net_listen_tls<NP>( #[serde] addr: IpAddr, #[serde] args: ListenTlsArgs, #[cppgc] keys: &TlsKeysHolder, -) -> Result<(ResourceId, IpAddr), AnyError> +) -> Result<(ResourceId, IpAddr), NetError> where NP: NetPermissions + 'static, { @@ -455,12 +463,13 @@ where { let permissions = state.borrow_mut::<NP>(); 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)? .next() - .ok_or_else(|| generic_error("No resolved address found"))?; + .ok_or(NetError::NoResolvedAddress)?; let tcp_listener = if args.load_balanced { TcpListener::bind_load_balanced(bind_addr) @@ -475,28 +484,24 @@ where .map(|s| s.into_bytes()) .collect(); 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)) => { let mut tls_config = ServerConfig::builder() .with_no_client_auth() - .with_single_cert(cert, key) - .map_err(|e| anyhow!(e))?; + .with_single_cert(cert, key)?; tls_config.alpn_protocols = alpn; - Ok(TlsListener { + TlsListener { tcp_listener, tls_config: Some(tls_config.into()), server_config_provider: None, - }) + } } - TlsKeys::Resolver(resolver) => Ok(TlsListener { + TlsKeys::Resolver(resolver) => TlsListener { tcp_listener, tls_config: None, 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); @@ -510,23 +515,23 @@ where pub async fn op_net_accept_tls( 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<TlsListener>>(rid) - .map_err(|_| bad_resource("Listener has been closed"))?; + .map_err(|_| NetError::ListenerClosed)?; let cancel_handle = RcRef::map(&resource, |r| &r.cancel); 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 (tls_stream, remote_addr) = match listener.accept().try_or_cancel(&cancel_handle).await { Ok(tuple) => tuple, 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()), }; @@ -547,11 +552,11 @@ pub async fn op_net_accept_tls( pub async fn op_tls_handshake( state: Rc<RefCell<OpState>>, #[smi] rid: ResourceId, -) -> Result<TlsHandshakeInfo, AnyError> { +) -> Result<TlsHandshakeInfo, NetError> { let resource = state .borrow() .resource_table .get::<TlsStreamResource>(rid) - .map_err(|_| bad_resource("Listener has been closed"))?; - resource.handshake().await + .map_err(|_| NetError::ListenerClosed)?; + resource.handshake().await.map_err(Into::into) } diff --git a/ext/net/ops_unix.rs b/ext/net/ops_unix.rs index 95293284f..04ae84906 100644 --- a/ext/net/ops_unix.rs +++ b/ext/net/ops_unix.rs @@ -1,11 +1,9 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::io::UnixStreamResource; +use crate::ops::NetError; use crate::raw::NetworkListenerResource; 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::AsyncRefCell; use deno_core::CancelHandle; @@ -26,11 +24,8 @@ use tokio::net::UnixListener; pub use tokio::net::UnixStream; /// A utility function to map OsStrings to Strings -pub fn into_string(s: std::ffi::OsString) -> Result<String, AnyError> { - s.into_string().map_err(|s| { - let message = format!("File name or path {s:?} is not valid UTF-8"); - custom_error("InvalidData", message) - }) +pub fn into_string(s: std::ffi::OsString) -> Result<String, NetError> { + s.into_string().map_err(NetError::InvalidUtf8) } pub struct UnixDatagramResource { @@ -63,15 +58,15 @@ pub struct UnixListenArgs { pub async fn op_net_accept_unix( state: Rc<RefCell<OpState>>, #[smi] rid: ResourceId, -) -> Result<(ResourceId, Option<String>, Option<String>), AnyError> { +) -> Result<(ResourceId, Option<String>, Option<String>), NetError> { let resource = state .borrow() .resource_table .get::<NetworkListenerResource<UnixListener>>(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", "Listener already in use"))?; + .ok_or(NetError::ListenerBusy)?; let cancel = RcRef::map(resource, |r| &r.cancel); let (unix_stream, _socket_addr) = listener .accept() @@ -95,7 +90,7 @@ pub async fn op_net_accept_unix( pub async fn op_net_connect_unix<NP>( state: Rc<RefCell<OpState>>, #[string] address_path: String, -) -> Result<(ResourceId, Option<String>, Option<String>), AnyError> +) -> Result<(ResourceId, Option<String>, Option<String>), NetError> where NP: NetPermissions + 'static, { @@ -103,10 +98,12 @@ where let mut state_ = state.borrow_mut(); let address_path = state_ .borrow_mut::<NP>() - .check_read(&address_path, "Deno.connect()")?; + .check_read(&address_path, "Deno.connect()") + .map_err(NetError::Permission)?; _ = state_ .borrow_mut::<NP>() - .check_write_path(&address_path, "Deno.connect()")?; + .check_write_path(&address_path, "Deno.connect()") + .map_err(NetError::Permission)?; address_path }; let unix_stream = UnixStream::connect(&address_path).await?; @@ -127,15 +124,15 @@ pub async fn op_net_recv_unixpacket( state: Rc<RefCell<OpState>>, #[smi] rid: ResourceId, #[buffer] mut buf: JsBuffer, -) -> Result<(usize, Option<String>), AnyError> { +) -> Result<(usize, Option<String>), NetError> { let resource = state .borrow() .resource_table .get::<UnixDatagramResource>(rid) - .map_err(|_| bad_resource("Socket has been closed"))?; + .map_err(|_| NetError::SocketClosed)?; let socket = RcRef::map(&resource, |r| &r.socket) .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 (nread, remote_addr) = 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, #[string] address_path: String, #[buffer] zero_copy: JsBuffer, -) -> Result<usize, AnyError> +) -> Result<usize, NetError> where NP: NetPermissions + 'static, { let address_path = { let mut s = state.borrow_mut(); 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 .borrow() .resource_table .get::<UnixDatagramResource>(rid) - .map_err(|_| custom_error("NotConnected", "Socket has been closed"))?; + .map_err(|_| NetError::SocketClosedNotConnected)?; let socket = RcRef::map(&resource, |r| &r.socket) .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?; Ok(nwritten) @@ -179,14 +177,18 @@ pub fn op_net_listen_unix<NP>( state: &mut OpState, #[string] address_path: String, #[string] api_name: String, -) -> Result<(ResourceId, Option<String>), AnyError> +) -> Result<(ResourceId, Option<String>), NetError> where NP: NetPermissions + 'static, { let permissions = state.borrow_mut::<NP>(); let api_call_expr = format!("{}()", api_name); - let address_path = permissions.check_read(&address_path, &api_call_expr)?; - _ = permissions.check_write_path(&address_path, &api_call_expr)?; + let address_path = permissions + .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 local_addr = listener.local_addr()?; let pathname = local_addr.as_pathname().map(pathstring).transpose()?; @@ -198,14 +200,17 @@ where pub fn net_listen_unixpacket<NP>( state: &mut OpState, address_path: String, -) -> Result<(ResourceId, Option<String>), AnyError> +) -> Result<(ResourceId, Option<String>), NetError> where NP: NetPermissions + 'static, { let permissions = state.borrow_mut::<NP>(); - let address_path = - permissions.check_read(&address_path, "Deno.listenDatagram()")?; - _ = permissions.check_write_path(&address_path, "Deno.listenDatagram()")?; + let address_path = permissions + .check_read(&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 local_addr = socket.local_addr()?; let pathname = local_addr.as_pathname().map(pathstring).transpose()?; @@ -222,7 +227,7 @@ where pub fn op_net_listen_unixpacket<NP>( state: &mut OpState, #[string] path: String, -) -> Result<(ResourceId, Option<String>), AnyError> +) -> Result<(ResourceId, Option<String>), NetError> where NP: NetPermissions + 'static, { @@ -235,13 +240,13 @@ where pub fn op_node_unstable_net_listen_unixpacket<NP>( state: &mut OpState, #[string] path: String, -) -> Result<(ResourceId, Option<String>), AnyError> +) -> Result<(ResourceId, Option<String>), NetError> where NP: NetPermissions + 'static, { 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()) } diff --git a/ext/net/resolve_addr.rs b/ext/net/resolve_addr.rs index 8bbdd5192..3a97081ea 100644 --- a/ext/net/resolve_addr.rs +++ b/ext/net/resolve_addr.rs @@ -1,6 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; use std::net::SocketAddr; use std::net::ToSocketAddrs; use tokio::net::lookup_host; @@ -9,7 +8,7 @@ use tokio::net::lookup_host; pub async fn resolve_addr( hostname: &str, 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 result = lookup_host(addr_port_pair).await?; Ok(result) @@ -19,7 +18,7 @@ pub async fn resolve_addr( pub fn resolve_addr_sync( hostname: &str, 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 result = addr_port_pair.to_socket_addrs()?; Ok(result) |