Fix: Move WS error handling (#174)
Moves all WS handling of unexpected payloads into the stream to prevent code duplication.
This also prevents non-{Hello,Resumed,Ready} messages from causing a handshake failure, as it seems Discord do not prevent such messages from appearing.
---------
Co-authored-by: Kyle Simpson <kyleandrew.simpson@gmail.com>
This commit is contained in:
@@ -27,8 +27,6 @@ pub enum Error {
|
|||||||
CryptoModeUnavailable,
|
CryptoModeUnavailable,
|
||||||
/// An indicator that an endpoint URL was invalid.
|
/// An indicator that an endpoint URL was invalid.
|
||||||
EndpointUrl,
|
EndpointUrl,
|
||||||
/// Discord hello/ready handshake was violated.
|
|
||||||
ExpectedHandshake,
|
|
||||||
/// Discord failed to correctly respond to IP discovery.
|
/// Discord failed to correctly respond to IP discovery.
|
||||||
IllegalDiscoveryResponse,
|
IllegalDiscoveryResponse,
|
||||||
/// Could not parse Discord's view of our IP.
|
/// Could not parse Discord's view of our IP.
|
||||||
@@ -103,7 +101,6 @@ impl fmt::Display for Error {
|
|||||||
Self::CryptoModeInvalid => write!(f, "server changed negotiated encryption mode"),
|
Self::CryptoModeInvalid => write!(f, "server changed negotiated encryption mode"),
|
||||||
Self::CryptoModeUnavailable => write!(f, "server did not offer chosen encryption mode"),
|
Self::CryptoModeUnavailable => write!(f, "server did not offer chosen encryption mode"),
|
||||||
Self::EndpointUrl => write!(f, "endpoint URL received from gateway was invalid"),
|
Self::EndpointUrl => write!(f, "endpoint URL received from gateway was invalid"),
|
||||||
Self::ExpectedHandshake => write!(f, "voice initialisation protocol was violated"),
|
|
||||||
Self::IllegalDiscoveryResponse =>
|
Self::IllegalDiscoveryResponse =>
|
||||||
write!(f, "IP discovery/NAT punching response was invalid"),
|
write!(f, "IP discovery/NAT punching response was invalid"),
|
||||||
Self::IllegalIp => write!(f, "IP discovery/NAT punching response had bad IP value"),
|
Self::IllegalIp => write!(f, "IP discovery/NAT punching response had bad IP value"),
|
||||||
@@ -124,7 +121,6 @@ impl StdError for Error {
|
|||||||
| Error::CryptoModeInvalid
|
| Error::CryptoModeInvalid
|
||||||
| Error::CryptoModeUnavailable
|
| Error::CryptoModeUnavailable
|
||||||
| Error::EndpointUrl
|
| Error::EndpointUrl
|
||||||
| Error::ExpectedHandshake
|
|
||||||
| Error::IllegalDiscoveryResponse
|
| Error::IllegalDiscoveryResponse
|
||||||
| Error::IllegalIp
|
| Error::IllegalIp
|
||||||
| Error::InterconnectFailure(_)
|
| Error::InterconnectFailure(_)
|
||||||
|
|||||||
@@ -95,8 +95,6 @@ impl Connection {
|
|||||||
},
|
},
|
||||||
other => {
|
other => {
|
||||||
debug!("Expected ready/hello; got: {:?}", other);
|
debug!("Expected ready/hello; got: {:?}", other);
|
||||||
|
|
||||||
return Err(Error::ExpectedHandshake);
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -304,8 +302,6 @@ impl Connection {
|
|||||||
},
|
},
|
||||||
other => {
|
other => {
|
||||||
debug!("Expected resumed/hello; got: {:?}", other);
|
debug!("Expected resumed/hello; got: {:?}", other);
|
||||||
|
|
||||||
return Err(Error::ExpectedHandshake);
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ pub use mix_mode::MixMode;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub use test_config::*;
|
pub use test_config::*;
|
||||||
|
|
||||||
#[cfg(feature = "builtin-queue")]
|
|
||||||
use crate::tracks;
|
|
||||||
#[cfg(feature = "builtin-queue")]
|
#[cfg(feature = "builtin-queue")]
|
||||||
use crate::tracks::TrackQueue;
|
use crate::tracks::TrackQueue;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|||||||
@@ -95,10 +95,6 @@ impl AuxNetwork {
|
|||||||
}
|
}
|
||||||
ws_msg = self.ws_client.recv_json_no_timeout(), if !self.dont_send => {
|
ws_msg = self.ws_client.recv_json_no_timeout(), if !self.dont_send => {
|
||||||
ws_error = match ws_msg {
|
ws_error = match ws_msg {
|
||||||
Err(WsError::Json(e)) => {
|
|
||||||
debug!("Unexpected JSON {:?}.", e);
|
|
||||||
false
|
|
||||||
},
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
should_reconnect = ws_error_is_not_final(&e);
|
should_reconnect = ws_error_is_not_final(&e);
|
||||||
ws_reason = Some((&e).into());
|
ws_reason = Some((&e).into());
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ impl From<&ConnectionError> for DisconnectReason {
|
|||||||
| ConnectionError::CryptoModeInvalid
|
| ConnectionError::CryptoModeInvalid
|
||||||
| ConnectionError::CryptoModeUnavailable
|
| ConnectionError::CryptoModeUnavailable
|
||||||
| ConnectionError::EndpointUrl
|
| ConnectionError::EndpointUrl
|
||||||
| ConnectionError::ExpectedHandshake
|
|
||||||
| ConnectionError::IllegalDiscoveryResponse
|
| ConnectionError::IllegalDiscoveryResponse
|
||||||
| ConnectionError::IllegalIp
|
| ConnectionError::IllegalIp
|
||||||
| ConnectionError::Json(_) => Self::ProtocolViolation,
|
| ConnectionError::Json(_) => Self::ProtocolViolation,
|
||||||
|
|||||||
21
src/ws.rs
21
src/ws.rs
@@ -94,19 +94,16 @@ pub(crate) fn convert_ws_message(message: Option<Message>) -> Result<Option<Even
|
|||||||
Ok(match message {
|
Ok(match message {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// simd-json::serde::from_str may leave an &mut str in a non-UTF state on failure.
|
// simd-json::serde::from_str may leave an &mut str in a non-UTF state on failure.
|
||||||
// The below is safe as we have taken ownership of the inner `String`, and don't
|
// The below is safe as we have taken ownership of the inner `String`, and if
|
||||||
// access it as a `str`/`String` or return it if failure occurs.
|
// failure occurs we forcibly re-validate its contents before logging.
|
||||||
Some(Message::Text(mut payload)) =>
|
Some(Message::Text(mut payload)) =>
|
||||||
match unsafe { crate::json::from_str(payload.as_mut_str()) } {
|
(unsafe { crate::json::from_str(payload.as_mut_str()) })
|
||||||
Ok(event) => Some(event),
|
.map_err(|e| {
|
||||||
Err(why) => {
|
let safe_payload = String::from_utf8_lossy(payload.as_bytes());
|
||||||
debug!(
|
debug!("Unexpected JSON: {e}. Payload: {safe_payload}");
|
||||||
"Could not deserialize websocket event, payload: {}, error: {}",
|
e
|
||||||
payload, why
|
})
|
||||||
);
|
.ok(),
|
||||||
None
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Some(Message::Binary(bytes)) => {
|
Some(Message::Binary(bytes)) => {
|
||||||
return Err(Error::UnexpectedBinaryMessage(bytes));
|
return Err(Error::UnexpectedBinaryMessage(bytes));
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user