Skip to content

Commit b39e93f

Browse files
authored
net: Add http_version to HttpRouteFragment and ConnectionConfig
Setting this at the route level is a requirement that doesn't quite match up with the "negotiation" part of ALPN. However, we currently know exactly which HTTP version we'll use to connect to any given server: HTTP/1.1, unless we specifically know in advance the server supports H2. That's sufficient for our uses here.
1 parent 8894050 commit b39e93f

File tree

13 files changed

+75
-14
lines changed

13 files changed

+75
-14
lines changed

rust/bridge/shared/testing/src/net_env.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use libsignal_net::enclave::{Cdsi, EnclaveEndpoint, EndpointParams, MrEnclave, S
1212
use libsignal_net::env::{ConnectionConfig, DomainConfig, Env, KeyTransConfig, SvrBEnv};
1313
use libsignal_net::infra::RECOMMENDED_WS_CONFIG;
1414
use libsignal_net::infra::certs::RootCertificates;
15+
use libsignal_net::infra::route::HttpVersion;
1516

1617
const ENCLAVE_ID_MOCK_SERVER: &[u8] = b"0.20240911.184407";
1718

@@ -27,6 +28,7 @@ fn localhost_test_domain_config_with_port_and_cert(
2728
hostname: "localhost",
2829
port,
2930
cert: RootCertificates::FromDer(std::borrow::Cow::Owned(root_certificate_der.to_vec())),
31+
http_version: Some(HttpVersion::Http1_1),
3032
min_tls_version: None,
3133
confirmation_header_name: None,
3234
proxy: None,

rust/net/examples/dns_custom_lookup.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use libsignal_net_infra::Alpn;
1616
use libsignal_net_infra::dns::dns_transport_doh::DohTransportConnectorFactory;
1717
use libsignal_net_infra::dns::dns_transport_udp::UdpTransportConnectorFactory;
1818
use libsignal_net_infra::route::{
19-
HttpRouteFragment, HttpsTlsRoute, TcpRoute, TlsRoute, TlsRouteFragment, UdpRoute,
19+
HttpRouteFragment, HttpVersion, HttpsTlsRoute, TcpRoute, TlsRoute, TlsRouteFragment, UdpRoute,
2020
};
2121
use libsignal_net_infra::timeouts::DNS_LATER_RESPONSE_GRACE_PERIOD;
2222
use libsignal_net_infra::utils::no_network_change_events;
@@ -70,6 +70,7 @@ async fn main() {
7070
fragment: HttpRouteFragment {
7171
host_header: host.clone(),
7272
path_prefix: "".into(),
73+
http_version: Some(HttpVersion::Http2),
7374
front_name: None,
7475
},
7576
inner: TlsRoute {

rust/net/examples/dns_over_https.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ use std::sync::Arc;
88

99
use clap::Parser;
1010
use futures_util::StreamExt;
11+
use libsignal_net::infra::Alpn;
1112
use libsignal_net::infra::certs::RootCertificates;
1213
use libsignal_net::infra::dns::custom_resolver::DnsTransport;
1314
use libsignal_net::infra::dns::dns_lookup::DnsLookupRequest;
15+
use libsignal_net::infra::dns::dns_transport_doh::DohTransportConnector;
1416
use libsignal_net::infra::host::Host;
15-
use libsignal_net_infra::Alpn;
16-
use libsignal_net_infra::dns::dns_transport_doh::DohTransportConnector;
17-
use libsignal_net_infra::route::{
18-
HttpRouteFragment, HttpsTlsRoute, NoDelay, TcpRoute, TlsRoute, TlsRouteFragment,
17+
use libsignal_net::infra::route::{
18+
HttpRouteFragment, HttpVersion, HttpsTlsRoute, NoDelay, TcpRoute, TlsRoute, TlsRouteFragment,
1919
};
2020

2121
#[derive(Parser, Debug)]
@@ -49,6 +49,7 @@ async fn main() {
4949
fragment: HttpRouteFragment {
5050
host_header: host.clone(),
5151
path_prefix: "".into(),
52+
http_version: Some(HttpVersion::Http2),
5253
front_name: None,
5354
},
5455
inner: TlsRoute {

rust/net/infra/src/dns.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ use crate::dns::dns_utils::log_safe_domain;
2323
use crate::dns::lookup_result::LookupResult;
2424
use crate::host::Host;
2525
use crate::route::{
26-
DEFAULT_HTTPS_PORT, HttpRouteFragment, HttpsTlsRoute, TcpRoute, TlsRoute, TlsRouteFragment,
26+
DEFAULT_HTTPS_PORT, HttpRouteFragment, HttpVersion, HttpsTlsRoute, TcpRoute, TlsRoute,
27+
TlsRouteFragment,
2728
};
2829
use crate::timeouts::{
2930
DNS_LATER_RESPONSE_GRACE_PERIOD, DNS_SYSTEM_LOOKUP_TIMEOUT, DOH_FALLBACK_LOOKUP_TIMEOUT,
@@ -106,6 +107,7 @@ pub fn build_custom_resolver_cloudflare_doh(
106107
path_prefix: "".into(),
107108
front_name: None,
108109
host_header: Arc::from(host.to_string()),
110+
http_version: Some(HttpVersion::Http2),
109111
},
110112
inner: TlsRoute {
111113
fragment: TlsRouteFragment {

rust/net/infra/src/http_client.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use hyper_util::rt::{TokioExecutor, TokioIo};
1818
use static_assertions::assert_impl_all;
1919

2020
use crate::errors::{LogSafeDisplay, TransportConnectError};
21-
use crate::route::{Connector, HttpRouteFragment};
21+
use crate::route::{Connector, HttpRouteFragment, HttpVersion};
2222
use crate::{AsyncDuplexStream, Connection};
2323

2424
#[derive(displaydoc::Display, Debug)]
@@ -243,9 +243,14 @@ where
243243
let HttpRouteFragment {
244244
host_header,
245245
path_prefix,
246+
http_version,
246247
front_name: _,
247248
} = route;
248249

250+
if http_version != Some(HttpVersion::Http2) {
251+
return Err(HttpConnectError::InvalidConfig("wrong HTTP version"));
252+
}
253+
249254
let info = over.transport_info();
250255
let io = TokioIo::new(over);
251256
let (sender, connection) = http2::Builder::new(TokioExecutor::new())
@@ -436,6 +441,7 @@ mod test {
436441
fragment: HttpRouteFragment {
437442
host_header: Arc::clone(&host),
438443
path_prefix: prefix.into(),
444+
http_version: Some(HttpVersion::Http2),
439445
front_name: None,
440446
},
441447
inner: TlsRoute {
@@ -513,6 +519,7 @@ mod test {
513519
fragment: HttpRouteFragment {
514520
host_header,
515521
path_prefix: "".into(),
522+
http_version: Some(HttpVersion::Http2),
516523
front_name: None,
517524
},
518525
inner: TlsRoute {

rust/net/infra/src/route.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ mod test {
761761
fragment: HttpRouteFragment {
762762
host_header: "http-host".into(),
763763
path_prefix: "".into(),
764+
http_version: Some(HttpVersion::Http1_1),
764765
front_name: None,
765766
},
766767
inner: TlsRoute {
@@ -787,6 +788,7 @@ mod test {
787788
fragment: HttpRouteFragment {
788789
host_header: "front-host".into(),
789790
path_prefix: "/front-host-path-prefix".into(),
791+
http_version: Some(HttpVersion::Http2),
790792
front_name: Some("front-host"),
791793
},
792794
inner: TlsRoute {
@@ -813,6 +815,7 @@ mod test {
813815
fragment: HttpRouteFragment {
814816
host_header: "front-host".into(),
815817
path_prefix: "/front-host-path-prefix".into(),
818+
http_version: Some(HttpVersion::Http2),
816819
front_name: Some("front-host"),
817820
},
818821
inner: TlsRoute {

rust/net/infra/src/route/http.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ pub const DEFAULT_HTTPS_PORT: NonZeroU16 = nonzero!(443u16);
2222
pub struct HttpRouteFragment {
2323
pub host_header: Arc<str>,
2424
pub path_prefix: Arc<str>,
25+
/// If present, the connector may *assume* we'll be using this HTTP version.
26+
///
27+
/// This isn't fully compliant with the H2 standard, RFC 7540; if we're using TLS, we should
28+
/// always check the ALPN result before going ahead with an H2 connection. However, at the time
29+
/// of this writing (Nov 2025) we don't connect to arbitrary servers with H2, only those we
30+
/// already know should support it. If we some day have a need to negotiate ALPN properly, we'll
31+
/// need to change [`TlsRouteFragment`] to accept multiple permitted ALPN values, and then once
32+
/// everything is threaded through we should be able to remove this field (treating "no ALPN" as
33+
/// "assume HTTP/1.1 only").
34+
pub http_version: Option<HttpVersion>,
2535
/// Only for logging; the name of the domain front for this proxy.
2636
pub front_name: Option<&'static str>,
2737
}
@@ -47,7 +57,7 @@ pub struct DomainFrontRouteProvider {
4757
/// This is distinct from [`http::Version`] since only a subset of versions are
4858
/// supported, and is distinct from [`Alpn`] which is TLS-specific and could in
4959
/// theory represent non-HTTP-version values.
50-
#[derive(Copy, Clone, Debug)]
60+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
5161
pub enum HttpVersion {
5262
Http1_1,
5363
Http2,
@@ -141,6 +151,7 @@ impl RouteProvider for DomainFrontRouteProvider {
141151
fragment: HttpRouteFragment {
142152
host_header: Arc::clone(http_host),
143153
path_prefix: Arc::clone(path_prefix),
154+
http_version: Some(*http_version),
144155
front_name: Some(*front_name),
145156
},
146157
})
@@ -175,6 +186,7 @@ where
175186
fragment: HttpRouteFragment {
176187
host_header: Arc::clone(direct_host_header),
177188
path_prefix: "".into(),
189+
http_version: Some(*direct_http_version),
178190
front_name: None,
179191
},
180192
inner,
@@ -260,6 +272,7 @@ mod test {
260272
fragment: HttpRouteFragment {
261273
host_header: "direct-host".into(),
262274
path_prefix: "".into(),
275+
http_version: Some(HttpVersion::Http2),
263276
front_name: None,
264277
},
265278
inner: TlsRoute {
@@ -279,6 +292,7 @@ mod test {
279292
fragment: HttpRouteFragment {
280293
host_header: "front-host-1".into(),
281294
path_prefix: "/prefix-1".into(),
295+
http_version: Some(HttpVersion::Http1_1),
282296
front_name: Some("front-1")
283297
},
284298
inner: TlsRoute {
@@ -298,6 +312,7 @@ mod test {
298312
fragment: HttpRouteFragment {
299313
host_header: "front-host-1".into(),
300314
path_prefix: "/prefix-1".into(),
315+
http_version: Some(HttpVersion::Http1_1),
301316
front_name: Some("front-1")
302317
},
303318
inner: TlsRoute {
@@ -317,6 +332,7 @@ mod test {
317332
fragment: HttpRouteFragment {
318333
host_header: "front-host-2".into(),
319334
path_prefix: "/prefix-2".into(),
335+
http_version: Some(HttpVersion::Http1_1),
320336
front_name: Some("front-2")
321337
},
322338
inner: TlsRoute {

rust/net/infra/src/route/resolve.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ mod test {
677677
let http_fragment = HttpRouteFragment {
678678
host_header: "target-domain".into(),
679679
path_prefix: "".into(),
680+
http_version: None,
680681
front_name: None,
681682
};
682683

rust/net/infra/src/ws.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use tungstenite::{Message, Utf8Bytes, http};
1313

1414
use crate::AsyncDuplexStream;
1515
use crate::errors::LogSafeDisplay;
16-
use crate::route::{Connector, HttpRouteFragment, WebSocketRouteFragment};
16+
use crate::route::{Connector, HttpRouteFragment, HttpVersion, WebSocketRouteFragment};
1717
use crate::ws::error::{HttpFormatError, ProtocolError, SpaceError};
1818

1919
pub mod error;
@@ -136,10 +136,15 @@ where
136136
HttpRouteFragment {
137137
host_header,
138138
path_prefix,
139+
http_version,
139140
front_name: _,
140141
},
141142
) = route;
142143

144+
if !matches!(http_version, None | Some(HttpVersion::Http1_1)) {
145+
unimplemented!("can only connect over HTTP/1.1 right now");
146+
}
147+
143148
let uri_path = if path_prefix.is_empty() {
144149
Ok(endpoint)
145150
} else {
@@ -323,6 +328,7 @@ pub mod testutil {
323328
HttpRouteFragment {
324329
host_header: "localhost".into(),
325330
path_prefix: "".into(),
331+
http_version: Some(HttpVersion::Http1_1),
326332
front_name: None,
327333
},
328334
),

rust/net/src/chat.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ pub(crate) mod test {
519519
use libsignal_net_infra::host::Host;
520520
use libsignal_net_infra::route::testutils::ConnectFn;
521521
use libsignal_net_infra::route::{
522-
DEFAULT_HTTPS_PORT, DirectOrProxyRoute, HttpRouteFragment, HttpsTlsRoute,
522+
DEFAULT_HTTPS_PORT, DirectOrProxyRoute, HttpRouteFragment, HttpVersion, HttpsTlsRoute,
523523
PreconnectingFactory, TcpRoute, TlsRoute, TlsRouteFragment, UnresolvedHost,
524524
};
525525
use libsignal_net_infra::utils::no_network_change_events;
@@ -735,6 +735,7 @@ pub(crate) mod test {
735735
fragment: HttpRouteFragment {
736736
host_header: CHAT_DOMAIN.into(),
737737
path_prefix: "".into(),
738+
http_version: Some(HttpVersion::Http1_1),
738739
front_name: None,
739740
},
740741
inner: TlsRoute {
@@ -799,6 +800,7 @@ pub(crate) mod test {
799800
fragment: HttpRouteFragment {
800801
host_header: CHAT_DOMAIN.into(),
801802
path_prefix: "".into(),
803+
http_version: Some(HttpVersion::Http1_1),
802804
front_name: None,
803805
},
804806
inner: TlsRoute {

0 commit comments

Comments
 (0)