0.34.6_repo_cleanup

This commit is contained in:
Mateusz Gruszczyński committed 2026-10-22 09:31:15 +02:00
1 parent ce1a90397c
commit 133d2f0f91
273 files changed
+5969 -6926

No files matched your search

-34
View File
@@ -22,8 +22,6 @@ use std::{
time::{Duration, Instant},
};
/// Hyper's public error chain omits the GOAWAY reason, but Debug retains
/// the peer-initiated H2 `NO_ERROR` variant. Restrict this to graceful closure.
pub fn is_graceful_h2_goaway(error: &(dyn std::error::Error + 'static)) -> bool {
let chain = format!("{error:?}");
chain.contains("GoAway(") && chain.contains("NO_ERROR") && chain.contains("Remote")
@@ -64,12 +62,6 @@ struct RotatingClient {
graceful_goaway_at_ms: AtomicU64,
}
/// Backend HTTP client with bounded generation lifetime.
///
/// Hyper reuses a client/pool for efficiency. Under sustained traffic that also
/// makes connection/TLS/buffer high-water allocations live as long as the
/// compiled vhost snapshot. Recycling only this client generation bounds that
/// lifetime without reloading the vhost or touching cache/configuration state.
#[derive(Clone)]
pub struct ProxyClient {
inner: Arc<RotatingClient>,
@@ -127,8 +119,6 @@ impl ProxyClient {
match &response {
Ok(value) => self.inner.observe_protocol(value.version()),
Err(error) if is_graceful_h2_goaway(error) => {
// Also applies to cache refresh and other backend HTTP callers,
// not only the regular forward loop.
self.note_graceful_goaway(generation);
}
Err(_) => {}
@@ -136,8 +126,6 @@ impl ProxyClient {
response
}
/// A peer may gracefully close a reused H2 connection. Discard only the
/// affected client generation; concurrent requests must not rotate again.
pub fn note_graceful_goaway(&self, generation: u64) {
self.inner
.graceful_goaway_at_ms
@@ -145,8 +133,6 @@ impl ProxyClient {
self.inner.rotate(generation, "h2_goaway_no_error", false);
}
/// A cancellation immediately following GOAWAY may be another stream on
/// the closing H2 connection. Keep this correlation window short.
pub fn recently_saw_graceful_goaway(&self) -> bool {
let at = self.inner.graceful_goaway_at_ms.load(Ordering::Acquire);
at != 0 && monotonic_millis().saturating_add(1).saturating_sub(at) <= 1_000
@@ -160,15 +146,10 @@ impl ProxyClient {
self.inner.stats()
}
/// Whether a newly compiled backend client has exactly the same connection
/// policy and lifecycle settings as this one. Compatible clients can be
/// retained across unrelated snapshot rebuilds so generation age and
/// rotation counters are not restarted from zero.
pub(crate) fn reusable_with(&self, other: &Self) -> bool {
self.inner.factory == other.inner.factory
}
/// Recycle an aged connection pool even when no user request arrives.
pub(crate) fn maintain_rotation(&self) {
self.inner.maintain_rotation();
}
@@ -276,8 +257,6 @@ impl RotatingClient {
Ok(client) => {
let next_generation = observed_generation.saturating_add(1);
self.current.store(Arc::new(client));
// Request-driven rotation sends the triggering request through
// the new generation. Maintenance-driven rotation happens idle.
self.generation_requests
.store(if triggering_request { 1 } else { 0 }, Ordering::Relaxed);
self.generation_started_ms
@@ -292,9 +271,6 @@ impl RotatingClient {
);
}
Err(error) => {
// The same immutable settings built the current client. If a
// future dependency makes rebuilding fail, keep serving through
// the current generation and retry only after another interval.
self.generation_requests.store(0, Ordering::Relaxed);
self.generation_started_ms
.store(monotonic_millis(), Ordering::Relaxed);
@@ -352,9 +328,6 @@ fn build_raw_client(factory: &ClientFactory) -> Result<RawProxyClient> {
let keepalive = &factory.keepalive;
let timeout = factory.timeout;
let is_https = url::Url::parse(&backend.url)?.scheme() == "https";
// WebSocket HTTP/1.1 Upgrade retains its isolated H1 client. Preserve
// the 0.32.2 `http2` meaning: HTTPS allows H2/H1 via ALPN, while
// plaintext uses H2C. Only the NEW `h2` value is strict on HTTPS.
let protocol = if websocket {
UpstreamProtocol::Http1
} else if is_https && backend.protocol == UpstreamProtocol::Http2 {
@@ -409,10 +382,6 @@ fn build_raw_client(factory: &ClientFactory) -> Result<RawProxyClient> {
let builder = HttpsConnectorBuilder::new()
.with_tls_config(config)
.https_or_http();
// TLS Auto offers h2 then HTTP/1.1 in a single handshake. Negotiating
// HTTP/1.1 here happens *before* any request is sent: there is no unsafe
// automatic replay after a timed-out or partially delivered POST/PATCH.
// Cleartext Auto uses H1; H2C requires the explicit Http2 mode.
let protocol = if !is_https && protocol == UpstreamProtocol::Auto {
UpstreamProtocol::Http1
} else {
@@ -449,9 +418,6 @@ fn build_raw_client(factory: &ClientFactory) -> Result<RawProxyClient> {
)
.http2_keep_alive_timeout(Duration::from_secs(10))
.http2_keep_alive_while_idle(false);
// The request URI is free to carry the preserved public H2 :authority,
// while TLS SNI/verification uses tls_server_name (or backend URL) and
// DNS/TCP remains restricted to backend.url by GuardedResolver.
let origin = url::Url::parse(&backend.url)?;
let network_host = match origin.host().context("backend host missing")? {
url::Host::Ipv6(ip) => format!("[{ip}]"),
-2
View File
@@ -17,8 +17,6 @@ mod tests {
let client = client(&backend, AddressPolicy::new(&backend).unwrap(), false).unwrap();
assert_eq!(client.protocol_stats().last_version, None);
let shared = client.clone();
// Exercise the response-version recorder independently of the network;
// a live TLS ALPN acceptance test must still run on staging.
shared.inner.observe_protocol(Version::HTTP_11);
shared.inner.observe_protocol(Version::HTTP_2);
let observed = client.protocol_stats();
-7
View File
@@ -1,4 +1,3 @@
// Real Hyper + Rustls upstream peers, independent of the Python mock.
async fn tls_origin(
offer_h2: bool,
) -> (
@@ -26,8 +25,6 @@ async fn tls_origin(
let (observed_tx, observed_rx) = tokio::sync::oneshot::channel();
let server = tokio::spawn(async move {
let (tcp, _) = listener.accept().await.unwrap();
// For an H2-only client and H1-only server, negotiation can fail
// before any HTTP request is delivered. That is the desired error.
let Ok(tls) = acceptor.accept(tcp).await else {
return;
};
@@ -222,8 +219,6 @@ fn default_protocol_and_serialization_are_backward_compatible() {
}
}
// Exercise real TLS ALPN and the actual Hyper connector rather than only the
// local authority helper. The public Host must never become a DNS/TCP target.
async fn tls_authority_origin(
offer_h2: bool,
) -> (
@@ -334,8 +329,6 @@ async fn auto_h2_alpn_retains_same_public_host_and_pinned_tls_origin() {
assert_eq!(response.version(), Version::HTTP_2);
let (version, authority, host, sni) = seen.await.unwrap();
assert_eq!(version, Version::HTTP_2);
// Legacy Hyper may preserve H1-compatible Host on ALPN H2; neither value
// may select a different origin or differ from the intended public name.
assert_eq!(authority.or(host).as_deref(), Some("unitraklub.pl"));
assert_eq!(sni.as_deref(), Some("localhost"));
server.abort();
-2
View File
@@ -80,8 +80,6 @@ mod tests {
#[tokio::test]
async fn explicit_h2c_backend_uses_http2_prior_knowledge() {
// The persisted HTTP/2 value and the new strict H2 value both retain
// plaintext HTTP/2 prior knowledge, with no HTTP/1.1 probe.
for mode in ["http2", "h2"] {
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let address = listener.local_addr().unwrap();