lib_humus/headers/
accept_header.rs1use std::{fmt::Display, str::FromStr};
6
7use axum::extract::OptionalFromRequestParts;
8
9use crate::headers::parser::HeaderParser;
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub enum AcceptHeaderItem {
16 Wildcard,
18
19 PartialWildcard(String),
21
22 MediaType(String),
24}
25
26impl Display for AcceptHeaderItem {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match self {
29 Self::Wildcard => write!(f, "*/*"),
30 Self::PartialWildcard(media_type) => write!(f, "{media_type}/*"),
31 Self::MediaType(media_type) => write!(f, "{media_type}"),
32 }
33 }
34}
35
36impl FromStr for AcceptHeaderItem {
37 type Err = String;
38
39 fn from_str(s: &str) -> Result<Self, Self::Err> {
40 let mut parser = HeaderParser::new(s);
41 if let Some(item) = parser.parse_accept_header_item() {
42 if !parser.is_at_end() {
43 return Err(format!(
44 "Found additional data after media type or wildcard. Expexted text to end after '{item}'"
45 ));
46 }
47 return Ok(item);
48 } else {
49 return Err("Unable to parse accept header item, expected some/type[+foo], some/* or */* as imput.".to_string());
50 }
51 }
52}
53
54impl<'de> serde::de::Deserialize<'de> for AcceptHeaderItem {
55 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
56 where
57 D: serde::Deserializer<'de>,
58 {
59 deserializer.deserialize_str(AcceptHeaderItemVisitor)
60 }
61}
62
63struct AcceptHeaderItemVisitor;
64
65impl<'de> serde::de::Visitor<'de> for AcceptHeaderItemVisitor {
66 type Value = AcceptHeaderItem;
67
68 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
69 write!(
70 f,
71 "The media_type part of an HTTP Accept header, i.e. some/type[+foo], some/* or */*"
72 )
73 }
74
75 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
76 where
77 E: serde::de::Error,
78 {
79 AcceptHeaderItem::from_str(v).map_err(|e| E::custom(e.to_string()))
80 }
81}
82
83impl serde::Serialize for AcceptHeaderItem {
84 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85 where
86 S: serde::Serializer,
87 {
88 serializer.serialize_str(self.to_string().as_str())
89 }
90}
91
92#[derive(Debug, Clone, PartialEq)]
94pub struct AcceptHeader {
95 pub items: Vec<(AcceptHeaderItem, f32)>,
97}
98
99impl AcceptHeader {
100 pub fn new(header_text: &str) -> Self {
102 HeaderParser::new(header_text).parse_accept()
103 }
104}
105
106impl FromStr for AcceptHeader {
107 type Err = ();
108
109 fn from_str(s: &str) -> Result<Self, Self::Err> {
110 Ok(HeaderParser::new(s).parse_accept())
111 }
112}
113
114impl<S> OptionalFromRequestParts<S> for AcceptHeader
115where
116 S: Sync,
117{
118 type Rejection = ();
119
120 async fn from_request_parts(
121 parts: &mut axum::http::request::Parts,
122 _state: &S,
123 ) -> Result<Option<Self>, Self::Rejection> {
124 Ok(parts
125 .headers
126 .get("accept")
127 .and_then(|v| Some(AcceptHeader::new(v.to_str().ok()?))))
128 }
129}