mirror of
https://github.com/telemt/telemt.git
synced 2026-09-23 02:58:23 +03:00
WEB: Lifecycle + Lane ownership + Diag fixes
Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,50 @@
|
||||
use super::*;
|
||||
|
||||
async fn open_keepalive(
|
||||
listener: &TcpListener,
|
||||
runtime: &Arc<WebProcessRuntime>,
|
||||
) -> (TcpStream, CancellationToken, tokio::task::JoinHandle<()>) {
|
||||
let addr = listener.local_addr().unwrap();
|
||||
let (accepted, client) = tokio::join!(listener.accept(), TcpStream::connect(addr));
|
||||
let (server, peer) = accepted.unwrap();
|
||||
let cancellation = CancellationToken::new();
|
||||
let permit = runtime.try_http_connection().unwrap();
|
||||
let task = tokio::spawn(serve_connection(
|
||||
server,
|
||||
peer,
|
||||
WebClientIpSource::XForwardedFor,
|
||||
Arc::from(["127.0.0.1/32".parse().unwrap()]),
|
||||
Arc::clone(runtime),
|
||||
cancellation.clone(),
|
||||
permit,
|
||||
));
|
||||
(client.unwrap(), cancellation, task)
|
||||
}
|
||||
|
||||
async fn read_http_response(client: &mut TcpStream) -> Vec<u8> {
|
||||
let mut response = Vec::new();
|
||||
while !response.ends_with(b"\r\n\r\n") {
|
||||
assert!(response.len() < 16 * 1024);
|
||||
response.push(client.read_u8().await.unwrap());
|
||||
}
|
||||
let content_length = std::str::from_utf8(&response)
|
||||
.unwrap()
|
||||
.lines()
|
||||
.filter_map(|line| line.split_once(':'))
|
||||
.find_map(|(name, value)| {
|
||||
name.eq_ignore_ascii_case("content-length")
|
||||
.then(|| value.trim().parse::<usize>().unwrap())
|
||||
})
|
||||
.unwrap_or(0);
|
||||
let body_start = response.len();
|
||||
response.resize(body_start + content_length, 0);
|
||||
client
|
||||
.read_exact(&mut response[body_start..])
|
||||
.await
|
||||
.unwrap();
|
||||
response
|
||||
}
|
||||
|
||||
async fn request_with_body_delay(
|
||||
listener: &TcpListener,
|
||||
runtime: &Arc<WebProcessRuntime>,
|
||||
@@ -35,6 +80,9 @@ async fn live_session_body_and_closed_token_timeouts_survive_reload() {
|
||||
let capability = [21u8; 32];
|
||||
let mut initial_config = runtime_config(capability, WebCarrier::Https);
|
||||
initial_config.web.timeouts.body_secs = 3;
|
||||
initial_config.web.timeouts.header_secs = 1;
|
||||
initial_config.web.timeouts.http_idle_secs = 4;
|
||||
initial_config.web.timeouts.long_poll_secs = 3;
|
||||
initial_config.web.timeouts.bootstrap_lifetime_secs = 5;
|
||||
let generation = test_runtime_generation(1, initial_config);
|
||||
let active_runtime = Arc::new(ArcSwap::from(Arc::clone(&generation)));
|
||||
@@ -68,6 +116,9 @@ async fn live_session_body_and_closed_token_timeouts_survive_reload() {
|
||||
|
||||
let mut replacement_config = runtime_config(capability, WebCarrier::Https);
|
||||
replacement_config.web.timeouts.body_secs = 1;
|
||||
replacement_config.web.timeouts.header_secs = 1;
|
||||
replacement_config.web.timeouts.http_idle_secs = 2;
|
||||
replacement_config.web.timeouts.long_poll_secs = 1;
|
||||
replacement_config.web.timeouts.bootstrap_lifetime_secs = 1;
|
||||
let replacement = test_runtime_generation(2, replacement_config);
|
||||
active_runtime.store(Arc::clone(&replacement));
|
||||
@@ -84,6 +135,13 @@ async fn live_session_body_and_closed_token_timeouts_survive_reload() {
|
||||
assert!(retry_headers.starts_with(b"HTTP/1.1 200"));
|
||||
assert_eq!(response_header(retry_headers, "x-session-token"), session);
|
||||
|
||||
let down = format!(
|
||||
"POST /api/v1/down HTTP/1.1\r\nHost: proxy.example.com\r\nX-Forwarded-For: 192.0.2.10\r\nAuthorization: Bearer {session}\r\nX-Down-Cursor: 0\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
|
||||
)
|
||||
.into_bytes();
|
||||
let down_response = request(&listener, &runtime, down).await;
|
||||
assert!(down_response.starts_with(b"HTTP/1.1 204"));
|
||||
|
||||
let close = format!(
|
||||
"DELETE /api/v1/session HTTP/1.1\r\nHost: proxy.example.com\r\nX-Forwarded-For: 192.0.2.10\r\nAuthorization: Bearer {session}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
|
||||
)
|
||||
@@ -100,3 +158,83 @@ async fn live_session_body_and_closed_token_timeouts_survive_reload() {
|
||||
replacement.stop_sessions().await;
|
||||
replacement.stop_background_tasks().await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn active_body_deadline_survives_reload_on_old_keepalive_connection() {
|
||||
let capability = [22u8; 32];
|
||||
let mut initial_config = runtime_config(capability, WebCarrier::Https);
|
||||
initial_config.web.timeouts.header_secs = 1;
|
||||
initial_config.web.timeouts.body_secs = 1;
|
||||
initial_config.web.timeouts.long_poll_secs = 1;
|
||||
initial_config.web.timeouts.http_idle_secs = 2;
|
||||
let generation = test_runtime_generation(1, initial_config);
|
||||
let active_runtime = Arc::new(ArcSwap::from(Arc::clone(&generation)));
|
||||
let runtime = WebProcessRuntime::start(Arc::clone(&active_runtime));
|
||||
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||
let (mut client, cancellation, task) = open_keepalive(&listener, &runtime).await;
|
||||
client
|
||||
.write_all(
|
||||
b"GET / HTTP/1.1\r\nHost: proxy.example.com\r\nX-Forwarded-For: 192.0.2.10\r\n\r\n",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(
|
||||
read_http_response(&mut client)
|
||||
.await
|
||||
.starts_with(b"HTTP/1.1 200")
|
||||
);
|
||||
|
||||
let mut replacement_config = runtime_config(capability, WebCarrier::Https);
|
||||
replacement_config.web.timeouts.header_secs = 1;
|
||||
replacement_config.web.timeouts.body_secs = 3;
|
||||
replacement_config.web.timeouts.long_poll_secs = 1;
|
||||
replacement_config.web.timeouts.http_idle_secs = 4;
|
||||
let replacement = test_runtime_generation(2, replacement_config);
|
||||
active_runtime.store(Arc::clone(&replacement));
|
||||
let encoded = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(capability);
|
||||
client
|
||||
.write_all(
|
||||
format!(
|
||||
"GET /?bridge={encoded} HTTP/1.1\r\nHost: proxy.example.com\r\nX-Forwarded-For: 192.0.2.10\r\n\r\n"
|
||||
)
|
||||
.as_bytes(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let bridge = read_http_response(&mut client).await;
|
||||
let (_, bridge_body) = split_response(&bridge);
|
||||
let bootstrap = std::str::from_utf8(bridge_body)
|
||||
.unwrap()
|
||||
.split_once("bootstrap=\"")
|
||||
.and_then(|(_, suffix)| suffix.split_once('"'))
|
||||
.map(|(token, _)| token.to_string())
|
||||
.unwrap();
|
||||
let hello = frame::encode(FrameType::Hello, 0, &[1]);
|
||||
client
|
||||
.write_all(
|
||||
format!(
|
||||
"POST /api/v1/session HTTP/1.1\r\nHost: proxy.example.com\r\nX-Forwarded-For: 192.0.2.10\r\nAuthorization: Bearer {bootstrap}\r\nContent-Type: application/octet-stream\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
|
||||
hello.len()
|
||||
)
|
||||
.as_bytes(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
tokio::time::sleep(std::time::Duration::from_millis(2200)).await;
|
||||
client.write_all(&hello).await.unwrap();
|
||||
|
||||
assert!(
|
||||
read_http_response(&mut client)
|
||||
.await
|
||||
.starts_with(b"HTTP/1.1 200")
|
||||
);
|
||||
|
||||
cancellation.cancel();
|
||||
drop(client);
|
||||
task.await.unwrap();
|
||||
runtime.shutdown().await;
|
||||
generation.stop_sessions().await;
|
||||
generation.stop_background_tasks().await;
|
||||
replacement.stop_sessions().await;
|
||||
replacement.stop_background_tasks().await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user