diff --git a/kube-client/src/client/mod.rs b/kube-client/src/client/mod.rs index 3a2b97eac..d27c0f1f9 100644 --- a/kube-client/src/client/mod.rs +++ b/kube-client/src/client/mod.rs @@ -258,7 +258,9 @@ impl Client { upgrade::StreamProtocol::add_to_headers(&mut parts.headers)?; let res = self.send(Request::from_parts(parts, Body::from(body))).await?; - let protocol = upgrade::verify_response(&res, &key).map_err(Error::UpgradeConnection)?; + let (protocol, res) = upgrade::verify_response(res, &key) + .await + .map_err(Error::UpgradeConnection)?; match hyper::upgrade::on(res).await { Ok(upgraded) => Ok(Connection { stream: WebSocketStream::from_raw_socket( diff --git a/kube-client/src/client/upgrade.rs b/kube-client/src/client/upgrade.rs index 4de96c2d3..5dd84987e 100644 --- a/kube-client/src/client/upgrade.rs +++ b/kube-client/src/client/upgrade.rs @@ -90,8 +90,14 @@ pub enum UpgradeConnectionError { /// connection. /// /// [`SWITCHING_PROTOCOLS`]: http::status::StatusCode::SWITCHING_PROTOCOLS - #[error("failed to switch protocol: {0}")] - ProtocolSwitch(http::status::StatusCode), + #[error("failed to switch protocol: {status}: {body}")] + ProtocolSwitch { + /// HTTP status code returned by the API server. + status: http::status::StatusCode, + /// Response body, typically a JSON-encoded `metav1.Status` with + /// message, reason, and details explaining the failure. + body: String, + }, /// `Upgrade` header was not set to `websocket` (case insensitive) #[error("upgrade header was not set to websocket")] @@ -116,9 +122,19 @@ pub enum UpgradeConnectionError { // Verify upgrade response according to RFC6455. // Based on `tungstenite` and added subprotocol verification. -pub fn verify_response(res: &Response, key: &str) -> Result { +pub async fn verify_response( + res: Response, + key: &str, +) -> Result<(StreamProtocol, Response), UpgradeConnectionError> { if res.status() != StatusCode::SWITCHING_PROTOCOLS { - return Err(UpgradeConnectionError::ProtocolSwitch(res.status())); + let status = res.status(); + let body = res + .into_body() + .collect_bytes() + .await + .map(|b| String::from_utf8_lossy(&b).into_owned()) + .unwrap_or_default(); + return Err(UpgradeConnectionError::ProtocolSwitch { status, body }); } let headers = res.headers(); @@ -150,10 +166,10 @@ pub fn verify_response(res: &Response, key: &str) -> Result p, None => return Err(UpgradeConnectionError::SecWebSocketProtocolMismatch), }; - Ok(protocol) + Ok((protocol, res)) }