{"record":{"id":"c661b1315286ff8c","repo":"jlcodes99/cockpit-tools","slug":"ws-c661b1","errorCode":null,"errorMessage":"[WS] 握手失败 {}: {}","messagePattern":"\\[WS\\] 握手失败 (.+?): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/cockpit-core/src/modules/websocket.rs","lineNumber":526,"sourceCode":"\n    let server = get_server();\n\n    while let Ok((stream, addr)) = listener.accept().await {\n        if !is_allowed_remote_client(&addr) {\n            crate::modules::logger::log_warn(&format!(\"[WS] 鎷掔粷闈炵櫧鍚嶅崟鏉ユ簮: {}\", addr));\n            continue;\n        }\n        let server_clone = Arc::clone(server);\n        tokio::spawn(handle_connection(server_clone, stream, addr));\n    }\n}\n\n/// 处理单个客户端连接\nasync fn handle_connection(server: Arc<WsServer>, stream: TcpStream, addr: SocketAddr) {\n    let ws_stream = match tokio_tungstenite::accept_async(stream).await {\n        Ok(ws) => ws,\n        Err(e) => {\n            crate::modules::logger::log_error(&format!(\"[WS] 握手失败 {}: {}\", addr, e));\n            return;\n        }\n    };\n\n    crate::modules::logger::log_info(&format!(\"[WS] 新连接: {}\", addr));\n\n    // 添加客户端\n    {\n        let mut clients = server.clients.write().await;\n        clients.insert(addr, Client { _addr: addr });\n    }\n\n    let (mut ws_sender, mut ws_receiver) = ws_stream.split();\n\n    // 发送 Ready 消息\n    let ready_msg = WsMessage::Ready {\n        version: env!(\"CARGO_PKG_VERSION\").to_string(),\n    };","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/crates/cockpit-core/src/modules/websocket.rs#L508-L544","documentation":"Logged in handle_connection when tokio_tungstenite::accept_async(stream) fails, i.e. the TCP connection could not be upgraded to a WebSocket. The WebSocket handshake (HTTP 101 Upgrade with Sec-WebSocket-* headers) was rejected as invalid, so the connection is dropped and the handler returns. The server itself keeps running for other clients.","triggerScenarios":"A client connects to ws://127.0.0.1:<port> but sends data that is not a valid WebSocket opening handshake: a plain HTTP GET without Upgrade headers, garbage bytes (e.g. a port probe), an invalid Sec-WebSocket-Key/version, or a TLS ClientHello sent to the plaintext port.","commonSituations":"A health-check or browser fetch() hitting the WebSocket port with a normal HTTP request; security/port scanners probing 127.0.0.1; a client configured for wss:// connecting to a non-TLS listener; a malformed or third-party WS client with bad handshake headers.","solutions":["Read the addr and tungstenite error in the log to see who connected and why the handshake was rejected.","Ensure the client uses a real WebSocket client (ws://, not plain HTTP fetch or https/wss) against this plaintext listener.","Check the client's handshake headers/Sec-WebSocket-Version (must be 13) if using a custom client.","Ignore routine scanner/probe noise if the log shows non-WebSocket bytes from unknown local processes."],"exampleFix":"// before: browser fetch against the WS port causes handshake failure\nfetch(\"http://127.0.0.1:9100/\")\n// after: use a WebSocket client\nconst ws = new WebSocket(\"ws://127.0.0.1:9100\");","handlingStrategy":"validation","validationCode":"// client side: only speak WebSocket to the WS port\nconst url = new URL(endpoint);\nif (url.protocol !== \"ws:\" && url.protocol !== \"wss:\") {\n  throw new Error(`expected ws:// endpoint, got ${url.protocol}`);\n}\nconst ws = new WebSocket(url); // real handshake, not plain HTTP","typeGuard":null,"tryCatchPattern":"match tokio_tungstenite::accept_async(stream).await {\n    Ok(ws) => { /* serve connection */ }\n    Err(e) => {\n        log_error(&format!(\"[WS] 握手失败 {}: {}\", addr, e));\n        // drop the socket; do not crash the accept loop\n    }\n}","preventionTips":["Point clients at ws:// (not http://, https://, or wss://) for this plaintext listener.","Never reuse the WS port for health checks or plain HTTP endpoints.","Use standard WS client libraries that send correct Sec-WebSocket-Key/Version headers.","Expect port-scan noise on local ports; alert only on repeated handshake failures from your own client."],"tags":["websocket","handshake","tungstenite","rust"],"backgroundTag":"websocket-handshake-failed","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}