rama_http/layer/validate_request/
accept_header.rs1use rama_core::error::{BoxError, ErrorContext};
2use rama_http_types::body::OptionalBody;
3
4use super::ValidateRequest;
5use crate::{
6 Body, Request, Response, StatusCode, header,
7 mime::{Mime, MimeIter},
8};
9use std::{fmt, marker::PhantomData, sync::Arc};
10
11pub struct AcceptHeader<ResBody = Body> {
13 header_value: Arc<Mime>,
14 _ty: PhantomData<fn() -> ResBody>,
15}
16
17impl<ResBody> AcceptHeader<ResBody> {
18 pub(super) fn new(mime: Mime) -> Self {
20 Self {
21 header_value: Arc::new(mime),
22 _ty: PhantomData,
23 }
24 }
25
26 pub(super) fn try_new(header_value: &str) -> Result<Self, BoxError> {
32 Ok(Self {
33 header_value: Arc::new(
34 header_value
35 .parse::<Mime>()
36 .context("value is not a valid header value")?,
37 ),
38 _ty: PhantomData,
39 })
40 }
41}
42
43impl<ResBody> Clone for AcceptHeader<ResBody> {
44 fn clone(&self) -> Self {
45 Self {
46 header_value: self.header_value.clone(),
47 _ty: PhantomData,
48 }
49 }
50}
51
52impl<ResBody> fmt::Debug for AcceptHeader<ResBody> {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 f.debug_struct("AcceptHeader")
55 .field("header_value", &self.header_value)
56 .finish()
57 }
58}
59
60impl<B, ResBody> ValidateRequest<B> for AcceptHeader<ResBody>
61where
62 B: Send + Sync + 'static,
63 ResBody: Send + 'static,
64{
65 type ResponseBody = OptionalBody<ResBody>;
66
67 async fn validate(&self, req: Request<B>) -> Result<Request<B>, Response<Self::ResponseBody>> {
68 if !req.headers().contains_key(header::ACCEPT) {
69 return Ok(req);
70 }
71 if req
72 .headers()
73 .get_all(header::ACCEPT)
74 .into_iter()
75 .filter_map(|header| header.to_str().ok())
76 .any(|h| {
77 MimeIter::new(h)
78 .map(|mim| {
79 if let Ok(mim) = mim {
80 let typ = self.header_value.type_();
81 let subtype = self.header_value.subtype();
82 match (mim.type_(), mim.subtype()) {
83 (t, s) if t == typ && s == subtype => true,
84 (t, crate::mime::STAR) if t == typ => true,
85 (crate::mime::STAR, crate::mime::STAR) => true,
86 _ => false,
87 }
88 } else {
89 false
90 }
91 })
92 .reduce(|acc, mim| acc || mim)
93 .unwrap_or(false)
94 })
95 {
96 return Ok(req);
97 }
98 let mut res = Response::new(OptionalBody::none());
99 *res.status_mut() = StatusCode::NOT_ACCEPTABLE;
100 Err(res)
101 }
102}