@@ -82,26 +82,29 @@ impl Transport {
82 let mut content_length = None;
82 let mut content_length = None;
84 buffer.truncate(0);
84 buffer.truncate(0);
85− reader.read_line(buffer).await?;
85+ if reader.read_line(buffer).await? == 0 {
86− let header = buffer.trim();
86+ return Err(Error::StreamClosed);
88− if header.is_empty() {
89+ if buffer == "\r\n" {
90+ // look for an empty CRLF line
94+ let header = buffer.trim();
92− let mut parts = header.split(": ");
95+ let parts = header.split_once(": ");
94− match (parts.next(), parts.next(), parts.next()) {
97+ match parts {
95− (Some("Content-Length"), Some(value), None) => {
98+ Some(("Content-Length", value)) => {
96 content_length = Some(value.parse().context("invalid content length")?);
99 content_length = Some(value.parse().context("invalid content length")?);
98− (Some(_), Some(_), None) => {}
102+ None => {
99− _ => {
103+ // Workaround: Some non-conformant language servers will output logging and other garbage
100− return Err(std::io::Error::new(
104+ // into the same stream as JSON-RPC messages. This can also happen from shell scripts that spawn
101− std::io::ErrorKind::Other,
105+ // the server. Skip such lines and log a warning.
102− "Failed to parse header",
107+ // warn!("Failed to parse header: {:?}", header);
@@ -126,7 +129,9 @@ impl Transport {
126 buffer: &mut String,
129 buffer: &mut String,
127 ) -> Result<()> {
130 ) -> Result<()> {
128 buffer.truncate(0);
131 buffer.truncate(0);
129− err.read_line(buffer).await?;
132+ if err.read_line(buffer).await? == 0 {
133+ return Err(Error::StreamClosed);
130 error!("err <- {}", buffer);
135 error!("err <- {}", buffer);