summaryrefslogtreecommitdiff
path: root/ext/net
diff options
context:
space:
mode:
authorYury Selivanov <yury@edgedb.com>2021-11-26 10:59:53 -0800
committerGitHub <noreply@github.com>2021-11-26 19:59:53 +0100
commit1d3f734e1815bf1649e0cac445be9eacb4cd296d (patch)
treef0178e951f3f44313def5d7ea8e2e391219f7791 /ext/net
parentd763633781be484bb19b458208dd7c11efb83228 (diff)
feat(ext/net): ALPN support in `Deno.connectTls()` (#12786)
Diffstat (limited to 'ext/net')
-rw-r--r--ext/net/02_tls.js12
-rw-r--r--ext/net/lib.deno_net.d.ts5
-rw-r--r--ext/net/ops.rs7
-rw-r--r--ext/net/ops_tls.rs69
4 files changed, 77 insertions, 16 deletions
diff --git a/ext/net/02_tls.js b/ext/net/02_tls.js
index 9ae6cb055..00acd7c96 100644
--- a/ext/net/02_tls.js
+++ b/ext/net/02_tls.js
@@ -41,6 +41,7 @@
caCerts = [],
certChain = undefined,
privateKey = undefined,
+ alpnProtocols = undefined,
}) {
const res = await opConnectTls({
port,
@@ -50,6 +51,7 @@
caCerts,
certChain,
privateKey,
+ alpnProtocols,
});
return new TlsConn(res.rid, res.remoteAddr, res.localAddr);
}
@@ -67,7 +69,7 @@
keyFile,
hostname = "0.0.0.0",
transport = "tcp",
- alpnProtocols,
+ alpnProtocols = undefined,
}) {
const res = opListenTls({
port,
@@ -82,13 +84,19 @@
async function startTls(
conn,
- { hostname = "127.0.0.1", certFile = undefined, caCerts = [] } = {},
+ {
+ hostname = "127.0.0.1",
+ certFile = undefined,
+ caCerts = [],
+ alpnProtocols = undefined,
+ } = {},
) {
const res = await opStartTls({
rid: conn.rid,
hostname,
certFile,
caCerts,
+ alpnProtocols,
});
return new TlsConn(res.rid, res.remoteAddr, res.localAddr);
}
diff --git a/ext/net/lib.deno_net.d.ts b/ext/net/lib.deno_net.d.ts
index 81c248871..accf01f96 100644
--- a/ext/net/lib.deno_net.d.ts
+++ b/ext/net/lib.deno_net.d.ts
@@ -52,11 +52,14 @@ declare namespace Deno {
closeWrite(): Promise<void>;
}
+ // deno-lint-ignore no-empty-interface
+ export interface TlsHandshakeInfo {}
+
export interface TlsConn extends Conn {
/** Runs the client or server handshake protocol to completion if that has
* not happened yet. Calling this method is optional; the TLS handshake
* will be completed automatically as soon as data is sent or received. */
- handshake(): Promise<void>;
+ handshake(): Promise<TlsHandshakeInfo>;
}
export interface ListenOptions {
diff --git a/ext/net/ops.rs b/ext/net/ops.rs
index d4fa2e5da..1f7005247 100644
--- a/ext/net/ops.rs
+++ b/ext/net/ops.rs
@@ -12,6 +12,7 @@ use deno_core::error::AnyError;
use deno_core::op_async;
use deno_core::op_sync;
use deno_core::AsyncRefCell;
+use deno_core::ByteString;
use deno_core::CancelHandle;
use deno_core::CancelTryFuture;
use deno_core::OpPair;
@@ -84,6 +85,12 @@ pub struct OpPacket {
pub remote_addr: OpAddr,
}
+#[derive(Serialize, Clone, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct TlsHandshakeInfo {
+ pub alpn_protocol: Option<ByteString>,
+}
+
#[derive(Serialize)]
pub struct IpAddr {
pub hostname: String,
diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs
index 87744ed63..fd2308ef1 100644
--- a/ext/net/ops_tls.rs
+++ b/ext/net/ops_tls.rs
@@ -4,6 +4,7 @@ use crate::io::TcpStreamResource;
use crate::ops::IpAddr;
use crate::ops::OpAddr;
use crate::ops::OpConn;
+use crate::ops::TlsHandshakeInfo;
use crate::resolve_addr::resolve_addr;
use crate::resolve_addr::resolve_addr_sync;
use crate::DefaultTlsOptions;
@@ -29,6 +30,7 @@ use deno_core::op_sync;
use deno_core::parking_lot::Mutex;
use deno_core::AsyncRefCell;
use deno_core::AsyncResult;
+use deno_core::ByteString;
use deno_core::CancelHandle;
use deno_core::CancelTryFuture;
use deno_core::OpPair;
@@ -54,7 +56,6 @@ use io::Read;
use io::Write;
use serde::Deserialize;
use std::borrow::Cow;
-use std::cell::Cell;
use std::cell::RefCell;
use std::convert::From;
use std::fs::File;
@@ -190,6 +191,14 @@ impl TlsStream {
fn poll_handshake(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.inner_mut().poll_handshake(cx)
}
+
+ fn get_alpn_protocol(&mut self) -> Option<ByteString> {
+ self
+ .inner_mut()
+ .tls
+ .get_alpn_protocol()
+ .map(|s| ByteString(s.to_owned()))
+ }
}
impl AsyncRead for TlsStream {
@@ -549,6 +558,10 @@ impl WriteHalf {
})
.await
}
+
+ fn get_alpn_protocol(&mut self) -> Option<ByteString> {
+ self.shared.get_alpn_protocol()
+ }
}
impl AsyncWrite for WriteHalf {
@@ -658,6 +671,11 @@ impl Shared {
fn drop_shared_waker(self_ptr: *const ()) {
let _ = unsafe { Weak::from_raw(self_ptr as *const Self) };
}
+
+ fn get_alpn_protocol(self: &Arc<Self>) -> Option<ByteString> {
+ let mut tls_stream = self.tls_stream.lock();
+ tls_stream.get_alpn_protocol()
+ }
}
struct ImplementReadTrait<'a, T>(&'a mut T);
@@ -698,7 +716,8 @@ pub fn init<P: NetPermissions + 'static>() -> Vec<OpPair> {
pub struct TlsStreamResource {
rd: AsyncRefCell<ReadHalf>,
wr: AsyncRefCell<WriteHalf>,
- handshake_done: Cell<bool>,
+ // `None` when a TLS handshake hasn't been done.
+ handshake_info: RefCell<Option<TlsHandshakeInfo>>,
cancel_handle: CancelHandle, // Only read and handshake ops get canceled.
}
@@ -707,7 +726,7 @@ impl TlsStreamResource {
Self {
rd: rd.into(),
wr: wr.into(),
- handshake_done: Cell::new(false),
+ handshake_info: RefCell::new(None),
cancel_handle: Default::default(),
}
}
@@ -744,14 +763,21 @@ impl TlsStreamResource {
Ok(())
}
- pub async fn handshake(self: &Rc<Self>) -> Result<(), AnyError> {
- if !self.handshake_done.get() {
- let mut wr = RcRef::map(self, |r| &r.wr).borrow_mut().await;
- let cancel_handle = RcRef::map(self, |r| &r.cancel_handle);
- wr.handshake().try_or_cancel(cancel_handle).await?;
- self.handshake_done.set(true);
+ pub async fn handshake(
+ self: &Rc<Self>,
+ ) -> Result<TlsHandshakeInfo, AnyError> {
+ if let Some(tls_info) = &*self.handshake_info.borrow() {
+ return Ok(tls_info.clone());
}
- Ok(())
+
+ let mut wr = RcRef::map(self, |r| &r.wr).borrow_mut().await;
+ let cancel_handle = RcRef::map(self, |r| &r.cancel_handle);
+ wr.handshake().try_or_cancel(cancel_handle).await?;
+
+ let alpn_protocol = wr.get_alpn_protocol();
+ let tls_info = TlsHandshakeInfo { alpn_protocol };
+ self.handshake_info.replace(Some(tls_info.clone()));
+ Ok(tls_info)
}
}
@@ -787,6 +813,7 @@ pub struct ConnectTlsArgs {
ca_certs: Vec<String>,
cert_chain: Option<String>,
private_key: Option<String>,
+ alpn_protocols: Option<Vec<String>>,
}
#[derive(Deserialize)]
@@ -795,6 +822,7 @@ pub struct StartTlsArgs {
rid: ResourceId,
ca_certs: Vec<String>,
hostname: String,
+ alpn_protocols: Option<Vec<String>>,
}
pub async fn op_tls_start<NP>(
@@ -851,11 +879,20 @@ where
let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?;
- let tls_config = Arc::new(create_client_config(
+ let mut tls_config = create_client_config(
root_cert_store,
ca_certs,
unsafely_ignore_certificate_errors,
- )?);
+ )?;
+
+ if let Some(alpn_protocols) = args.alpn_protocols {
+ super::check_unstable2(&state, "Deno.startTls#alpnProtocols");
+ tls_config.alpn_protocols =
+ alpn_protocols.into_iter().map(|s| s.into_bytes()).collect();
+ }
+
+ let tls_config = Arc::new(tls_config);
+
let tls_stream =
TlsStream::new_client_side(tcp_stream, &tls_config, hostname_dns);
@@ -948,6 +985,12 @@ where
unsafely_ignore_certificate_errors,
)?;
+ if let Some(alpn_protocols) = args.alpn_protocols {
+ super::check_unstable2(&state, "Deno.connectTls#alpnProtocols");
+ tls_config.alpn_protocols =
+ alpn_protocols.into_iter().map(|s| s.into_bytes()).collect();
+ }
+
if args.cert_chain.is_some() || args.private_key.is_some() {
let cert_chain = args
.cert_chain
@@ -1144,7 +1187,7 @@ pub async fn op_tls_handshake(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
_: (),
-) -> Result<(), AnyError> {
+) -> Result<TlsHandshakeInfo, AnyError> {
let resource = state
.borrow()
.resource_table