sipmsg/
request.rs

1use crate::common::{errorparse::SipParseError, sip_method::*, traits::NomParser};
2use crate::{headers::*, message::*};
3use nom::{
4    bytes::complete::{tag, take_while1},
5    character::{complete, is_alphabetic},
6    sequence::tuple,
7};
8
9use core::{str, u8};
10
11/// [rfc3261 section-7.1](https://tools.ietf.org/html/rfc3261#section-7.1)
12pub struct Request<'a> {
13    /// The request line. Example: `OPTIONS sip:user@example.com SIP/2.0`
14    pub rl: RequestLine<'a>,
15    /// The request headers.
16    pub headers: SipHeaders<'a>,
17    /// The body of message
18    pub body: Option<&'a [u8]>,
19}
20
21impl<'a> Request<'a> {
22    fn new(rl: RequestLine<'a>, headers: SipHeaders<'a>, body: Option<&'a [u8]>) -> Request<'a> {
23        Request {
24            rl: rl,
25            headers: headers,
26            body: body,
27        }
28    }
29}
30
31impl<'a> NomParser<'a> for Request<'a> {
32    type ParseResult = Request<'a>;
33
34    fn parse(buf_input: &'a [u8]) -> nom::IResult<&[u8], Request, SipParseError> {
35        let (input, rl) = RequestLine::parse(buf_input)?;
36
37        let (input, headers) = SipHeaders::parse(input)?;
38        // TODO check header Content-Length and fix buf_input return
39        let (body, _) = tag("\r\n")(input)?;
40        Ok((buf_input, Request::new(rl, headers, Some(body))))
41    }
42}
43
44/// Ex: `INVITE sip:user@example.com SIP/2.0`
45/// The Request line and u8 buffer shoud have the same life time
46pub struct RequestLine<'a> {
47    pub method: SipMethod,
48    pub uri: SipUri<'a>,
49    pub sip_version: SipVersion,
50}
51
52impl<'a> NomParser<'a> for RequestLine<'a> {
53    type ParseResult = RequestLine<'a>;
54
55    fn parse(rl: &[u8]) -> nom::IResult<&[u8], RequestLine, SipParseError> {
56        let method = take_while1(is_alphabetic);
57        let uri = take_while1(|c| c != b' ' as u8);
58        let (input, (method, _, uri, _, _, major_version, _, minor_version, _)) = tuple((
59            method,
60            complete::space1,
61            uri,
62            complete::space1,
63            tag("SIP/"),
64            complete::digit1,
65            complete::char('.'),
66            complete::digit1,
67            complete::crlf,
68        ))(rl)?;
69
70        let (_, sip_uri) = SipUri::parse(uri)?;
71
72        let sip_version = SipVersion(
73            u8::from_str_radix(str::from_utf8(major_version).unwrap(), 10).unwrap(),
74            u8::from_str_radix(str::from_utf8(minor_version).unwrap(), 10).unwrap(),
75        );
76
77        match RequestLine::parse_method(method) {
78            Some(m) => Ok((
79                input,
80                RequestLine {
81                    method: m,
82                    uri: sip_uri,
83                    sip_version: sip_version,
84                },
85            )),
86            None => return sip_parse_error!(1, "Error cast from_utf8"),
87        }
88    }
89}
90
91impl<'a> RequestLine<'a> {
92    fn parse_method(method: &[u8]) -> Option<SipMethod> {
93        match str::from_utf8(method) {
94            Ok(s) => SipMethod::from_str(s),
95            Err(_) => None,
96        }
97    }
98}