(
reader: &mut BufReader<tokio::process::ChildStdout>,
deadline: tokio::time::Instant,
timeouts: LspRefreshTimeouts,
)
| 425 | } |
| 426 | |
| 427 | async fn read_message_until( |
| 428 | reader: &mut BufReader<tokio::process::ChildStdout>, |
| 429 | deadline: tokio::time::Instant, |
| 430 | timeouts: LspRefreshTimeouts, |
| 431 | ) -> Result<Option<JsonRpcMessage>> { |
| 432 | let mut header = Vec::new(); |
| 433 | while !header.ends_with(b"\r\n\r\n") && !header.ends_with(b"\n\n") { |
| 434 | let Some(byte) = read_byte_until(reader, deadline, !header.is_empty(), timeouts).await? |
| 435 | else { |
| 436 | return Ok(None); |
| 437 | }; |
| 438 | header.push(byte); |
| 439 | if header.len() > 16 * 1024 { |
| 440 | return Err(TraceDecayError::Config { |
| 441 | message: "LSP message header exceeded 16 KiB".to_string(), |
| 442 | }); |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | let header = String::from_utf8_lossy(&header); |
| 447 | let content_length = header.lines().find_map(|line| { |
| 448 | let (name, value) = line.split_once(':')?; |
| 449 | name.eq_ignore_ascii_case("content-length") |
| 450 | .then(|| value.trim().parse::<usize>().ok()) |
| 451 | .flatten() |
| 452 | }); |
| 453 | let Some(length) = content_length else { |
| 454 | return Err(TraceDecayError::Config { |
| 455 | message: "LSP message missing Content-Length header".to_string(), |
| 456 | }); |
| 457 | }; |
| 458 | |
| 459 | let mut body = vec![0_u8; length]; |
| 460 | let mut read = 0; |
| 461 | while read < length { |
| 462 | let now = tokio::time::Instant::now(); |
| 463 | if now >= deadline { |
| 464 | return Err(refresh_timed_out(timeouts)); |
| 465 | } |
| 466 | let remaining = deadline.saturating_duration_since(now); |
| 467 | let bytes_read = match tokio::time::timeout(remaining, reader.read(&mut body[read..])).await |
| 468 | { |
| 469 | Ok(Ok(bytes_read)) => bytes_read, |
| 470 | Ok(Err(err)) => { |
| 471 | return Err(TraceDecayError::Config { |
| 472 | message: format!("failed to read LSP body: {err}"), |
| 473 | }); |
| 474 | } |
| 475 | Err(_) => return Err(refresh_timed_out(timeouts)), |
| 476 | }; |
| 477 | if bytes_read == 0 { |
| 478 | return Err(TraceDecayError::Config { |
| 479 | message: "LSP server closed before completing message body".to_string(), |
| 480 | }); |
| 481 | } |
| 482 | read += bytes_read; |
| 483 | } |
| 484 |
no test coverage detected