sipmsg/headers/
header.rs

1use crate::{
2    common::{
3        bnfcore::*,
4        errorparse::SipParseError,
5        nom_wrappers::{from_utf8_nom, take_sws},
6        take_sws_token,
7        traits::NomParser,
8    },
9    headers::{
10        parsers::ExtensionParser,
11        traits::{HeaderValueParserFn, SipHeaderParser},
12        GenericParams, SipRFCHeader, SipUri,
13    },
14};
15use alloc::collections::{BTreeMap, VecDeque};
16use core::str;
17use nom::{bytes::complete::take_while1, character::complete, sequence::tuple};
18use unicase::Ascii;
19
20// All possible types of value
21// Glossary: R-required, O-optional
22#[derive(PartialEq, Debug)]
23pub enum HeaderValueType {
24    EmptyValue,           // SIP header with empty value. Haven't tags
25    TokenValue,           // Haven't tags. Simple value of token chars
26    Digit,                // Haven't tags, just *[0-9] in HeaderValue.vstr
27    AbsoluteURI,          // tags: AbsoluteURI(R),
28    QuotedValue,          // tags: PureValue(R)
29    AuthentificationInfo, // tags: AinfoType(R), AinfoValue(R)
30    CSeq,                 // tags: Number(R), Method(R)
31    DateString,           // Haven't tags
32    Utf8Text,             // Haven't tags
33    Version,              // tags: Major(R) Minor(O)
34
35    // Authorization     =  "Authorization" HCOLON credentials
36    // credentials       =  ("Digest" LWS digest-response)
37    // other-response
38    AuthorizationDigest, // tags: username / realm / nonce / digest-uri
39    //       / dresponse / algorithm / cnonce
40    //       / opaque / QopValue / nonce-count / auth-param
41
42    // callid   =  word [ "@" word ]
43    CallID, // tags: ID(R), Host(O)
44
45    // Call-Info   =  "Call-Info" HCOLON info *(COMMA info)
46    CallInfo, // tags: PureValue(R)
47
48    /// Contact, From, To, Record-Route, Route headers
49    NameAddr, // tags: Star(O), DisplayName(O), AbsoluteURI(O)
50
51    Timestamp, // tags: TimeVal, Delay
52
53    RetryAfter, // tags: Seconds(R), Comment(O)
54    UserAgent,  // haven't tags,
55
56    Via,     // tags: ProtocolName(R),ProtocolVersion(R),ProtocolTransport(R), Host(R), Port(O)
57    Warning, // tags: WarnCode(R), WarnAgent(R), WarnText(R)
58    ExtensionHeader, // No tags
59}
60
61#[derive(PartialEq, Debug, Eq, PartialOrd, Ord)]
62pub enum HeaderTagType {
63    PureValue,
64    AinfoType,   // nextnonce, qop, rspauth, etc.
65    AinfoValue,  // value after equal without quotes
66    AbsoluteURI, // absolute uri without qoutes
67    // Auth params: (Headers: Authorization, Proxy-Authenticate)
68    AuthSchema,
69    Username,
70    Domain,
71    Realm,
72    Nonce,
73    DigestUri, // digest-uri-value  =  Request-URI ; as defined in Section 25
74    Dresponse,
75    Algorithm,
76    Cnonce,
77    Opaque,
78    Stale,
79    QopValue,
80    NonceCount,
81    ///////////////
82    Number,
83    Method,
84    ID,
85    Host,
86    Port,
87    Star, // alway must be equal to *
88    DisplayName,
89    Seconds,
90    Comment,
91    Major,
92    Minor,
93    TimveVal,
94    Delay,
95
96    ProtocolName,
97    ProtocolVersion,
98    ProtocolTransport,
99
100    WarnCode,
101    WarnAgent,
102    WarnText,
103}
104
105pub type HeaderTags<'a> = BTreeMap<HeaderTagType, &'a [u8]>;
106
107#[derive(PartialEq, Debug)]
108pub struct HeaderValue<'a> {
109    pub vstr: &'a str,
110    pub vtype: HeaderValueType,
111    vtags: Option<HeaderTags<'a>>,
112    sip_uri: Option<SipUri<'a>>,
113}
114
115impl<'a> HeaderValue<'a> {
116    pub fn create_empty_value() -> HeaderValue<'a> {
117        HeaderValue {
118            vstr: "",
119            vtype: HeaderValueType::EmptyValue,
120            vtags: None,
121            sip_uri: None,
122        }
123    }
124
125    pub fn new(
126        val: &'a [u8],
127        vtype: HeaderValueType,
128        vtags: Option<HeaderTags<'a>>,
129        sip_uri: Option<SipUri<'a>>,
130    ) -> nom::IResult<&'a [u8], HeaderValue<'a>, SipParseError<'a>> {
131        let (_, vstr) = from_utf8_nom(val)?;
132
133        Ok((
134            val,
135            HeaderValue {
136                vstr: vstr,
137                vtype: vtype,
138                vtags: vtags,
139                sip_uri: sip_uri,
140            },
141        ))
142    }
143
144    pub fn tags(&self) -> Option<&HeaderTags<'a>> {
145        self.vtags.as_ref()
146    }
147
148    pub fn sip_uri(&self) -> Option<&SipUri<'a>> {
149        self.sip_uri.as_ref()
150    }
151}
152
153#[derive(PartialEq, Debug)]
154/// [rfc3261 section-7.3](https://tools.ietf.org/html/rfc3261#section-7.3)
155pub struct Header<'a> {
156    /// SIP header name
157    pub name: Ascii<&'a str>,
158    /// SIP header value
159    pub value: HeaderValue<'a>,
160    /// SIP parameters
161    parameters: Option<GenericParams<'a>>,
162}
163
164impl<'a> Header<'a> {
165    pub fn new(
166        name: &'a str,
167        value: HeaderValue<'a>,
168        parameters: Option<GenericParams<'a>>,
169    ) -> Header<'a> {
170        Header {
171            name: { Ascii::new(name) },
172            value: value,
173            parameters: parameters,
174        }
175    }
176
177    pub fn params(&self) -> Option<&GenericParams<'a>> {
178        self.parameters.as_ref()
179    }
180
181    pub fn find_parser(header_name: &'a str) -> (Option<SipRFCHeader>, HeaderValueParserFn) {
182        match SipRFCHeader::from_str(&header_name) {
183            Some(rfc_header) => (Some(rfc_header), rfc_header.get_parser()),
184            None => (None, ExtensionParser::take_value),
185        }
186    }
187
188    pub fn take_name(input: &'a [u8]) -> nom::IResult<&[u8], &'a str, SipParseError> {
189        let (input_rest, (header_name, _, _, _)) = tuple((
190            take_while1(is_token_char),
191            complete::space0,
192            complete::char(':'),
193            complete::space0,
194        ))(input)?;
195        match str::from_utf8(header_name) {
196            Ok(hdr_str) => Ok((input_rest, hdr_str)),
197            Err(_) => sip_parse_error!(1, "Bad header name"),
198        }
199    }
200
201    /// Should return COMMA, SEMI or '\r\n' in first argument
202    pub fn take_value(
203        input: &'a [u8],
204        parser: HeaderValueParserFn,
205    ) -> nom::IResult<&'a [u8], (HeaderValue<'a>, Option<GenericParams<'a>>), SipParseError<'a>>
206    {
207        // skip whitespaces before take value
208        let (input, _) = take_sws(input)?;
209        if is_crlf(input) {
210            return Ok((input, (HeaderValue::create_empty_value(), None))); // This is header with empty value
211        }
212
213        let (inp, value) = parser(input)?;
214        // let (_, value) = from_utf8_nom(value)?;
215
216        // skip whitespaces after take value
217        let (inp, _) = complete::space0(inp)?;
218        if inp.is_empty() {
219            return sip_parse_error!(1, "Error parse header value");
220        }
221        if inp[0] != b',' && inp[0] != b';' && inp[0] != b' ' && !is_crlf(inp) {
222            return sip_parse_error!(2, "Error parse header value");
223        }
224
225        if inp[0] == b';' {
226            let (inp, params) = Header::try_take_parameters(inp)?;
227            return Ok((inp, (value, params)));
228        }
229        Ok((inp, (value, None)))
230    }
231
232    fn try_take_parameters(
233        input: &'a [u8],
234    ) -> nom::IResult<&'a [u8], Option<GenericParams<'a>>, SipParseError<'a>> {
235        if input.is_empty() || input[0] != b';' {
236            return Ok((input, None));
237        }
238        let (input, parameters) = GenericParams::parse(input)?;
239        Ok((input, Some(parameters)))
240    }
241}
242
243impl<'a> NomParser<'a> for Header<'a> {
244    type ParseResult = (Option<SipRFCHeader>, VecDeque<Header<'a>>);
245    fn parse(input: &'a [u8]) -> nom::IResult<&[u8], Self::ParseResult, SipParseError> {
246        let mut headers = VecDeque::new();
247        let (input, header_name) = Header::take_name(input)?;
248        let (rfc_type, value_parser) = Header::find_parser(header_name);
249        let mut inp = input;
250        loop {
251            let (input, (value, params)) = Header::take_value(inp, value_parser)?;
252            headers.push_back(Header::new(header_name, value, params));
253            if input[0] == b',' {
254                let (input, _) = take_sws_token::comma(input)?;
255                inp = input;
256                continue;
257            }
258            inp = input;
259            break;
260        }
261        Ok((inp, (rfc_type, headers)))
262    }
263}