feat(smart-proxy): add hot-reloadable global ingress security policy across Rust and TypeScript proxy layers
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
mod common;
|
||||
|
||||
use bytes::Buf;
|
||||
use common::*;
|
||||
use rustproxy::RustProxy;
|
||||
use rustproxy_config::{RustProxyOptions, TransportProtocol, RouteUdp, RouteQuic};
|
||||
use bytes::Buf;
|
||||
use rustproxy_config::{RouteQuic, RouteUdp, RustProxyOptions, TransportProtocol};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Build a route that listens on UDP with HTTP/3 enabled and TLS terminate.
|
||||
@@ -14,7 +14,14 @@ fn make_h3_route(
|
||||
cert_pem: &str,
|
||||
key_pem: &str,
|
||||
) -> rustproxy_config::RouteConfig {
|
||||
let mut route = make_tls_terminate_route(port, "localhost", target_host, target_port, cert_pem, key_pem);
|
||||
let mut route = make_tls_terminate_route(
|
||||
port,
|
||||
"localhost",
|
||||
target_host,
|
||||
target_port,
|
||||
cert_pem,
|
||||
key_pem,
|
||||
);
|
||||
route.route_match.transport = Some(TransportProtocol::All);
|
||||
// Keep domain="localhost" from make_tls_terminate_route — needed for TLS cert extraction
|
||||
route.action.udp = Some(RouteUdp {
|
||||
@@ -89,11 +96,9 @@ async fn test_h3_response_stream_finishes() {
|
||||
.await
|
||||
.expect("QUIC handshake failed");
|
||||
|
||||
let (mut driver, mut send_request) = h3::client::new(
|
||||
h3_quinn::Connection::new(connection),
|
||||
)
|
||||
.await
|
||||
.expect("H3 connection setup failed");
|
||||
let (mut driver, mut send_request) = h3::client::new(h3_quinn::Connection::new(connection))
|
||||
.await
|
||||
.expect("H3 connection setup failed");
|
||||
|
||||
// Drive the H3 connection in background
|
||||
tokio::spawn(async move {
|
||||
@@ -108,33 +113,46 @@ async fn test_h3_response_stream_finishes() {
|
||||
.body(())
|
||||
.unwrap();
|
||||
|
||||
let mut stream = send_request.send_request(req).await
|
||||
let mut stream = send_request
|
||||
.send_request(req)
|
||||
.await
|
||||
.expect("Failed to send H3 request");
|
||||
stream.finish().await
|
||||
stream
|
||||
.finish()
|
||||
.await
|
||||
.expect("Failed to finish sending H3 request body");
|
||||
|
||||
// 6. Read response headers
|
||||
let resp = stream.recv_response().await
|
||||
let resp = stream
|
||||
.recv_response()
|
||||
.await
|
||||
.expect("Failed to receive H3 response");
|
||||
assert_eq!(resp.status(), http::StatusCode::OK,
|
||||
"Expected 200 OK, got {}", resp.status());
|
||||
assert_eq!(
|
||||
resp.status(),
|
||||
http::StatusCode::OK,
|
||||
"Expected 200 OK, got {}",
|
||||
resp.status()
|
||||
);
|
||||
|
||||
// 7. Read body and verify stream ends (FIN received)
|
||||
// This is the critical assertion: recv_data() must return None (stream ended)
|
||||
// within the timeout, NOT hang forever waiting for a FIN that never arrives.
|
||||
let result = with_timeout(async {
|
||||
let mut total = 0usize;
|
||||
while let Some(chunk) = stream.recv_data().await.expect("H3 data receive error") {
|
||||
total += chunk.remaining();
|
||||
}
|
||||
// recv_data() returned None => stream ended (FIN received)
|
||||
total
|
||||
}, 10)
|
||||
let result = with_timeout(
|
||||
async {
|
||||
let mut total = 0usize;
|
||||
while let Some(chunk) = stream.recv_data().await.expect("H3 data receive error") {
|
||||
total += chunk.remaining();
|
||||
}
|
||||
// recv_data() returned None => stream ended (FIN received)
|
||||
total
|
||||
},
|
||||
10,
|
||||
)
|
||||
.await;
|
||||
|
||||
let bytes_received = result.expect(
|
||||
"TIMEOUT: H3 stream never ended (FIN not received by client). \
|
||||
The proxy sent all response data but failed to send the QUIC stream FIN."
|
||||
The proxy sent all response data but failed to send the QUIC stream FIN.",
|
||||
);
|
||||
assert_eq!(
|
||||
bytes_received,
|
||||
|
||||
Reference in New Issue
Block a user