Skip to main content

ftth_rsip/headers/auth/
scheme.rs

1#[doc(hidden)]
2pub use tokenizer::Tokenizer;
3
4/// The `Scheme`, as part of the SIP Authorization framework, found in headers like
5/// [Authorization](super::super::typed::Authorization) and
6/// [WwwAuthenticate](super::super::typed::WwwAuthenticate)
7#[derive(Debug, PartialEq, Eq, Clone)]
8pub enum Scheme {
9    Digest,
10    Other(String),
11}
12
13impl Default for Scheme {
14    fn default() -> Self {
15        Self::Digest
16    }
17}
18
19impl std::fmt::Display for Scheme {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        match self {
22            Self::Digest => write!(f, "Digest"),
23            Self::Other(inner) => write!(f, "{}", inner),
24        }
25    }
26}
27
28impl<'a> std::convert::TryFrom<Tokenizer<'a, &'a [u8], u8>> for Scheme {
29    type Error = crate::Error;
30
31    fn try_from(tokenizer: Tokenizer<'a, &'a [u8], u8>) -> Result<Self, Self::Error> {
32        use std::str::from_utf8;
33
34        match from_utf8(tokenizer.value)? {
35            part if part.eq_ignore_ascii_case("digest") => Ok(Self::Digest),
36            part => Ok(Self::Other(part.into())),
37        }
38    }
39}
40
41impl<'a> std::convert::TryFrom<Tokenizer<'a, &'a str, char>> for Scheme {
42    type Error = crate::Error;
43
44    fn try_from(tokenizer: Tokenizer<'a, &'a str, char>) -> Result<Self, Self::Error> {
45        match tokenizer.value {
46            part if part.eq_ignore_ascii_case("digest") => Ok(Self::Digest),
47            part => Ok(Self::Other(part.into())),
48        }
49    }
50}
51
52#[doc(hidden)]
53mod tokenizer {
54    use crate::{AbstractInput, GResult, GenericNomError, TokenizerError};
55    use std::marker::PhantomData;
56
57    #[derive(Debug, PartialEq, Eq, Clone)]
58    pub struct Tokenizer<'a, T, I>
59    where
60        T: AbstractInput<'a, I>,
61        I: nom::AsChar,
62    {
63        pub value: T,
64        phantom1: PhantomData<&'a T>,
65        phantom2: PhantomData<I>,
66    }
67
68    impl<'a, T, I> From<T> for Tokenizer<'a, T, I>
69    where
70        T: AbstractInput<'a, I>,
71        I: nom::AsChar,
72    {
73        fn from(value: T) -> Self {
74            Self {
75                value,
76                phantom1: PhantomData,
77                phantom2: PhantomData,
78            }
79        }
80    }
81
82    impl<'a, T, I> Tokenizer<'a, T, I>
83    where
84        T: AbstractInput<'a, I>,
85        I: nom::AsChar,
86    {
87        pub fn tokenize(part: T) -> GResult<T, Self> {
88            use nom::{branch::alt, bytes::complete::take_until, combinator::rest};
89
90            let (rem, scheme) =
91                alt((take_until(" "), rest))(part).map_err(|_: GenericNomError<'a, T>| {
92                    TokenizerError::from(("scheme (header)", part)).into()
93                })?;
94
95            Ok((rem, Self::from(scheme)))
96        }
97    }
98}