Revert "hold raw header string"

This reverts commit 5bb52fbd8c.
This commit is contained in:
yggverse 2025-03-19 15:06:53 +02:00
parent 3f968d87b1
commit 9eb21bb6a3
11 changed files with 78 additions and 278 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "ggemini" name = "ggemini"
version = "0.18.0" version = "0.17.3"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
readme = "README.md" readme = "README.md"

View file

@ -1,28 +1,19 @@
pub mod error; pub mod error;
pub use error::Error; pub use error::Error;
const REQUIRED: (u8, &str) = (60, "Certificate required"); const REQUIRED: (u8, &str) = (10, "Certificate required");
const NOT_AUTHORIZED: (u8, &str) = (61, "Certificate not authorized"); const NOT_AUTHORIZED: (u8, &str) = (11, "Certificate not authorized");
const NOT_VALID: (u8, &str) = (62, "Certificate not valid"); const NOT_VALID: (u8, &str) = (11, "Certificate not valid");
/// 6* status code group /// 6* status code group
/// https://geminiprotocol.net/docs/protocol-specification.gmi#client-certificates /// https://geminiprotocol.net/docs/protocol-specification.gmi#client-certificates
pub enum Certificate { pub enum Certificate {
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-60 /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-60
Required { Required { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-61-certificate-not-authorized /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-61-certificate-not-authorized
NotAuthorized { NotAuthorized { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-62-certificate-not-valid /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-62-certificate-not-valid
NotValid { NotValid { message: Option<String> },
header: String,
message: Option<String>,
},
} }
impl Certificate { impl Certificate {
@ -31,14 +22,7 @@ impl Certificate {
/// Create new `Self` from buffer include header bytes /// Create new `Self` from buffer include header bytes
pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> { pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> {
use std::str::FromStr; use std::str::FromStr;
let len = buffer.len(); match std::str::from_utf8(buffer) {
match std::str::from_utf8(
&buffer[..if len > super::HEADER_LEN {
super::HEADER_LEN
} else {
len
}],
) {
Ok(header) => Self::from_str(header), Ok(header) => Self::from_str(header),
Err(e) => Err(Error::Utf8Error(e)), Err(e) => Err(Error::Utf8Error(e)),
} }
@ -55,20 +39,11 @@ impl Certificate {
.0 .0
} }
pub fn header(&self) -> &str {
match self {
Self::Required { header, .. }
| Self::NotAuthorized { header, .. }
| Self::NotValid { header, .. } => header,
}
.as_str()
}
pub fn message(&self) -> Option<&str> { pub fn message(&self) -> Option<&str> {
match self { match self {
Self::Required { message, .. } Self::Required { message } => message,
| Self::NotAuthorized { message, .. } Self::NotAuthorized { message } => message,
| Self::NotValid { message, .. } => message, Self::NotValid { message } => message,
} }
.as_deref() .as_deref()
} }
@ -92,25 +67,18 @@ impl std::fmt::Display for Certificate {
impl std::str::FromStr for Certificate { impl std::str::FromStr for Certificate {
type Err = Error; type Err = Error;
fn from_str(header: &str) -> Result<Self, Self::Err> { fn from_str(header: &str) -> Result<Self, Self::Err> {
let len = header.len();
if len > super::HEADER_LEN {
return Err(Error::HeaderLen(len));
}
if let Some(postfix) = header.strip_prefix("60") { if let Some(postfix) = header.strip_prefix("60") {
return Ok(Self::Required { return Ok(Self::Required {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("61") { if let Some(postfix) = header.strip_prefix("61") {
return Ok(Self::NotAuthorized { return Ok(Self::NotAuthorized {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("62") { if let Some(postfix) = header.strip_prefix("62") {
return Ok(Self::NotValid { return Ok(Self::NotValid {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }

View file

@ -6,7 +6,6 @@ use std::{
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
Code, Code,
HeaderLen(usize),
Utf8Error(Utf8Error), Utf8Error(Utf8Error),
} }
@ -14,14 +13,7 @@ impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result { fn fmt(&self, f: &mut Formatter) -> Result {
match self { match self {
Self::Code => { Self::Code => {
write!(f, "Unexpected status code") write!(f, "Status code error")
}
Self::HeaderLen(l) => {
write!(
f,
"Header length reached protocol limit ({l} of {} bytes max)",
super::super::HEADER_LEN
)
} }
Self::Utf8Error(e) => { Self::Utf8Error(e) => {
write!(f, "UTF-8 error: {e}") write!(f, "UTF-8 error: {e}")

View file

@ -45,13 +45,6 @@ impl Failure {
} }
} }
pub fn header(&self) -> &str {
match self {
Self::Permanent(permanent) => permanent.header(),
Self::Temporary(temporary) => temporary.header(),
}
}
pub fn message(&self) -> Option<&str> { pub fn message(&self) -> Option<&str> {
match self { match self {
Self::Permanent(permanent) => permanent.message(), Self::Permanent(permanent) => permanent.message(),

View file

@ -10,30 +10,15 @@ const BAD_REQUEST: (u8, &str) = (59, "bad-request");
/// https://geminiprotocol.net/docs/protocol-specification.gmi#permanent-failure /// https://geminiprotocol.net/docs/protocol-specification.gmi#permanent-failure
pub enum Permanent { pub enum Permanent {
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-50 /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-50
Default { Default { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-51-not-found /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-51-not-found
NotFound { NotFound { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-52-gone /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-52-gone
Gone { Gone { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-53-proxy-request-refused /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-53-proxy-request-refused
ProxyRequestRefused { ProxyRequestRefused { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-59-bad-request /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-59-bad-request
BadRequest { BadRequest { message: Option<String> },
header: String,
message: Option<String>,
},
} }
impl Permanent { impl Permanent {
@ -42,14 +27,7 @@ impl Permanent {
/// Create new `Self` from buffer include header bytes /// Create new `Self` from buffer include header bytes
pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> { pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> {
use std::str::FromStr; use std::str::FromStr;
let len = buffer.len(); match std::str::from_utf8(buffer) {
match std::str::from_utf8(
&buffer[..if len > super::super::HEADER_LEN {
super::super::HEADER_LEN
} else {
len
}],
) {
Ok(header) => Self::from_str(header), Ok(header) => Self::from_str(header),
Err(e) => Err(Error::Utf8Error(e)), Err(e) => Err(Error::Utf8Error(e)),
} }
@ -68,24 +46,13 @@ impl Permanent {
.0 .0
} }
pub fn header(&self) -> &str {
match self {
Self::Default { header, .. }
| Self::NotFound { header, .. }
| Self::Gone { header, .. }
| Self::ProxyRequestRefused { header, .. }
| Self::BadRequest { header, .. } => header,
}
.as_str()
}
pub fn message(&self) -> Option<&str> { pub fn message(&self) -> Option<&str> {
match self { match self {
Self::Default { message, .. } Self::Default { message } => message,
| Self::NotFound { message, .. } Self::NotFound { message } => message,
| Self::Gone { message, .. } Self::Gone { message } => message,
| Self::ProxyRequestRefused { message, .. } Self::ProxyRequestRefused { message } => message,
| Self::BadRequest { message, .. } => message, Self::BadRequest { message } => message,
} }
.as_deref() .as_deref()
} }
@ -113,31 +80,26 @@ impl std::str::FromStr for Permanent {
fn from_str(header: &str) -> Result<Self, Self::Err> { fn from_str(header: &str) -> Result<Self, Self::Err> {
if let Some(postfix) = header.strip_prefix("50") { if let Some(postfix) = header.strip_prefix("50") {
return Ok(Self::Default { return Ok(Self::Default {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("51") { if let Some(postfix) = header.strip_prefix("51") {
return Ok(Self::NotFound { return Ok(Self::NotFound {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("52") { if let Some(postfix) = header.strip_prefix("52") {
return Ok(Self::Gone { return Ok(Self::Gone {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("53") { if let Some(postfix) = header.strip_prefix("53") {
return Ok(Self::ProxyRequestRefused { return Ok(Self::ProxyRequestRefused {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("59") { if let Some(postfix) = header.strip_prefix("59") {
return Ok(Self::BadRequest { return Ok(Self::BadRequest {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }

View file

@ -10,30 +10,15 @@ const SLOW_DOWN: (u8, &str) = (44, "Slow down");
/// https://geminiprotocol.net/docs/protocol-specification.gmi#temporary-failure /// https://geminiprotocol.net/docs/protocol-specification.gmi#temporary-failure
pub enum Temporary { pub enum Temporary {
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-40 /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-40
Default { Default { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-41-server-unavailable /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-41-server-unavailable
ServerUnavailable { ServerUnavailable { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-42-cgi-error /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-42-cgi-error
CgiError { CgiError { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-43-proxy-error /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-43-proxy-error
ProxyError { ProxyError { message: Option<String> },
header: String,
message: Option<String>,
},
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-44-slow-down /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-44-slow-down
SlowDown { SlowDown { message: Option<String> },
header: String,
message: Option<String>,
},
} }
impl Temporary { impl Temporary {
@ -42,14 +27,7 @@ impl Temporary {
/// Create new `Self` from buffer include header bytes /// Create new `Self` from buffer include header bytes
pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> { pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> {
use std::str::FromStr; use std::str::FromStr;
let len = buffer.len(); match std::str::from_utf8(buffer) {
match std::str::from_utf8(
&buffer[..if len > super::super::HEADER_LEN {
super::super::HEADER_LEN
} else {
len
}],
) {
Ok(header) => Self::from_str(header), Ok(header) => Self::from_str(header),
Err(e) => Err(Error::Utf8Error(e)), Err(e) => Err(Error::Utf8Error(e)),
} }
@ -68,24 +46,13 @@ impl Temporary {
.0 .0
} }
pub fn header(&self) -> &str {
match self {
Self::Default { header, .. }
| Self::ServerUnavailable { header, .. }
| Self::CgiError { header, .. }
| Self::ProxyError { header, .. }
| Self::SlowDown { header, .. } => header,
}
.as_str()
}
pub fn message(&self) -> Option<&str> { pub fn message(&self) -> Option<&str> {
match self { match self {
Self::Default { message, .. } Self::Default { message } => message,
| Self::ServerUnavailable { message, .. } Self::ServerUnavailable { message } => message,
| Self::CgiError { message, .. } Self::CgiError { message } => message,
| Self::ProxyError { message, .. } Self::ProxyError { message } => message,
| Self::SlowDown { message, .. } => message, Self::SlowDown { message } => message,
} }
.as_deref() .as_deref()
} }
@ -113,31 +80,26 @@ impl std::str::FromStr for Temporary {
fn from_str(header: &str) -> Result<Self, Self::Err> { fn from_str(header: &str) -> Result<Self, Self::Err> {
if let Some(postfix) = header.strip_prefix("40") { if let Some(postfix) = header.strip_prefix("40") {
return Ok(Self::Default { return Ok(Self::Default {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("41") { if let Some(postfix) = header.strip_prefix("41") {
return Ok(Self::ServerUnavailable { return Ok(Self::ServerUnavailable {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("42") { if let Some(postfix) = header.strip_prefix("42") {
return Ok(Self::CgiError { return Ok(Self::CgiError {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("43") { if let Some(postfix) = header.strip_prefix("43") {
return Ok(Self::ProxyError { return Ok(Self::ProxyError {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("44") { if let Some(postfix) = header.strip_prefix("44") {
return Ok(Self::SlowDown { return Ok(Self::SlowDown {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }

View file

@ -5,14 +5,8 @@ const DEFAULT: (u8, &str) = (10, "Input");
const SENSITIVE: (u8, &str) = (11, "Sensitive input"); const SENSITIVE: (u8, &str) = (11, "Sensitive input");
pub enum Input { pub enum Input {
Default { Default { message: Option<String> },
header: String, Sensitive { message: Option<String> },
message: Option<String>,
},
Sensitive {
header: String,
message: Option<String>,
},
} }
impl Input { impl Input {
@ -21,14 +15,7 @@ impl Input {
/// Create new `Self` from buffer include header bytes /// Create new `Self` from buffer include header bytes
pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> { pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> {
use std::str::FromStr; use std::str::FromStr;
let len = buffer.len(); match std::str::from_utf8(buffer) {
match std::str::from_utf8(
&buffer[..if len > super::HEADER_LEN {
super::HEADER_LEN
} else {
len
}],
) {
Ok(header) => Self::from_str(header), Ok(header) => Self::from_str(header),
Err(e) => Err(Error::Utf8Error(e)), Err(e) => Err(Error::Utf8Error(e)),
} }
@ -44,16 +31,10 @@ impl Input {
.0 .0
} }
pub fn header(&self) -> &str {
match self {
Self::Default { header, .. } | Self::Sensitive { header, .. } => header,
}
.as_str()
}
pub fn message(&self) -> Option<&str> { pub fn message(&self) -> Option<&str> {
match self { match self {
Self::Default { message, .. } | Self::Sensitive { message, .. } => message, Self::Default { message } => message,
Self::Sensitive { message } => message,
} }
.as_deref() .as_deref()
} }
@ -76,22 +57,17 @@ impl std::fmt::Display for Input {
impl std::str::FromStr for Input { impl std::str::FromStr for Input {
type Err = Error; type Err = Error;
fn from_str(header: &str) -> Result<Self, Self::Err> { fn from_str(header: &str) -> Result<Self, Self::Err> {
if header.len() > super::HEADER_LEN {
return Err(Error::HeaderLen(header.len()));
}
if let Some(postfix) = header.strip_prefix("10") { if let Some(postfix) = header.strip_prefix("10") {
return Ok(Self::Default { return Ok(Self::Default {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
if let Some(postfix) = header.strip_prefix("11") { if let Some(postfix) = header.strip_prefix("11") {
return Ok(Self::Sensitive { return Ok(Self::Sensitive {
header: header.to_string(),
message: message(postfix), message: message(postfix),
}); });
} }
Err(Error::Code) Err(Error::Protocol)
} }
} }

View file

@ -5,27 +5,19 @@ use std::{
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
Code, Protocol,
HeaderLen(usize),
Utf8Error(Utf8Error), Utf8Error(Utf8Error),
} }
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result { fn fmt(&self, f: &mut Formatter) -> Result {
match self { match self {
Self::Code => {
write!(f, "Unexpected status code")
}
Self::HeaderLen(l) => {
write!(
f,
"Header length reached protocol limit ({l} of {} bytes max)",
super::super::HEADER_LEN
)
}
Self::Utf8Error(e) => { Self::Utf8Error(e) => {
write!(f, "UTF-8 error: {e}") write!(f, "UTF-8 error: {e}")
} }
Self::Protocol => {
write!(f, "Protocol error")
}
} }
} }
} }

View file

@ -8,9 +8,9 @@ const PERMANENT: (u8, &str) = (31, "Permanent redirect");
pub enum Redirect { pub enum Redirect {
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-30-temporary-redirection /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-30-temporary-redirection
Temporary { header: String, target: String }, Temporary { target: String },
/// https://geminiprotocol.net/docs/protocol-specification.gmi#status-31-permanent-redirection /// https://geminiprotocol.net/docs/protocol-specification.gmi#status-31-permanent-redirection
Permanent { header: String, target: String }, Permanent { target: String },
} }
impl Redirect { impl Redirect {
@ -19,14 +19,7 @@ impl Redirect {
/// Create new `Self` from buffer include header bytes /// Create new `Self` from buffer include header bytes
pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> { pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> {
use std::str::FromStr; use std::str::FromStr;
let len = buffer.len(); match std::str::from_utf8(buffer) {
match std::str::from_utf8(
&buffer[..if len > super::HEADER_LEN {
super::HEADER_LEN
} else {
len
}],
) {
Ok(header) => Self::from_str(header), Ok(header) => Self::from_str(header),
Err(e) => Err(Error::Utf8Error(e)), Err(e) => Err(Error::Utf8Error(e)),
} }
@ -94,15 +87,10 @@ impl Redirect {
// Getters // Getters
pub fn header(&self) -> &str {
match self {
Self::Permanent { header, .. } | Self::Temporary { header, .. } => header,
}
}
pub fn target(&self) -> &str { pub fn target(&self) -> &str {
match self { match self {
Self::Permanent { target, .. } | Self::Temporary { target, .. } => target, Self::Permanent { target } => target,
Self::Temporary { target } => target,
} }
} }
} }
@ -136,11 +124,9 @@ impl std::str::FromStr for Redirect {
match regex.get(1) { match regex.get(1) {
Some(code) => match code.as_str() { Some(code) => match code.as_str() {
"0" => Ok(Self::Temporary { "0" => Ok(Self::Temporary {
header: header.to_string(),
target: target(regex.get(2))?, target: target(regex.get(2))?,
}), }),
"1" => Ok(Self::Permanent { "1" => Ok(Self::Permanent {
header: header.to_string(),
target: target(regex.get(2))?, target: target(regex.get(2))?,
}), }),
_ => todo!(), _ => todo!(),

View file

@ -4,7 +4,7 @@ pub use error::Error;
const DEFAULT: (u8, &str) = (20, "Success"); const DEFAULT: (u8, &str) = (20, "Success");
pub enum Success { pub enum Success {
Default { header: String, mime: String }, Default { mime: String },
// reserved for 2* codes // reserved for 2* codes
} }
@ -14,14 +14,7 @@ impl Success {
/// Create new `Self` from buffer include header bytes /// Create new `Self` from buffer include header bytes
pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> { pub fn from_utf8(buffer: &[u8]) -> Result<Self, Error> {
use std::str::FromStr; use std::str::FromStr;
let len = buffer.len(); match std::str::from_utf8(buffer) {
match std::str::from_utf8(
&buffer[..if len > super::HEADER_LEN {
super::HEADER_LEN
} else {
len
}],
) {
Ok(header) => Self::from_str(header), Ok(header) => Self::from_str(header),
Err(e) => Err(Error::Utf8Error(e)), Err(e) => Err(Error::Utf8Error(e)),
} }
@ -37,16 +30,9 @@ impl Success {
// Getters // Getters
pub fn header(&self) -> &str {
match self {
Self::Default { header, .. } => header,
}
.as_str()
}
pub fn mime(&self) -> &str { pub fn mime(&self) -> &str {
match self { match self {
Self::Default { mime, .. } => mime, Self::Default { mime } => mime,
} }
} }
} }
@ -68,34 +54,25 @@ impl std::str::FromStr for Success {
fn from_str(header: &str) -> Result<Self, Self::Err> { fn from_str(header: &str) -> Result<Self, Self::Err> {
use glib::{Regex, RegexCompileFlags, RegexMatchFlags}; use glib::{Regex, RegexCompileFlags, RegexMatchFlags};
if header.len() > super::HEADER_LEN { match Regex::split_simple(
return Err(Error::HeaderLen(header.len())); r"^20\s([^\/]+\/[^\s;]+)",
} header,
RegexCompileFlags::DEFAULT,
// * keep separator after code as expected by protocol RegexMatchFlags::DEFAULT,
match header.strip_prefix("20") { )
Some(postfix) => match Regex::split_simple( .get(1)
r"^\s+([^\/]+\/[^\s;]+)", {
postfix, Some(mime) => {
RegexCompileFlags::DEFAULT, let mime = mime.trim();
RegexMatchFlags::DEFAULT, if mime.is_empty() {
) Err(Error::Mime)
.get(1) } else {
{ Ok(Self::Default {
Some(mime) => { mime: mime.to_lowercase(),
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::ContentType), }
}, None => Err(Error::Protocol),
None => Err(Error::Code),
} }
} }
} }

View file

@ -5,31 +5,23 @@ use std::{
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
Code, Protocol,
ContentType, Mime,
HeaderLen(usize),
Utf8Error(Utf8Error), Utf8Error(Utf8Error),
} }
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result { fn fmt(&self, f: &mut Formatter) -> Result {
match self { 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) => { Self::Utf8Error(e) => {
write!(f, "UTF-8 error: {e}") write!(f, "UTF-8 error: {e}")
} }
Self::Protocol => {
write!(f, "Protocol error")
}
Self::Mime => {
write!(f, "MIME error")
}
} }
} }
} }