1use mime::Mime;
2
3#[derive(Debug, Clone, Copy)]
4pub enum JsonOrProto {
5 Json,
6 Proto,
7}
8
9impl JsonOrProto {
10 pub fn from_mime(mime: &Mime) -> Option<Self> {
11 if is_json(mime) {
12 Some(JsonOrProto::Json)
13 } else if is_protobuf(mime) {
14 Some(JsonOrProto::Proto)
15 } else {
16 None
17 }
18 }
19}
20
21pub fn content_type(headers: &http::HeaderMap) -> Option<Mime> {
23 headers.get(http::header::CONTENT_TYPE).and_then(parse)
24}
25
26pub fn accept(headers: &http::HeaderMap) -> Option<Mime> {
28 headers.get(http::header::ACCEPT).and_then(parse)
29}
30
31pub fn parse(header: &http::HeaderValue) -> Option<Mime> {
33 header.to_str().ok()?.split(',').next()?.trim().parse().ok()
34}
35
36pub fn is_json(mime: &mime::Mime) -> bool {
37 mime.type_() == mime::APPLICATION
38 && (mime.subtype() == mime::JSON || mime.suffix() == Some(mime::JSON))
39}
40
41pub fn is_protobuf(mime: &mime::Mime) -> bool {
42 mime.type_() == mime::APPLICATION && {
43 let s = mime.subtype().as_str();
44 s.eq_ignore_ascii_case("protobuf") || s.eq_ignore_ascii_case("x-protobuf")
45 }
46}
47
48pub fn is_s2s_proto(mime: &Mime) -> bool {
49 mime.type_().as_str().eq_ignore_ascii_case("s2s")
50 && mime.subtype().as_str().eq_ignore_ascii_case("proto")
51}
52
53pub fn is_event_stream(mime: &mime::Mime) -> bool {
54 mime.type_() == mime::TEXT && mime.subtype() == mime::EVENT_STREAM
55}
56
57#[cfg(test)]
58mod tests {
59 use mime::Mime;
60 use rstest::rstest;
61
62 #[rstest]
63 #[case("application/json", Some("application/json"))]
64 #[case(" application/json , application/protobuf", Some("application/json"))]
65 #[case(
66 "application/json; charset=utf-8",
67 Some("application/json;charset=utf-8")
68 )]
69 #[case("", None)]
70 #[case("not/a/mime, application/json", None)]
71 fn parse(#[case] header: &'static str, #[case] expected: Option<&'static str>) {
72 let header = http::HeaderValue::from_static(header);
73 let expected = expected.map(|s| s.parse::<Mime>().unwrap());
74 assert_eq!(super::parse(&header), expected);
75 }
76
77 #[test]
78 fn parse_returns_none_for_non_utf8_header_values() {
79 let header = http::HeaderValue::from_bytes(b"\xFF\xFF").unwrap();
80 assert_eq!(super::parse(&header), None);
81 }
82}