important fix for buffered stream + code cleanup

a `TlsStream<TcpStream>` was being wrapped in a `BufReader` during header parsing,
but then the pure stream (without BufReader) was being passed into a Response constructor,
discarding all content in an internal BufReader's buffer,
resulting in an incomplete body (truncated at the beginning)
or empty at all
This commit is contained in:
DarkCat09 2024-08-06 18:33:11 +04:00
parent 4f52475f2c
commit 39c31d9651
Signed by: DarkCat09
GPG key ID: 0A26CD5B3345D6E3
2 changed files with 34 additions and 29 deletions

View file

@ -85,39 +85,44 @@ impl Client {
stream.write_all(url_str.as_bytes()).await?; stream.write_all(url_str.as_bytes()).await?;
stream.write_all(b"\r\n").await?; stream.write_all(b"\r\n").await?;
let mut buf: [u8; 3] = [0, 0, 0]; // 2 digits, space let status = {
stream.read_exact(&mut buf).await?; let mut buf: [u8; 3] = [0, 0, 0]; // 2 digits, space
let status = Status::parse_status(&buf)?; stream.read_exact(&mut buf).await?;
Status::parse_status(&buf)?
};
let mut message: Vec<u8> = Vec::new(); let mut stream = tokio::io::BufReader::new(stream);
let mut buf_reader = tokio::io::BufReader::new(&mut stream);
let mut buf: [u8; 1] = [0]; // buffer for LF (\n)
// reading message after status code let message = {
// until CRLF (\r\n) let mut result: Vec<u8> = Vec::new();
loop { let mut buf = [0u8]; // buffer for LF (\n)
// until CR
buf_reader.read_until(b'\r', &mut message).await?; // reading message after status code
// now read next char... // until CRLF (\r\n)
buf_reader.read_exact(&mut buf).await?; loop {
if buf[0] == b'\n' { // until CR
// ...and check if it's LF stream.read_until(b'\r', &mut result).await?;
break; // now read next char...
} else { stream.read_exact(&mut buf).await?;
// ...otherwise, CR is a part of message, not a CRLF terminator, if buf[0] == b'\n' {
// so append that one byte that's supposed to be LF (but not LF) // ...and check if it's LF
// to the message buffer break;
message.push(buf[0].into()); } else {
// ...otherwise, CR is a part of message, not a CRLF terminator,
// so append that one byte that's supposed to be LF (but not LF)
// to the message buffer
result.push(buf[0].into());
}
} }
}
// trim last CR // trim last CR
if message.last().is_some_and(|c| c == &b'\r') { if result.last().is_some_and(|c| c == &b'\r') {
message.pop(); result.pop();
} }
// Vec<u8> -> ASCII or UTF-8 String // Vec<u8> -> ASCII or UTF-8 String
let message = String::from_utf8(message)?; String::from_utf8(result)?
};
Ok(Response::new(status, message, stream)) Ok(Response::new(status, message, stream))
} }

View file

@ -3,7 +3,7 @@ use crate::{status::Status, LibError, ReplyType};
use bytes::Bytes; use bytes::Bytes;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
type BodyStream = tokio_rustls::client::TlsStream<tokio::net::TcpStream>; type BodyStream = tokio::io::BufReader<tokio_rustls::client::TlsStream<tokio::net::TcpStream>>;
#[derive(Debug)] #[derive(Debug)]
pub struct Response { pub struct Response {