From 6dbf49cea3d4fe5d1caf73cf9c55e3941941c706 Mon Sep 17 00:00:00 2001 From: yggverse Date: Wed, 19 Mar 2025 03:13:37 +0200 Subject: [PATCH] validate header len --- src/client/connection/response/success.rs | 47 +++++++++++-------- .../connection/response/success/error.rs | 24 ++++++---- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/client/connection/response/success.rs b/src/client/connection/response/success.rs index f862fd9..fa4c236 100644 --- a/src/client/connection/response/success.rs +++ b/src/client/connection/response/success.rs @@ -60,26 +60,35 @@ impl std::str::FromStr for Success { type Err = Error; fn from_str(header: &str) -> Result { use glib::{Regex, RegexCompileFlags, RegexMatchFlags}; - match Regex::split_simple( - r"^20\s([^\/]+\/[^\s;]+)", - header, - RegexCompileFlags::DEFAULT, - RegexMatchFlags::DEFAULT, - ) - .get(1) - { - Some(mime) => { - let mime = mime.trim(); - if mime.is_empty() { - Err(Error::Mime) - } else { - Ok(Self::Default { - header: header.to_string(), - mime: mime.to_lowercase(), - }) + + if header.len() > super::HEADER_LEN { + return Err(Error::HeaderLen(header.len())); + } + + // * keep separator after code as expected by protocol + match header.strip_prefix("20") { + Some(postfix) => match Regex::split_simple( + r"^\s+([^\/]+\/[^\s;]+)", + postfix, + RegexCompileFlags::DEFAULT, + RegexMatchFlags::DEFAULT, + ) + .get(1) + { + Some(mime) => { + let mime = mime.trim(); + if mime.is_empty() { + Err(Error::ContentType) + } else { + Ok(Self::Default { + header: header.to_string(), + mime: mime.to_lowercase(), + }) + } } - } - None => Err(Error::Protocol), + None => Err(Error::ContentType), + }, + None => Err(Error::Code), } } } diff --git a/src/client/connection/response/success/error.rs b/src/client/connection/response/success/error.rs index 2dbe363..7eaf2e0 100644 --- a/src/client/connection/response/success/error.rs +++ b/src/client/connection/response/success/error.rs @@ -5,23 +5,31 @@ use std::{ #[derive(Debug)] pub enum Error { - Protocol, - Mime, + Code, + ContentType, + HeaderLen(usize), Utf8Error(Utf8Error), } impl Display for Error { fn fmt(&self, f: &mut Formatter) -> Result { match self { + Self::Code => { + write!(f, "Unexpected status code") + } + Self::ContentType => { + write!(f, "Content type required") + } + Self::HeaderLen(l) => { + write!( + f, + "Header length reached protocol limit ({l} of {} bytes max)", + super::super::HEADER_LEN + ) + } Self::Utf8Error(e) => { write!(f, "UTF-8 error: {e}") } - Self::Protocol => { - write!(f, "Protocol error") - } - Self::Mime => { - write!(f, "MIME error") - } } } }