use {super::*, axum::extract::FromRef};
#[derive(Default, Debug)]
pub(crate) struct AcceptEncoding(pub(crate) Option<String>);
impl<S> axum::extract::FromRequestParts<S> for AcceptEncoding
where
Arc<ServerConfig>: FromRef<S>,
S: Send + Sync,
{
type Rejection = (StatusCode, &'static str);
async fn from_request_parts(
parts: &mut http::request::Parts,
_state: &S,
) -> Result<Self, Self::Rejection> {
Ok(Self(
parts
.headers
.get("accept-encoding")
.map(|value| value.to_str().unwrap_or_default().to_owned()),
))
}
}
impl AcceptEncoding {
pub(crate) fn is_acceptable(&self, encoding: &HeaderValue) -> bool {
let Ok(encoding) = encoding.to_str() else {
return false;
};
self
.0
.clone()
.unwrap_or_default()
.split(',')
.any(|value| value.split(';').next().unwrap_or_default().trim() == encoding)
}
}
#[cfg(test)]
mod tests {
use {
super::*,
axum::{extract::FromRequestParts, http::Request},
http::header::ACCEPT_ENCODING,
};
#[tokio::test]
async fn single_encoding() {
let req = Request::builder()
.header(ACCEPT_ENCODING, "gzip")
.body(())
.unwrap();
let encodings = AcceptEncoding::from_request_parts(
&mut req.into_parts().0,
&Arc::new(ServerConfig {
json_api_enabled: false,
decompress: false,
..default()
}),
)
.await
.unwrap();
assert_eq!(encodings.0, Some("gzip".to_string()));
}
#[tokio::test]
async fn accepts_encoding_with_qvalues() {
let req = Request::builder()
.header(ACCEPT_ENCODING, "deflate;q=0.5, gzip;q=1.0, br;q=0.8")
.body(())
.unwrap();
let encodings = AcceptEncoding::from_request_parts(
&mut req.into_parts().0,
&Arc::new(ServerConfig {
json_api_enabled: false,
decompress: false,
..default()
}),
)
.await
.unwrap();
assert_eq!(
encodings.0,
Some("deflate;q=0.5, gzip;q=1.0, br;q=0.8".to_string())
);
assert!(encodings.is_acceptable(&HeaderValue::from_static("deflate")));
assert!(encodings.is_acceptable(&HeaderValue::from_static("gzip")));
assert!(encodings.is_acceptable(&HeaderValue::from_static(BROTLI)));
assert!(!encodings.is_acceptable(&HeaderValue::from_static("bzip2")));
}
#[tokio::test]
async fn accepts_encoding_without_qvalues() {
let req = Request::builder()
.header(ACCEPT_ENCODING, "gzip, deflate, br")
.body(())
.unwrap();
let encodings = AcceptEncoding::from_request_parts(
&mut req.into_parts().0,
&Arc::new(ServerConfig {
json_api_enabled: false,
decompress: false,
..default()
}),
)
.await
.unwrap();
assert_eq!(encodings.0, Some("gzip, deflate, br".to_string()));
assert!(encodings.is_acceptable(&HeaderValue::from_static("deflate")));
assert!(encodings.is_acceptable(&HeaderValue::from_static("gzip")));
assert!(encodings.is_acceptable(&HeaderValue::from_static(BROTLI)));
assert!(!encodings.is_acceptable(&HeaderValue::from_static("bzip2")));
}
}