From 42c426e7695a0037032d1ac5237830800eeaaed4 Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Wed, 1 Nov 2023 15:11:01 -0600 Subject: feat(ext/websocket): websockets over http2 (#21040) Implements `WebSocket` over http/2. This requires a conformant http/2 server supporting the extended connect protocol. Passes approximately 100 new WPT tests (mostly `?wpt_flags=h2` versions of existing websockets APIs). This is implemented as a fallback when http/1.1 fails, so a server that supports both h1 and h2 WebSockets will still end up on the http/1.1 upgrade path. The patch also cleas up the websockets handshake to split it up into http, https+http1 and https+http2, making it a little less intertwined. This uncovered a likely bug in the WPT test server: https://github.com/web-platform-tests/wpt/issues/42896 --- ext/tls/lib.rs | 47 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) (limited to 'ext/tls') diff --git a/ext/tls/lib.rs b/ext/tls/lib.rs index 323946601..3f276fcd0 100644 --- a/ext/tls/lib.rs +++ b/ext/tls/lib.rs @@ -157,11 +157,23 @@ pub fn create_default_root_cert_store() -> RootCertStore { root_cert_store } +pub enum SocketUse { + /// General SSL: No ALPN + GeneralSsl, + /// HTTP: h1 and h2 + Http, + /// http/1.1 only + Http1Only, + /// http/2 only + Http2Only, +} + pub fn create_client_config( root_cert_store: Option, ca_certs: Vec>, unsafely_ignore_certificate_errors: Option>, client_cert_chain_and_key: Option<(String, String)>, + socket_use: SocketUse, ) -> Result { let maybe_cert_chain_and_key = if let Some((cert_chain, private_key)) = client_cert_chain_and_key { @@ -184,7 +196,7 @@ pub fn create_client_config( // However it's not really feasible to deduplicate it as the `client_config` instances // are not type-compatible - one wants "client cert", the other wants "transparency policy // or client cert". - let client = + let mut client = if let Some((cert_chain, private_key)) = maybe_cert_chain_and_key { client_config .with_client_auth_cert(cert_chain, private_key) @@ -193,6 +205,7 @@ pub fn create_client_config( client_config.with_no_client_auth() }; + add_alpn(&mut client, socket_use); return Ok(client); } @@ -220,18 +233,34 @@ pub fn create_client_config( root_cert_store }); - let client = if let Some((cert_chain, private_key)) = maybe_cert_chain_and_key - { - client_config - .with_client_auth_cert(cert_chain, private_key) - .expect("invalid client key or certificate") - } else { - client_config.with_no_client_auth() - }; + let mut client = + if let Some((cert_chain, private_key)) = maybe_cert_chain_and_key { + client_config + .with_client_auth_cert(cert_chain, private_key) + .expect("invalid client key or certificate") + } else { + client_config.with_no_client_auth() + }; + add_alpn(&mut client, socket_use); Ok(client) } +fn add_alpn(client: &mut ClientConfig, socket_use: SocketUse) { + match socket_use { + SocketUse::Http1Only => { + client.alpn_protocols = vec!["http/1.1".into()]; + } + SocketUse::Http2Only => { + client.alpn_protocols = vec!["h2".into()]; + } + SocketUse::Http => { + client.alpn_protocols = vec!["h2".into(), "http/1.1".into()]; + } + SocketUse::GeneralSsl => {} + }; +} + pub fn load_certs( reader: &mut dyn BufRead, ) -> Result, AnyError> { -- cgit v1.2.3