fix: harden Lightpanda startup timeouts (#762)
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use super::types::BrowserVersionInfo;
|
||||
|
||||
pub async fn discover_cdp_url(port: u16) -> Result<String, String> {
|
||||
discover_cdp_url_with_request_timeout(port, Duration::from_secs(2)).await
|
||||
}
|
||||
|
||||
pub async fn discover_cdp_url_with_request_timeout(
|
||||
port: u16,
|
||||
request_timeout: Duration,
|
||||
) -> Result<String, String> {
|
||||
let url = format!("http://127.0.0.1:{}/json/version", port);
|
||||
|
||||
let body = tokio::time::timeout(request_timeout, async { reqwest_get_string(&url).await })
|
||||
.await
|
||||
.map_err(|_| format!("Timeout connecting to CDP on port {}", port))?
|
||||
.map_err(|e| format!("Failed to connect to CDP on port {}: {}", port, e))?;
|
||||
|
||||
let info: BrowserVersionInfo = serde_json::from_str(&body)
|
||||
.map_err(|e| format!("Invalid /json/version response: {}", e))?;
|
||||
|
||||
info.web_socket_debugger_url
|
||||
.ok_or_else(|| format!("No webSocketDebuggerUrl in /json/version on port {}", port))
|
||||
}
|
||||
|
||||
async fn reqwest_get_string(url: &str) -> Result<String, String> {
|
||||
let resp = reqwest::get(url).await.map_err(|e| e.to_string())?;
|
||||
resp.text().await.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
async fn spawn_json_server(body: &'static str) -> (u16, tokio::task::JoinHandle<()>) {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||
let port = listener.local_addr().unwrap().port();
|
||||
let handle = tokio::spawn(async move {
|
||||
let (mut socket, _) = listener.accept().await.unwrap();
|
||||
let mut buf = [0u8; 1024];
|
||||
let _ = socket.read(&mut buf).await;
|
||||
let response = format!(
|
||||
"HTTP/1.1 200 OK\r\nContent-Length: {}\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n{}",
|
||||
body.len(),
|
||||
body
|
||||
);
|
||||
socket.write_all(response.as_bytes()).await.unwrap();
|
||||
});
|
||||
(port, handle)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn discovers_ws_url_from_json_version() {
|
||||
let (port, server) =
|
||||
spawn_json_server(r#"{"webSocketDebuggerUrl":"ws://127.0.0.1:1234/"}"#).await;
|
||||
|
||||
let ws_url = discover_cdp_url(port).await.unwrap();
|
||||
assert_eq!(ws_url, "ws://127.0.0.1:1234/");
|
||||
server.await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalid_json_returns_parse_error() {
|
||||
let (port, server) = spawn_json_server("not-json").await;
|
||||
|
||||
let err = discover_cdp_url(port).await.unwrap_err();
|
||||
assert!(err.contains("Invalid /json/version response"));
|
||||
server.await.unwrap();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user