implement high-level getters, add comments, improve tests

This commit is contained in:
yggverse 2025-03-25 07:36:48 +02:00
parent 46da3a031a
commit 8ee088270f
3 changed files with 86 additions and 25 deletions

View file

@ -11,13 +11,18 @@ pub const CODE: &[u8] = b"20";
/// * this response type MAY contain body data
/// * the header has closed members to require valid construction
pub struct Default {
/// Formatted header holder with additional API
pub header: Header,
pub content: Option<Vec<u8>>,
/// Default success response MAY include body data
/// * if the `Request` constructed with `Mode::HeaderOnly` flag,\
/// this value wants to be processed manually, using external application logic (specific for content-type)
pub content: Vec<u8>,
}
impl Default {
// Constructors
/// Parse `Self` from buffer contains header bytes
pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> {
if !buffer.starts_with(CODE) {
return Err(Error::Code);
@ -25,9 +30,9 @@ impl Default {
let header = Header::from_utf8(buffer).map_err(Error::Header)?;
Ok(Self {
content: buffer
.get(header.len() + 1..)
.get(header.as_bytes().len()..)
.filter(|s| !s.is_empty())
.map(|v| v.to_vec()),
.map_or(Vec::new(), |v| v.to_vec()),
header,
})
}
@ -35,8 +40,12 @@ impl Default {
#[test]
fn test() {
let default =
Default::from_utf8("20 text/gemini; charset=utf-8; lang=en\r\n".as_bytes()).unwrap();
assert_eq!(default.header.mime().unwrap(), "text/gemini");
assert_eq!(default.content, None)
let d = Default::from_utf8("20 text/gemini; charset=utf-8; lang=en\r\n".as_bytes()).unwrap();
assert_eq!(d.header.mime().unwrap(), "text/gemini");
assert!(d.content.is_empty());
let d =
Default::from_utf8("20 text/gemini; charset=utf-8; lang=en\r\ndata".as_bytes()).unwrap();
assert_eq!(d.header.mime().unwrap(), "text/gemini");
assert_eq!(d.content.len(), 4);
}

View file

@ -1,19 +1,22 @@
pub mod error;
pub use error::Error;
pub struct Header(Vec<u8>);
pub struct Header(String);
impl Header {
// Constructors
/// Parse `Self` from buffer contains header bytes
pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> {
if !buffer.starts_with(super::CODE) {
return Err(Error::Code);
}
Ok(Self(
crate::client::connection::response::header_bytes(buffer)
.map_err(Error::Header)?
.to_vec(),
std::str::from_utf8(
crate::client::connection::response::header_bytes(buffer).map_err(Error::Header)?,
)
.map_err(Error::Utf8Error)?
.to_string(),
))
}
@ -23,7 +26,7 @@ impl Header {
pub fn mime(&self) -> Result<String, Error> {
glib::Regex::split_simple(
r"^\d{2}\s([^\/]+\/[^\s;]+)",
std::str::from_utf8(&self.0).map_err(Error::Utf8Error)?,
&self.0,
glib::RegexCompileFlags::DEFAULT,
glib::RegexMatchFlags::DEFAULT,
)
@ -33,15 +36,25 @@ impl Header {
.map_or(Err(Error::Mime), |s| Ok(s.to_lowercase()))
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Get header bytes of `Self`
pub fn as_bytes(&self) -> &[u8] {
&self.0
self.0.as_bytes()
}
/// Get header string of `Self`
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
#[test]
fn test() {
let s = "20 text/gemini; charset=utf-8; lang=en\r\n";
let b = s.as_bytes();
let h = Header::from_utf8(b).unwrap();
assert_eq!(h.mime().unwrap(), "text/gemini");
assert_eq!(h.as_bytes(), b);
assert_eq!(h.as_str(), s);
assert!(Header::from_utf8("21 text/gemini; charset=utf-8; lang=en\r\n".as_bytes()).is_err());
}