{"record":{"id":"cc8345b57364058a","repo":"shadowsocks/shadowsocks-rust","slug":"unexpected-response-from-http-clients3-google-co","errorCode":null,"errorMessage":"unexpected response from http://clients3.google.com/generate_204, {:?}","messagePattern":"unexpected response from http://clients3\\.google\\.com/generate_204, (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks-service/src/local/loadbalancing/ping_balancer.rs","lineNumber":875,"sourceCode":"            &addr,\n            self.server.connect_opts_ref(),\n        )\n        .await?;\n        stream.write_all(GET_BODY).await?;\n\n        let mut reader = BufReader::new(stream);\n\n        let mut buf = Vec::new();\n        reader.read_until(b'\\n', &mut buf).await?;\n\n        let mut headers = [httparse::EMPTY_HEADER; 1];\n        let mut response = httparse::Response::new(&mut headers);\n\n        if response.parse(&buf).is_ok() && matches!(response.code, Some(204)) {\n            return Ok(());\n        }\n\n        Err(Error::new(\n            ErrorKind::InvalidData,\n            format!(\n                \"unexpected response from http://clients3.google.com/generate_204, {:?}\",\n                ByteStr::new(&buf)\n            ),\n        ))\n    }\n\n    /// Detect TCP connectivity with Firefox's http://detectportal.firefox.com/success.txt\n    async fn check_request_tcp_firefox(&self) -> io::Result<()> {\n        use std::io::{Error, ErrorKind};\n\n        const GET_BODY: &[u8] =\n            b\"GET /success.txt HTTP/1.1\\r\\nHost: detectportal.firefox.com\\r\\nConnection: close\\r\\nAccept: */*\\r\\n\\r\\n\";\n\n        let addr = Address::DomainNameAddress(\"detectportal.firefox.com\".to_owned(), 80);\n\n        let mut stream = ProxyClientStream::connect_with_opts(","sourceCodeStart":857,"sourceCodeEnd":893,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks-service/src/local/loadbalancing/ping_balancer.rs#L857-L893","documentation":"In shadowsocks-service's ping_balancer, check_request_tcp_chromium sends an HTTP request to http://clients3.google.com/generate_204 through a candidate proxy server and expects a 204 response proving the server works. If httparse cannot parse the reply or the status code is not 204, the server (or the path through it) is broken, so InvalidData is thrown with the raw response bytes in the message for diagnosis.","triggerScenarios":"Running check_request_tcp_chromium (via loadbalancer's check_request) when the proxy server returns garbage, an HTTP error page, a captive-portal redirect (302/200), or closes/truncates the connection instead of returning HTTP 204 from the generate_204 endpoint.","commonSituations":"Dead or censored proxy nodes, captive portals intercepting traffic, GFW-style hijacking returning reset/redirect pages, or a node that resolves generate_204 incorrectly. Commonly surfaced during network-change events or periodic server health checks.","solutions":["Check whether the proxy server actually relays traffic (test with curl through the same proxy).","Switch to another server in the balancer or update the server list; this node is failing the liveness probe.","Verify no local firewall/ISP interception is rewriting HTTP responses (test generate_204 directly).","If the target is blocked in your network, point the probe at a reachable URL by adjusting the balancer's check logic."],"exampleFix":"// before: server fails the probe silently or is removed\nlet balancer = PingBalancerBuilder::new(check_adapter, mode).build().await;\n// after: handle probe failures gracefully by scheduling re-check instead of treating as fatal\nmatch check_request(server).await {\n    Ok(()) => balancer.add_server(server, estimate),\n    Err(err) => tracing::warn!(?err, \"server failed connectivity check, rescheduling\"),\n}","handlingStrategy":"retry","validationCode":"// precheck: only feed servers into the balancer that can reach the probe\ntcping(server_addr, Duration::from_secs(3)).await.is_ok()","typeGuard":null,"tryCatchPattern":"match check_request(server).await {\n    Ok(()) => balancer.add_server(server, estimate),\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {\n        tracing::warn!(\"probe failed (unexpected response), rescheduling check: {e}\");\n        schedule_recheck(server);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Pre-tcping server latency before adding to the balancer","Exclude nodes known to be behind captive portals","Log the raw probe response from the error message to diagnose hijacks","Use multiple probe targets (chromium + firefox) for robustness"],"tags":["network","proxy","health-check","http"],"backgroundTag":"http-error-response","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}