From dad7be8c77c88088fa31a8de9b8402e7a9ea0090 Mon Sep 17 00:00:00 2001 From: Li Yang <76434265+hewliyang@users.noreply.github.com> Date: Thu, 5 Mar 2026 06:32:01 +0800 Subject: [PATCH] fix: use reqwest for CDP port discovery instead of broken hand-rolled HTTP client (#619) reqwest_get_string() was hand-rolling HTTP/1.1 over raw TCP despite reqwest being an existing dependency. The hand-rolled implementation had two bugs: 1. URL path parsing: url.find('/') matched the first '/' in 'http://', producing path '//127.0.0.1:9222/json/version' instead of '/json/version' 2. read_to_end() hangs: Chrome's DevTools HTTP server ignores Connection: close and keeps the socket open, so read_to_end() waits for EOF that never comes This caused 'agent-browser --cdp ' to always timeout when AGENT_BROWSER_NATIVE=1. Fix: replace 49 lines of broken TCP code with reqwest::get(), which was already in Cargo.toml. --- cli/src/native/cdp/chrome.rs | 51 ++---------------------------------- 1 file changed, 2 insertions(+), 49 deletions(-) diff --git a/cli/src/native/cdp/chrome.rs b/cli/src/native/cdp/chrome.rs index 7a15e56..dfbee43 100644 --- a/cli/src/native/cdp/chrome.rs +++ b/cli/src/native/cdp/chrome.rs @@ -381,55 +381,8 @@ pub async fn discover_cdp_url(port: u16) -> Result { } async fn reqwest_get_string(url: &str) -> Result { - let client = tokio::net::TcpStream::connect( - url.strip_prefix("http://") - .unwrap_or(url) - .split('/') - .next() - .unwrap_or("127.0.0.1:9222"), - ) - .await - .map_err(|e| e.to_string())?; - - let path = url - .find('/') - .and_then(|i| url[i..].find('/').map(|j| &url[i + j..])) - .unwrap_or("/json/version"); - - let host = url - .strip_prefix("http://") - .unwrap_or(url) - .split('/') - .next() - .unwrap_or("127.0.0.1"); - - let request = format!( - "GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", - path, host - ); - - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - - let mut client = client; - client - .write_all(request.as_bytes()) - .await - .map_err(|e| e.to_string())?; - - let mut response = Vec::new(); - client - .read_to_end(&mut response) - .await - .map_err(|e| e.to_string())?; - - let response_str = String::from_utf8_lossy(&response); - let body = response_str - .split("\r\n\r\n") - .nth(1) - .unwrap_or("") - .to_string(); - - Ok(body) + let resp = reqwest::get(url).await.map_err(|e| e.to_string())?; + resp.text().await.map_err(|e| e.to_string()) } pub fn read_devtools_active_port(user_data_dir: &Path) -> Option<(u16, String)> {