refactor(protocol): centralize header parsing and validation

This commit is contained in:
Stanislav N Mikhailov
2026-08-07 03:41:19 +03:00
parent b80b8e9e04
commit 94030c34ca
2 changed files with 35 additions and 19 deletions
+5 -10
View File
@@ -9,7 +9,7 @@ use tokio::{
}; };
use crate::protocol::{ use crate::protocol::{
parse_header, decode_header,
Header, Header,
HEADER_SIZE, HEADER_SIZE,
MAX_BODY_SIZE, MAX_BODY_SIZE,
@@ -88,23 +88,18 @@ impl Connection {
return Ok(None); return Ok(None);
} }
// Читаем остальную часть буфера от 1 до конца
self.stream.read_exact(&mut buffer[1..]).await?; self.stream.read_exact(&mut buffer[1..]).await?;
let (remaining, header) = //Парсим скачанный заголовок через nocloud_core::protocol parse_header
parse_header(&buffer).map_err(|error| { let header =
decode_header(&buffer).map_err(|error| {
io::Error::new( io::Error::new(
io::ErrorKind::InvalidData, io::ErrorKind::InvalidData,
format!("Ошибка разбора заголовка: {error:?}"), format!("Ошибка разбора заголовка: {error:?}"),
) )
})?; })?;
// Мы дали парсеру ровно HEADER_SIZE байт.
debug_assert!(remaining.is_empty());
header.validate().map_err(|error| {
io::Error::new(io::ErrorKind::InvalidData, error)
})?;
Ok(Some(header)) Ok(Some(header))
} }
+27 -6
View File
@@ -18,7 +18,10 @@ use nom::{
use thiserror::Error; use thiserror::Error;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum HeaderValidationError { pub enum HeaderError {
#[error("Некорректный формат заголовка")]
InvalidFormat,
#[error("Неподдерживаемая версия протокола: {0}")] #[error("Неподдерживаемая версия протокола: {0}")]
UnsupportedVersion(u8), UnsupportedVersion(u8),
@@ -38,7 +41,25 @@ pub struct Header {
body_size: u64, body_size: u64,
} }
pub fn parse_header( pub fn decode_header(
input: &[u8; HEADER_SIZE],
) -> Result<Header, HeaderError> {
// Парсим заголовок:
let (remaining, header) = parse_header(input)
.map_err(|_| HeaderError::InvalidFormat)?;
// Выходим с ошибкой, если заголовок был недочитан парсером:
if !remaining.is_empty() {
return Err(HeaderError::InvalidFormat);
}
//Валидация заголовка
header.validate()?;
Ok(header)
}
fn parse_header(
input: &[u8], input: &[u8],
) -> IResult<&[u8],Header> { ) -> IResult<&[u8],Header> {
//1. Парсим магические байты "NCLD" //1. Парсим магические байты "NCLD"
@@ -95,24 +116,24 @@ impl Header {
///Валидаторы для данных из заголовка: ///Валидаторы для данных из заголовка:
/// ///
// Валидация Header // Валидация Header
pub fn validate(&self) -> Result<(), HeaderValidationError> { pub fn validate(&self) -> Result<(), HeaderError> {
//Валидация version //Валидация version
if self.version != 1 { if self.version != 1 {
return Err( return Err(
HeaderValidationError::UnsupportedVersion(self.version) HeaderError::UnsupportedVersion(self.version)
); );
} }
// Валидация command // Валидация command
if self.command != 1 { if self.command != 1 {
return Err( return Err(
HeaderValidationError::UnsupportedCommand(self.command) HeaderError::UnsupportedCommand(self.command)
); );
} }
// Валидация flags // Валидация flags
if !(0..=7).contains(&self.flags){ if !(0..=7).contains(&self.flags){
return Err(HeaderValidationError::UnsupportedFlagSet (self.flags)); return Err(HeaderError::UnsupportedFlagSet (self.flags));
}; };
Ok(()) Ok(())