http-error: add new http-error crate
Break out proxmox-router's HttpError into it's own crate so that it can be used without pulling in proxmox-router. This commit also implements `Serialize` for `HttpError` so that it can be returned from perlmod bindings, allowing Perl code to access the status code as well as the message. Also add some smoke-tests to make sure that the `http_bail` and `http_err` macros actually produce valid code. Suggested-by: Wolfgang Bumiller <w.bumiller@proxmox.com> Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
This commit is contained in:
parent
a1cbaea766
commit
779c45eaad
@ -7,6 +7,7 @@ members = [
|
||||
"proxmox-borrow",
|
||||
"proxmox-compression",
|
||||
"proxmox-http",
|
||||
"proxmox-http-error",
|
||||
"proxmox-human-byte",
|
||||
"proxmox-io",
|
||||
"proxmox-lang",
|
||||
@ -88,6 +89,7 @@ proxmox-api-macro = { version = "1.0.4", path = "proxmox-api-macro" }
|
||||
proxmox-async = { version = "0.4.1", path = "proxmox-async" }
|
||||
proxmox-compression = { version = "0.2.0", path = "proxmox-compression" }
|
||||
proxmox-http = { version = "0.9.0", path = "proxmox-http" }
|
||||
proxmox-http-error = { version = "0.1.0", path = "proxmox-http-error" }
|
||||
proxmox-human-byte = { version = "0.1.0", path = "proxmox-human-byte" }
|
||||
proxmox-io = { version = "1.0.0", path = "proxmox-io" }
|
||||
proxmox-lang = { version = "1.1", path = "proxmox-lang" }
|
||||
|
16
proxmox-http-error/Cargo.toml
Normal file
16
proxmox-http-error/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "proxmox-http-error"
|
||||
version = "0.1.0"
|
||||
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
description = "Proxmox HTTP Error"
|
||||
|
||||
exclude.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
http.workspace = true
|
||||
serde.workspace = true
|
81
proxmox-http-error/src/lib.rs
Normal file
81
proxmox-http-error/src/lib.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use serde::{ser::SerializeStruct, Serialize, Serializer};
|
||||
use std::fmt;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use http::StatusCode;
|
||||
|
||||
/// HTTP error including `StatusCode` and message.
|
||||
#[derive(Debug)]
|
||||
pub struct HttpError {
|
||||
pub code: StatusCode,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl std::error::Error for HttpError {}
|
||||
|
||||
impl HttpError {
|
||||
pub fn new(code: StatusCode, message: String) -> Self {
|
||||
HttpError { code, message }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HttpError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for HttpError {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct("HttpError", 2)?;
|
||||
state.serialize_field("code", &self.code.as_u16())?;
|
||||
state.serialize_field("message", &self.message)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro to create a HttpError inside a anyhow::Error
|
||||
#[macro_export]
|
||||
macro_rules! http_err {
|
||||
($status:ident, $($fmt:tt)+) => {{
|
||||
::anyhow::Error::from($crate::HttpError::new(
|
||||
$crate::StatusCode::$status,
|
||||
format!($($fmt)+)
|
||||
))
|
||||
}};
|
||||
}
|
||||
|
||||
/// Bail with an error generated with the `http_err!` macro.
|
||||
#[macro_export]
|
||||
macro_rules! http_bail {
|
||||
($status:ident, $($fmt:tt)+) => {{
|
||||
return Err($crate::http_err!($status, $($fmt)+));
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_http_err() {
|
||||
// Make sure the macro generates valid code.
|
||||
http_err!(IM_A_TEAPOT, "Cannot brew coffee");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_http_bail() {
|
||||
fn t() -> Result<(), anyhow::Error> {
|
||||
// Make sure the macro generates valid code.
|
||||
http_bail!(
|
||||
UNAVAILABLE_FOR_LEGAL_REASONS,
|
||||
"Nothing to see here, move along"
|
||||
);
|
||||
}
|
||||
|
||||
assert!(t().is_err());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user