rama_http/layer/classify/
status_in_range_is_error.rsuse super::{ClassifiedResponse, ClassifyResponse, NeverClassifyEos, SharedClassifier};
use rama_http_types::StatusCode;
use std::{fmt, ops::RangeInclusive};
#[derive(Debug, Clone)]
pub struct StatusInRangeAsFailures {
range: RangeInclusive<u16>,
}
impl StatusInRangeAsFailures {
pub fn new(range: RangeInclusive<u16>) -> Self {
assert!(
StatusCode::from_u16(*range.start()).is_ok(),
"range start isn't a valid status code"
);
assert!(
StatusCode::from_u16(*range.end()).is_ok(),
"range end isn't a valid status code"
);
Self { range }
}
pub fn new_for_client_and_server_errors() -> Self {
Self::new(400..=599)
}
pub fn into_make_classifier(self) -> SharedClassifier<Self> {
SharedClassifier::new(self)
}
}
impl ClassifyResponse for StatusInRangeAsFailures {
type FailureClass = StatusInRangeFailureClass;
type ClassifyEos = NeverClassifyEos<Self::FailureClass>;
fn classify_response<B>(
self,
res: &http::Response<B>,
) -> ClassifiedResponse<Self::FailureClass, Self::ClassifyEos> {
if self.range.contains(&res.status().as_u16()) {
let class = StatusInRangeFailureClass::StatusCode(res.status());
ClassifiedResponse::Ready(Err(class))
} else {
ClassifiedResponse::Ready(Ok(()))
}
}
fn classify_error<E>(self, error: &E) -> Self::FailureClass
where
E: std::fmt::Display,
{
StatusInRangeFailureClass::Error(error.to_string())
}
}
#[derive(Debug)]
pub enum StatusInRangeFailureClass {
StatusCode(StatusCode),
Error(String),
}
impl fmt::Display for StatusInRangeFailureClass {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::StatusCode(code) => write!(f, "Status code: {}", code),
Self::Error(error) => write!(f, "Error: {}", error),
}
}
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use super::*;
use rama_http_types::Response;
#[test]
fn basic() {
let classifier = StatusInRangeAsFailures::new(400..=599);
assert!(matches!(
dbg!(classifier
.clone()
.classify_response(&response_with_status(200))),
ClassifiedResponse::Ready(Ok(())),
));
assert!(matches!(
dbg!(classifier
.clone()
.classify_response(&response_with_status(400))),
ClassifiedResponse::Ready(Err(StatusInRangeFailureClass::StatusCode(
StatusCode::BAD_REQUEST
))),
));
assert!(matches!(
dbg!(classifier.classify_response(&response_with_status(500))),
ClassifiedResponse::Ready(Err(StatusInRangeFailureClass::StatusCode(
StatusCode::INTERNAL_SERVER_ERROR
))),
));
}
fn response_with_status(status: u16) -> Response<()> {
Response::builder().status(status).body(()).unwrap()
}
}