1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 22:42:48 +03:00

codec: improve error messaging when remote is misconfigured

Work a bit harder to surface that the remote might be outputting
stuff to stdout.

closes: https://github.com/wez/wezterm/issues/5380
This commit is contained in:
Wez Furlong 2024-05-10 06:22:12 -07:00
parent 107dd67bf2
commit e19def7c9a
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
2 changed files with 31 additions and 18 deletions

View File

@ -37,8 +37,8 @@ use wezterm_term::color::ColorPalette;
use wezterm_term::{Alert, ClipboardSelection, StableRowIndex, TerminalSize}; use wezterm_term::{Alert, ClipboardSelection, StableRowIndex, TerminalSize};
#[derive(Error, Debug)] #[derive(Error, Debug)]
#[error("Corrupt Response")] #[error("Corrupt Response: {0}")]
pub struct CorruptResponse; pub struct CorruptResponse(String);
/// Returns the encoded length of the leb128 representation of value /// Returns the encoded length of the leb128 representation of value
fn encoded_length(value: u64) -> usize { fn encoded_length(value: u64) -> usize {
@ -173,30 +173,39 @@ async fn decode_raw_async<R: Unpin + AsyncRead + std::fmt::Debug>(
r: &mut R, r: &mut R,
max_serial: Option<u64>, max_serial: Option<u64>,
) -> anyhow::Result<Decoded> { ) -> anyhow::Result<Decoded> {
let len = read_u64_async(r).await.context("reading PDU length")?; let len = read_u64_async(r)
.await
.context("decode_raw_async failed to read PDU length")?;
let (len, is_compressed) = if (len & COMPRESSED_MASK) != 0 { let (len, is_compressed) = if (len & COMPRESSED_MASK) != 0 {
(len & !COMPRESSED_MASK, true) (len & !COMPRESSED_MASK, true)
} else { } else {
(len, false) (len, false)
}; };
let serial = read_u64_async(r).await.context("reading PDU serial")?; let serial = read_u64_async(r)
.await
.context("decode_raw_async failed to read PDU serial")?;
if let Some(max_serial) = max_serial { if let Some(max_serial) = max_serial {
if serial > max_serial && max_serial > 0 { if serial > max_serial && max_serial > 0 {
return Err(CorruptResponse).context("decode_raw"); return Err(CorruptResponse(format!(
"decode_raw_async: serial {serial} is implausibly large \
(bigger than {max_serial})"
))
.into());
} }
} }
let ident = read_u64_async(r).await.context("reading PDU ident")?; let ident = read_u64_async(r)
.await
.context("decode_raw_async failed to read PDU ident")?;
let data_len = let data_len =
match (len as usize).overflowing_sub(encoded_length(ident) + encoded_length(serial)) { match (len as usize).overflowing_sub(encoded_length(ident) + encoded_length(serial)) {
(_, true) => { (_, true) => {
anyhow::bail!( return Err(CorruptResponse(format!(
"sizes don't make sense: len:{} serial:{} (enc={}) ident:{} (enc={})", "decode_raw_async: sizes don't make sense: \
len, len:{len} serial:{serial} (enc={}) ident:{ident} (enc={})",
serial,
encoded_length(serial), encoded_length(serial),
ident,
encoded_length(ident) encoded_length(ident)
); ))
.into());
} }
(data_len, false) => data_len, (data_len, false) => data_len,
}; };
@ -210,7 +219,8 @@ async fn decode_raw_async<R: Unpin + AsyncRead + std::fmt::Debug>(
let mut data = vec![0u8; data_len]; let mut data = vec![0u8; data_len];
r.read_exact(&mut data).await.with_context(|| { r.read_exact(&mut data).await.with_context(|| {
format!( format!(
"reading {} bytes of data for PDU of length {} with serial={} ident={}", "decode_raw_async failed to read {} bytes of data \
for PDU of length {} with serial={} ident={}",
data_len, len, serial, ident data_len, len, serial, ident
) )
})?; })?;

View File

@ -1167,21 +1167,24 @@ impl Client {
} else if err.root_cause().is::<CorruptResponse>() { } else if err.root_cause().is::<CorruptResponse>() {
"Received an implausible and likely corrupt response from \ "Received an implausible and likely corrupt response from \
the server. This can happen if the remote host outputs \ the server. This can happen if the remote host outputs \
to stdout prior to running commands." to stdout prior to running commands. \
Check your shell startup!"
.to_string() .to_string()
} else if err.root_cause().is::<ChannelSendError>() { } else if err.root_cause().is::<ChannelSendError>() {
"Internal channel was closed prior to sending request. \ "Internal channel was closed prior to sending request. \
This may indicate that the remote host output invalid data \ This may indicate that the remote host output invalid data \
to stdout prior to running the requested command" to stdout prior to running the requested command. \
Check your shell startup!"
.to_string() .to_string()
} else { } else {
format!( format!(
"Please install the same version of wezterm on both \ "Please install the same version of wezterm on both \
the client and server! \ the client and server! \
The server reported error '{}' while being asked for its \ The server reported error '{err}' while being asked for its \
version. This likely means that the server is older \ version. This likely means that the server is older \
than the client.\n", than the client, but it could also happen if the remote \
err host outputs to stdout prior to running commands. \
Check your shell startup!",
) )
}; };
ui.output_str(&msg); ui.output_str(&msg);