mirror of
https://github.com/YGGverse/titanite.git
synced 2026-03-31 17:15:33 +00:00
55 lines
1.6 KiB
Rust
55 lines
1.6 KiB
Rust
pub const CODE: &[u8] = b"20";
|
|
|
|
pub struct Meta {
|
|
pub mime: String,
|
|
}
|
|
|
|
impl Meta {
|
|
/// Build `Self` from UTF-8 meta bytes
|
|
/// * expected buffer includes leading status code, message, CRLF
|
|
pub fn from_bytes(buffer: &[u8]) -> Result<Self> {
|
|
use crate::tool::Header;
|
|
use regex::Regex;
|
|
use std::str::from_utf8;
|
|
let h = buffer.header_bytes()?;
|
|
if h.get(..2)
|
|
.is_none_or(|c| c[0] != CODE[0] || c[1] != CODE[1])
|
|
{
|
|
bail!("Invalid status code")
|
|
}
|
|
Ok(Self {
|
|
mime: match Regex::new(r"^([^\/]+\/[^\s;]+)")?.captures(from_utf8(&h[3..])?) {
|
|
Some(c) => match c.get(1) {
|
|
Some(m) => m.as_str().to_string(),
|
|
None => bail!("Content type required"),
|
|
},
|
|
None => bail!("Could not parse content type"),
|
|
},
|
|
})
|
|
}
|
|
|
|
/// Convert `Self` into UTF-8 bytes presentation
|
|
pub fn into_bytes(self) -> Vec<u8> {
|
|
self.to_bytes()
|
|
}
|
|
|
|
pub fn to_bytes(&self) -> Vec<u8> {
|
|
let mut bytes = Vec::with_capacity(3 + self.mime.len() + 2);
|
|
bytes.extend(CODE);
|
|
bytes.push(b' ');
|
|
bytes.extend(self.mime.as_bytes());
|
|
bytes.extend([b'\r', b'\n']);
|
|
bytes
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test() {
|
|
const BYTES: &[u8] = "20 text/gemini\r\nDATA".as_bytes();
|
|
let meta = Meta::from_bytes(BYTES).unwrap();
|
|
|
|
assert_eq!(meta.mime, "text/gemini".to_string());
|
|
assert_eq!(meta.into_bytes(), BYTES[..BYTES.len() - 4]); // skip DATA
|
|
}
|
|
|
|
use anyhow::{bail, Result};
|