From ff5d072702aee52882787ea85dd73573a8f8f316 Mon Sep 17 00:00:00 2001 From: Aaron O'Mullan Date: Tue, 6 Apr 2021 10:33:43 +0200 Subject: [PATCH] refactor: rewrite "net" ops to use serde_v8 (#10028) --- runtime/ops/fs.rs | 8 +- runtime/ops/mod.rs | 1 + runtime/ops/net.rs | 198 +++++++++++++++++++++++----------------- runtime/ops/net_unix.rs | 50 +++++----- runtime/ops/os.rs | 11 +-- runtime/ops/tls.rs | 103 ++++++++++----------- runtime/ops/utils.rs | 10 ++ 7 files changed, 206 insertions(+), 175 deletions(-) create mode 100644 runtime/ops/utils.rs diff --git a/runtime/ops/fs.rs b/runtime/ops/fs.rs index d965f768df..3d9802b08a 100644 --- a/runtime/ops/fs.rs +++ b/runtime/ops/fs.rs @@ -1,6 +1,7 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. // Some deserializer fields are only used on Unix and Windows build fails without it use super::io::StdFileResource; +use super::utils::into_string; use crate::fs_util::canonicalize_path; use crate::permissions::Permissions; use deno_core::error::bad_resource_id; @@ -108,13 +109,6 @@ pub fn init(rt: &mut deno_core::JsRuntime) { super::reg_json_async(rt, "op_utime_async", op_utime_async); } -fn into_string(s: std::ffi::OsString) -> Result { - s.into_string().map_err(|s| { - let message = format!("File name or path {:?} is not valid UTF-8", s); - custom_error("InvalidData", message) - }) -} - #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct OpenArgs { diff --git a/runtime/ops/mod.rs b/runtime/ops/mod.rs index b497f6a42a..6574546b17 100644 --- a/runtime/ops/mod.rs +++ b/runtime/ops/mod.rs @@ -18,6 +18,7 @@ pub mod timers; pub mod tls; pub mod tty; pub mod url; +mod utils; pub mod web_worker; pub mod webgpu; pub mod websocket; diff --git a/runtime/ops/net.rs b/runtime/ops/net.rs index 224fb5570f..48431ef22b 100644 --- a/runtime/ops/net.rs +++ b/runtime/ops/net.rs @@ -9,8 +9,6 @@ use deno_core::error::generic_error; use deno_core::error::null_opbuf; use deno_core::error::type_error; use deno_core::error::AnyError; -use deno_core::serde_json::json; -use deno_core::serde_json::Value; use deno_core::AsyncRefCell; use deno_core::CancelHandle; use deno_core::CancelTryFuture; @@ -53,6 +51,39 @@ pub fn init(rt: &mut deno_core::JsRuntime) { super::reg_json_async(rt, "op_dns_resolve", op_dns_resolve); } +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct OpConn { + pub rid: ResourceId, + pub remote_addr: Option, + pub local_addr: Option, +} + +#[derive(Serialize)] +#[serde(tag = "transport", rename_all = "lowercase")] +pub enum OpAddr { + Tcp(IpAddr), + Udp(IpAddr), + #[cfg(unix)] + Unix(net_unix::UnixAddr), + #[cfg(unix)] + UnixPacket(net_unix::UnixAddr), +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +/// A received datagram packet (from udp or unixpacket) +pub struct OpPacket { + pub size: usize, + pub remote_addr: OpAddr, +} + +#[derive(Serialize)] +pub struct IpAddr { + pub hostname: String, + pub port: u16, +} + #[derive(Deserialize)] pub(crate) struct AcceptArgs { pub rid: ResourceId, @@ -63,7 +94,7 @@ async fn accept_tcp( state: Rc>, args: AcceptArgs, _zero_copy: Option, -) -> Result { +) -> Result { let rid = args.rid; let resource = state @@ -91,37 +122,36 @@ async fn accept_tcp( let rid = state .resource_table .add(TcpStreamResource::new(tcp_stream.into_split())); - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": "tcp", - }, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": "tcp", - } - })) + Ok(OpConn { + rid, + local_addr: Some(OpAddr::Tcp(IpAddr { + hostname: local_addr.ip().to_string(), + port: local_addr.port(), + })), + remote_addr: Some(OpAddr::Tcp(IpAddr { + hostname: remote_addr.ip().to_string(), + port: remote_addr.port(), + })), + }) } async fn op_accept( state: Rc>, args: AcceptArgs, _buf: Option, -) -> Result { +) -> Result { match args.transport.as_str() { "tcp" => accept_tcp(state, args, _buf).await, #[cfg(unix)] "unix" => net_unix::accept_unix(state, args, _buf).await, - _ => Err(generic_error(format!( - "Unsupported transport protocol {}", - args.transport - ))), + other => Err(bad_transport(other)), } } +fn bad_transport(transport: &str) -> AnyError { + generic_error(format!("Unsupported transport protocol {}", transport)) +} + #[derive(Deserialize)] pub(crate) struct ReceiveArgs { pub rid: ResourceId, @@ -132,7 +162,7 @@ async fn receive_udp( state: Rc>, args: ReceiveArgs, zero_copy: Option, -) -> Result { +) -> Result { let zero_copy = zero_copy.ok_or_else(null_opbuf)?; let mut zero_copy = zero_copy.clone(); @@ -149,29 +179,25 @@ async fn receive_udp( .recv_from(&mut zero_copy) .try_or_cancel(cancel_handle) .await?; - Ok(json!({ - "size": size, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": "udp", - } - })) + Ok(OpPacket { + size, + remote_addr: OpAddr::Udp(IpAddr { + hostname: remote_addr.ip().to_string(), + port: remote_addr.port(), + }), + }) } async fn op_datagram_receive( state: Rc>, args: ReceiveArgs, zero_copy: Option, -) -> Result { +) -> Result { match args.transport.as_str() { "udp" => receive_udp(state, args, zero_copy).await, #[cfg(unix)] "unixpacket" => net_unix::receive_unix_packet(state, args, zero_copy).await, - _ => Err(generic_error(format!( - "Unsupported transport protocol {}", - args.transport - ))), + other => Err(bad_transport(other)), } } @@ -187,7 +213,7 @@ async fn op_datagram_send( state: Rc>, args: SendArgs, zero_copy: Option, -) -> Result { +) -> Result { let zero_copy = zero_copy.ok_or_else(null_opbuf)?; let zero_copy = zero_copy.clone(); @@ -215,7 +241,7 @@ async fn op_datagram_send( .ok_or_else(|| bad_resource("Socket has been closed"))?; let socket = RcRef::map(&resource, |r| &r.socket).borrow().await; let byte_length = socket.send_to(&zero_copy, &addr).await?; - Ok(json!(byte_length)) + Ok(byte_length) } #[cfg(unix)] SendArgs { @@ -239,7 +265,7 @@ async fn op_datagram_send( .try_borrow_mut() .ok_or_else(|| custom_error("Busy", "Socket already in use"))?; let byte_length = socket.send_to(&zero_copy, address_path).await?; - Ok(json!(byte_length)) + Ok(byte_length) } _ => Err(type_error("Wrong argument format!")), } @@ -256,7 +282,7 @@ async fn op_connect( state: Rc>, args: ConnectArgs, _zero_copy: Option, -) -> Result { +) -> Result { match args { ConnectArgs { transport, @@ -281,19 +307,17 @@ async fn op_connect( let rid = state_ .resource_table .add(TcpStreamResource::new(tcp_stream.into_split())); - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": transport, - }, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": transport, - } - })) + Ok(OpConn { + rid, + local_addr: Some(OpAddr::Tcp(IpAddr { + hostname: local_addr.ip().to_string(), + port: local_addr.port(), + })), + remote_addr: Some(OpAddr::Tcp(IpAddr { + hostname: remote_addr.ip().to_string(), + port: remote_addr.port(), + })), + }) } #[cfg(unix)] ConnectArgs { @@ -315,17 +339,15 @@ async fn op_connect( let mut state_ = state.borrow_mut(); let resource = UnixStreamResource::new(unix_stream.into_split()); let rid = state_.resource_table.add(resource); - Ok(json!({ - "rid": rid, - "localAddr": { - "path": local_addr.as_pathname(), - "transport": transport, - }, - "remoteAddr": { - "path": remote_addr.as_pathname(), - "transport": transport, - } - })) + Ok(OpConn { + rid, + local_addr: Some(OpAddr::Unix(net_unix::UnixAddr { + path: local_addr.as_pathname().and_then(net_unix::pathstring), + })), + remote_addr: Some(OpAddr::Unix(net_unix::UnixAddr { + path: remote_addr.as_pathname().and_then(net_unix::pathstring), + })), + }) } _ => Err(type_error("Wrong argument format!")), } @@ -420,7 +442,7 @@ fn op_listen( state: &mut OpState, args: ListenArgs, _zero_copy: Option, -) -> Result { +) -> Result { let permissions = state.borrow::(); match args { ListenArgs { @@ -447,14 +469,20 @@ fn op_listen( local_addr.ip().to_string(), local_addr.port() ); - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": transport, - }, - })) + let ip_addr = IpAddr { + hostname: local_addr.ip().to_string(), + port: local_addr.port(), + }; + Ok(OpConn { + rid, + local_addr: Some(match transport.as_str() { + "udp" => OpAddr::Udp(ip_addr), + "tcp" => OpAddr::Tcp(ip_addr), + // NOTE: This could be unreachable!() + other => return Err(bad_transport(other)), + }), + remote_addr: None, + }) } #[cfg(unix)] ListenArgs { @@ -482,13 +510,19 @@ fn op_listen( rid, local_addr.as_pathname().unwrap().display(), ); - Ok(json!({ - "rid": rid, - "localAddr": { - "path": local_addr.as_pathname(), - "transport": transport, - }, - })) + let unix_addr = net_unix::UnixAddr { + path: local_addr.as_pathname().and_then(net_unix::pathstring), + }; + + Ok(OpConn { + rid, + local_addr: Some(match transport.as_str() { + "unix" => OpAddr::Unix(unix_addr), + "unixpacket" => OpAddr::UnixPacket(unix_addr), + other => return Err(bad_transport(other)), + }), + remote_addr: None, + }) } #[cfg(unix)] _ => Err(type_error("Wrong argument format!")), @@ -546,7 +580,7 @@ async fn op_dns_resolve( state: Rc>, args: ResolveAddrArgs, _zero_copy: Option, -) -> Result { +) -> Result, AnyError> { let ResolveAddrArgs { query, record_type, @@ -584,7 +618,7 @@ async fn op_dns_resolve( let resolver = AsyncResolver::tokio(config, opts)?; - let results: Vec = resolver + let results = resolver .lookup(query, record_type, Default::default()) .await .map_err(|e| generic_error(format!("{}", e)))? @@ -592,7 +626,7 @@ async fn op_dns_resolve( .filter_map(rdata_to_return_record(record_type)) .collect(); - Ok(json!(results)) + Ok(results) } fn rdata_to_return_record( diff --git a/runtime/ops/net_unix.rs b/runtime/ops/net_unix.rs index 86c5ab8a04..4a2fbf1dec 100644 --- a/runtime/ops/net_unix.rs +++ b/runtime/ops/net_unix.rs @@ -1,14 +1,16 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. +use super::utils::into_string; use crate::ops::io::UnixStreamResource; use crate::ops::net::AcceptArgs; +use crate::ops::net::OpAddr; +use crate::ops::net::OpConn; +use crate::ops::net::OpPacket; use crate::ops::net::ReceiveArgs; use deno_core::error::bad_resource; use deno_core::error::custom_error; use deno_core::error::null_opbuf; use deno_core::error::AnyError; -use deno_core::serde_json::json; -use deno_core::serde_json::Value; use deno_core::AsyncRefCell; use deno_core::CancelHandle; use deno_core::CancelTryFuture; @@ -59,8 +61,7 @@ impl Resource for UnixDatagramResource { #[derive(Serialize)] pub struct UnixAddr { - pub path: String, - pub transport: String, + pub path: Option, } #[derive(Deserialize)] @@ -72,7 +73,7 @@ pub(crate) async fn accept_unix( state: Rc>, args: AcceptArgs, _bufs: Option, -) -> Result { +) -> Result { let rid = args.rid; let resource = state @@ -92,24 +93,22 @@ pub(crate) async fn accept_unix( let resource = UnixStreamResource::new(unix_stream.into_split()); let mut state = state.borrow_mut(); let rid = state.resource_table.add(resource); - Ok(json!({ - "rid": rid, - "localAddr": { - "path": local_addr.as_pathname(), - "transport": "unix", - }, - "remoteAddr": { - "path": remote_addr.as_pathname(), - "transport": "unix", - } - })) + Ok(OpConn { + rid, + local_addr: Some(OpAddr::Unix(UnixAddr { + path: local_addr.as_pathname().and_then(pathstring), + })), + remote_addr: Some(OpAddr::Unix(UnixAddr { + path: remote_addr.as_pathname().and_then(pathstring), + })), + }) } pub(crate) async fn receive_unix_packet( state: Rc>, args: ReceiveArgs, buf: Option, -) -> Result { +) -> Result { let mut buf = buf.ok_or_else(null_opbuf)?; let rid = args.rid; @@ -125,13 +124,12 @@ pub(crate) async fn receive_unix_packet( let cancel = RcRef::map(resource, |r| &r.cancel); let (size, remote_addr) = socket.recv_from(&mut buf).try_or_cancel(cancel).await?; - Ok(json!({ - "size": size, - "remoteAddr": { - "path": remote_addr.as_pathname(), - "transport": "unixpacket", - } - })) + Ok(OpPacket { + size, + remote_addr: OpAddr::UnixPacket(UnixAddr { + path: remote_addr.as_pathname().and_then(pathstring), + }), + }) } pub fn listen_unix( @@ -169,3 +167,7 @@ pub fn listen_unix_packet( Ok((rid, local_addr)) } + +pub fn pathstring(pathname: &Path) -> Option { + into_string(pathname.into()).ok() +} diff --git a/runtime/ops/os.rs b/runtime/ops/os.rs index 3e6feacfef..5f265bf20c 100644 --- a/runtime/ops/os.rs +++ b/runtime/ops/os.rs @@ -1,7 +1,8 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. +use super::utils::into_string; use crate::permissions::Permissions; -use deno_core::error::{custom_error, type_error, AnyError}; +use deno_core::error::{type_error, AnyError}; use deno_core::url::Url; use deno_core::OpState; use deno_core::ZeroCopyBuf; @@ -42,14 +43,6 @@ fn op_exec_path( into_string(path.into_os_string()) } -// TODO(@AaronO): share this code with fs' into_string() -fn into_string(s: std::ffi::OsString) -> Result { - s.into_string().map_err(|s| { - let message = format!("File name or path {:?} is not valid UTF-8", s); - custom_error("InvalidData", message) - }) -} - #[derive(Deserialize)] pub struct SetEnv { key: String, diff --git a/runtime/ops/tls.rs b/runtime/ops/tls.rs index e0cb992f01..d9c5f1854a 100644 --- a/runtime/ops/tls.rs +++ b/runtime/ops/tls.rs @@ -3,6 +3,9 @@ use super::io::TcpStreamResource; use super::io::TlsClientStreamResource; use super::io::TlsServerStreamResource; +use super::net::IpAddr; +use super::net::OpAddr; +use super::net::OpConn; use crate::permissions::Permissions; use crate::resolve_addr::resolve_addr; use crate::resolve_addr::resolve_addr_sync; @@ -11,8 +14,6 @@ use deno_core::error::bad_resource_id; use deno_core::error::custom_error; use deno_core::error::generic_error; use deno_core::error::AnyError; -use deno_core::serde_json::json; -use deno_core::serde_json::Value; use deno_core::AsyncRefCell; use deno_core::CancelHandle; use deno_core::CancelTryFuture; @@ -97,7 +98,7 @@ async fn op_start_tls( state: Rc>, args: StartTlsArgs, _zero_copy: Option, -) -> Result { +) -> Result { let rid = args.rid; let mut domain = args.hostname.as_str(); @@ -148,26 +149,26 @@ async fn op_start_tls( .resource_table .add(TlsClientStreamResource::from(tls_stream)) }; - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": "tcp", - }, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": "tcp", - } - })) + Ok(OpConn { + rid, + local_addr: Some(OpAddr::Tcp(IpAddr { + hostname: local_addr.ip().to_string(), + port: local_addr.port(), + })), + remote_addr: Some(OpAddr::Tcp(IpAddr { + hostname: remote_addr.ip().to_string(), + port: remote_addr.port(), + })), + }) } async fn op_connect_tls( state: Rc>, args: ConnectTlsArgs, _zero_copy: Option, -) -> Result { +) -> Result { + assert_eq!(args.transport, "tcp"); + { let s = state.borrow(); let permissions = s.borrow::(); @@ -208,19 +209,17 @@ async fn op_connect_tls( .resource_table .add(TlsClientStreamResource::from(tls_stream)) }; - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": args.transport, - }, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": args.transport, - } - })) + Ok(OpConn { + rid, + local_addr: Some(OpAddr::Tcp(IpAddr { + hostname: local_addr.ip().to_string(), + port: local_addr.port(), + })), + remote_addr: Some(OpAddr::Tcp(IpAddr { + hostname: remote_addr.ip().to_string(), + port: remote_addr.port(), + })), + }) } fn load_certs(path: &str) -> Result, AnyError> { @@ -307,7 +306,7 @@ fn op_listen_tls( state: &mut OpState, args: ListenTlsArgs, _zero_copy: Option, -) -> Result { +) -> Result { assert_eq!(args.transport, "tcp"); let cert_file = args.cert_file; @@ -338,21 +337,21 @@ fn op_listen_tls( let rid = state.resource_table.add(tls_listener_resource); - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": args.transport, - }, - })) + Ok(OpConn { + rid, + local_addr: Some(OpAddr::Tcp(IpAddr { + hostname: local_addr.ip().to_string(), + port: local_addr.port(), + })), + remote_addr: None, + }) } async fn op_accept_tls( state: Rc>, rid: ResourceId, _zero_copy: Option, -) -> Result { +) -> Result { let resource = state .borrow() .resource_table @@ -392,17 +391,15 @@ async fn op_accept_tls( .add(TlsServerStreamResource::from(tls_stream)) }; - Ok(json!({ - "rid": rid, - "localAddr": { - "transport": "tcp", - "hostname": local_addr.ip().to_string(), - "port": local_addr.port() - }, - "remoteAddr": { - "transport": "tcp", - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port() - } - })) + Ok(OpConn { + rid, + local_addr: Some(OpAddr::Tcp(IpAddr { + hostname: local_addr.ip().to_string(), + port: local_addr.port(), + })), + remote_addr: Some(OpAddr::Tcp(IpAddr { + hostname: remote_addr.ip().to_string(), + port: remote_addr.port(), + })), + }) } diff --git a/runtime/ops/utils.rs b/runtime/ops/utils.rs new file mode 100644 index 0000000000..881522b076 --- /dev/null +++ b/runtime/ops/utils.rs @@ -0,0 +1,10 @@ +use deno_core::error::custom_error; +use deno_core::error::AnyError; + +/// A utility function to map OsStrings to Strings +pub fn into_string(s: std::ffi::OsString) -> Result { + s.into_string().map_err(|s| { + let message = format!("File name or path {:?} is not valid UTF-8", s); + custom_error("InvalidData", message) + }) +}