mirror of
https://github.com/YGGverse/ggemini.git
synced 2026-03-31 09:05:45 +00:00
implement high-level getters, add comments, improve tests
This commit is contained in:
parent
46da3a031a
commit
8ee088270f
3 changed files with 86 additions and 25 deletions
|
|
@ -24,14 +24,53 @@ impl Success {
|
|||
Err(e) => Err(Error::Default(e)),
|
||||
}
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
/// Get header bytes for `Self` type
|
||||
pub fn as_header_bytes(&self) -> &[u8] {
|
||||
match self {
|
||||
Self::Default(default) => default.header.as_bytes(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get header string for `Self` type
|
||||
pub fn as_header_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Default(default) => default.header.as_str(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get parsed MIME for `Self` type
|
||||
///
|
||||
/// * high-level method, useful to skip extra match case constructions;
|
||||
/// * at this moment, Gemini protocol has only one status code in this scope,\
|
||||
/// this method would be deprecated in future, use on your own risk!
|
||||
pub fn mime(&self) -> Result<String, Error> {
|
||||
match self {
|
||||
Self::Default(default) => default
|
||||
.header
|
||||
.mime()
|
||||
.map_err(|e| Error::Default(default::Error::Header(e))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
match Success::from_utf8("20 text/gemini; charset=utf-8; lang=en\r\n".as_bytes()).unwrap() {
|
||||
Success::Default(default) => {
|
||||
assert_eq!(default.header.mime().unwrap(), "text/gemini");
|
||||
assert_eq!(default.content, None)
|
||||
let r = "20 text/gemini; charset=utf-8; lang=en\r\n";
|
||||
let b = r.as_bytes();
|
||||
let s = Success::from_utf8(b).unwrap();
|
||||
|
||||
match s {
|
||||
Success::Default(ref d) => {
|
||||
assert_eq!(d.header.mime().unwrap(), "text/gemini");
|
||||
assert!(d.content.is_empty())
|
||||
}
|
||||
}
|
||||
assert_eq!(s.as_header_bytes(), b);
|
||||
assert_eq!(s.as_header_str(), r);
|
||||
assert_eq!(s.mime().unwrap(), "text/gemini");
|
||||
|
||||
assert!(Success::from_utf8("40 text/gemini; charset=utf-8; lang=en\r\n".as_bytes()).is_err())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue