fix gemini request parser, implement tests

This commit is contained in:
yggverse 2025-02-22 04:44:01 +02:00
parent fa11659af0
commit d0fdbf6ac4
2 changed files with 27 additions and 17 deletions

View file

@ -6,6 +6,7 @@ pub use titan::Titan;
use anyhow::{bail, Result};
/// https://geminiprotocol.net/docs/protocol-specification.gmi#requests
pub enum Request<'a> {
Gemini(Gemini),
Titan(Titan<'a>),
@ -22,7 +23,6 @@ impl<'a> Request<'a> {
None => bail!("Empty request"),
}
}
pub fn into_bytes(self) -> Vec<u8> {
match self {
Self::Gemini(this) => this.into_bytes(),

View file

@ -7,24 +7,34 @@ pub struct Gemini {
impl Gemini {
pub fn from_bytes(buffer: &[u8]) -> Result<Self> {
let mut l: usize = 0;
for b in buffer {
l += 1;
if l > 1024 {
bail!("Max header length reached!")
}
if *b == b'\r' {
continue;
}
if *b == b'\n' {
break;
}
if buffer.len() > 1024 {
bail!("Header bytes length reached")
}
match buffer.iter().position(|&b| b == b'\r') {
Some(n) => {
if buffer.get(n + 1).is_some_and(|&b| b == b'\n') {
Ok(Self {
url: String::from_utf8(buffer[..l].to_vec())?,
url: String::from_utf8(buffer[..n].to_vec())?,
})
} else {
bail!("LF byte not found")
}
}
None => bail!("CR byte not found"),
}
}
pub fn into_bytes(self) -> Vec<u8> {
self.url.to_string().into_bytes()
let mut bytes = Vec::with_capacity(self.url.len() + 2);
bytes.extend(self.url.into_bytes());
bytes.extend(b"\r\n");
bytes
}
}
#[test]
fn test() {
const REQUEST: &[u8] = "gemini://geminiprotocol.net\r\n".as_bytes();
let request = Gemini::from_bytes(REQUEST).unwrap();
assert_eq!(request.url, "gemini://geminiprotocol.net");
assert_eq!(request.into_bytes(), REQUEST);
}