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
11pub struct Request<'a> {
13 pub rl: RequestLine<'a>,
15 pub headers: SipHeaders<'a>,
17 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 let (body, _) = tag("\r\n")(input)?;
40 Ok((buf_input, Request::new(rl, headers, Some(body))))
41 }
42}
43
44pub 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}