1use crate::{
2 common::bnfcore::is_unreserved, common::hostport::HostPort,
3 common::nom_wrappers::from_utf8_nom, common::nom_wrappers::take_while_with_escaped,
4 common::traits::NomParser, errorparse::SipParseError, headers::GenericParams,
5 userinfo::UserInfo,
6};
7use alloc::collections::btree_map::BTreeMap;
8use nom::bytes::complete::{take, take_till, take_until};
9
10use core::str;
11
12#[derive(Copy, Clone, PartialEq, Debug)]
13pub enum RequestUriScheme {
14 SIP,
15 SIPS,
16}
17
18impl RequestUriScheme {
19 pub fn from_bytes(s: &[u8]) -> Result<RequestUriScheme, nom::Err<SipParseError>> {
20 match s {
21 b"sip" => Ok(Self::SIP),
22 b"sips" => Ok(Self::SIPS),
23 _ => sip_parse_error!(101, "Can't parse sipuri scheme"),
24 }
25 }
26}
27
28#[inline]
30fn is_hnv_unreserved_char(c: u8) -> bool {
31 c == b'[' || c == b']' || c == b'/' || c == b'?' || c == b':' || c == b'+' || c == b'$'
32}
33
34#[inline]
35fn is_hnv_char(c: u8) -> bool {
36 is_unreserved(c) || is_hnv_unreserved_char(c)
37}
38
39pub struct SipUriHeader<'a> {
44 pub name: &'a str,
45 pub value: &'a str,
46}
47
48impl<'a> SipUriHeader<'a> {
49 fn parse_header(input: &[u8]) -> nom::IResult<&[u8], SipUriHeader, SipParseError> {
50 let (input, hname) = take_while_with_escaped(input, is_hnv_char)?;
51 if input.len() == 0 || input[0] != b'=' {
52 let (_, hname_str) = from_utf8_nom(hname)?;
53 return Ok((
54 input,
55 SipUriHeader {
56 name: hname_str,
57 value: "",
58 },
59 ));
60 }
61
62 let (input, _) = take(1usize)(input)?; let (input, hvalue) = take_while_with_escaped(input, is_hnv_char)?;
65 let (_, hname_str) = from_utf8_nom(hname)?;
66 let (_, hvalue_str) = from_utf8_nom(hvalue)?;
67 Ok((
68 input,
69 SipUriHeader {
70 name: hname_str,
71 value: hvalue_str,
72 },
73 ))
74 }
75}
76
77impl<'a> NomParser<'a> for SipUriHeader<'a> {
78 type ParseResult = BTreeMap<&'a str, &'a str>;
79
80 fn parse(input: &'a [u8]) -> nom::IResult<&[u8], Self::ParseResult, SipParseError> {
82 let (input, c) = take(1usize)(input)?;
83 if c[0] != b'?' {
84 return sip_parse_error!(1, "The first character of headers must be '?'");
85 }
86
87 let mut result = BTreeMap::new();
88 let mut inp2 = input;
89 loop {
90 let (input, sip_uri_header) = SipUriHeader::parse_header(inp2)?;
91 result.insert(sip_uri_header.name, sip_uri_header.value);
92 if input.len() == 0 || input[0] != b'&' {
93 inp2 = input;
94 break;
95 }
96 let (input, _) = take(1usize)(input)?;
97 inp2 = input;
98 }
99
100 Ok((inp2, result))
101 }
102}
103
104#[derive(PartialEq, Debug)]
113pub struct SipUri<'a> {
114 pub scheme: RequestUriScheme,
115 user_info: Option<UserInfo<'a>>,
116 pub hostport: HostPort<'a>,
117 parameters: Option<GenericParams<'a>>,
120 headers: Option<BTreeMap<&'a str, &'a str>>,
121}
122
123impl<'a> SipUri<'a> {
124 pub fn user_info(&self) -> Option<&UserInfo<'a>> {
125 self.user_info.as_ref()
126 }
127
128 pub fn params(&self) -> Option<&GenericParams<'a>> {
129 self.parameters.as_ref()
130 }
131
132 pub fn headers(&self) -> Option<&BTreeMap<&'a str, &'a str>> {
133 self.headers.as_ref()
134 }
135
136 fn try_parse_params(
137 input: &'a [u8],
138 ) -> nom::IResult<&[u8], Option<GenericParams<'a>>, SipParseError> {
139 if input[0] != b';' {
140 return Ok((input, None));
141 }
142 match GenericParams::parse(input) {
143 Ok((input, params)) => {
144 return Ok((input, Some(params)));
145 }
146 Err(e) => {
147 return Err(e);
148 }
149 }
150 }
151
152 fn try_parse_headers(
153 input: &'a [u8],
154 ) -> nom::IResult<&[u8], Option<BTreeMap<&'a str, &'a str>>, SipParseError> {
155 if input[0] != b'?' {
156 return Ok((input, None));
157 }
158 match SipUriHeader::parse(input) {
159 Ok((input, headers)) => {
160 return Ok((input, Some(headers)));
161 }
162 Err(e) => {
163 return Err(e);
164 }
165 }
166 }
167
168 pub fn parse_ext(
170 input: &'a [u8],
171 parse_with_parameters: bool,
172 ) -> nom::IResult<&[u8], SipUri<'a>, SipParseError> {
173 let (input, uri_scheme) = take_until(":")(input)?;
174 let (input_after_scheme, _) = take(1usize)(input)?; let scheme = RequestUriScheme::from_bytes(uri_scheme)?;
176
177 let (right_with_ampersat, before_ampersat) =
178 take_till(|c| c == b'@' || c == b'\n' || c == b',')(input_after_scheme)?;
179 let is_user_info_present = right_with_ampersat.is_empty()
180 || right_with_ampersat[0] == b'\n'
181 || right_with_ampersat[0] == b',';
182 let userinfo = if is_user_info_present {
184 None
185 } else {
186 Some(UserInfo::from_bytes(before_ampersat)?)
187 };
188 let input = if is_user_info_present {
191 input_after_scheme
192 } else {
193 &right_with_ampersat[1..] };
195
196 let (input, hostport) = HostPort::parse(input)?;
197
198 if !parse_with_parameters {
199 let (input, headers) = if input.is_empty() {
200 (input, None)
201 } else {
202 SipUri::try_parse_headers(input)?
203 };
204
205 return Ok((
206 input,
207 SipUri {
208 scheme: scheme,
209 user_info: userinfo,
210 hostport: hostport,
211 parameters: None,
212 headers: headers,
213 },
214 ));
215 }
216
217 let (input, params) = if input.is_empty() {
218 (input, None)
219 } else {
220 SipUri::try_parse_params(input)?
221 };
222
223 let (input, headers) = if input.is_empty() {
224 (input, None)
225 } else {
226 SipUri::try_parse_headers(input)?
227 };
228
229 Ok((
230 input,
231 SipUri {
232 scheme: scheme,
233 user_info: userinfo,
234 hostport: hostport,
235 parameters: params,
236 headers: headers,
237 },
238 ))
239 }
240}
241
242impl<'a> NomParser<'a> for SipUri<'a> {
243 type ParseResult = SipUri<'a>;
244
245 fn parse(input: &'a [u8]) -> nom::IResult<&[u8], Self::ParseResult, SipParseError> {
246 SipUri::parse_ext(input, true)
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253
254 #[test]
255 fn test_sip_uri_parse() {
256 let (rest, sip_uri) =
257 SipUri::parse_ext("sip:192.0.2.254:5061>\r\nblablabla@somm".as_bytes(), true).unwrap();
258 assert_eq!(rest, ">\r\nblablabla@somm".as_bytes());
259 assert_eq!(sip_uri.scheme, RequestUriScheme::SIP);
260 assert_eq!(sip_uri.hostport.host, "192.0.2.254");
261 assert_eq!(sip_uri.hostport.port, Some(5061));
262 let (rest, sip_uri) = SipUri::parse_ext("sip:atlanta.com".as_bytes(), true).unwrap();
264 assert_eq!(rest.len(), 0);
265 assert_eq!(sip_uri.scheme, RequestUriScheme::SIP);
266 assert_eq!(sip_uri.hostport.host, "atlanta.com");
267
268 let (rest, sip_uri) = SipUri::parse_ext("sip:alice@atlanta.com".as_bytes(), true).unwrap();
269 assert_eq!(rest.len(), 0);
270 assert_eq!(sip_uri.scheme, RequestUriScheme::SIP);
271 assert_eq!(sip_uri.user_info().unwrap().value, "alice");
272 assert_eq!(sip_uri.hostport.host, "atlanta.com");
273
274 let (rest, sip_uri) = SipUri::parse_ext(
275 "sip:alice:secretword@atlanta.com;transport=tcp".as_bytes(),
276 true,
277 )
278 .unwrap();
279 assert_eq!(rest.len(), 0);
280 assert_eq!(sip_uri.scheme, RequestUriScheme::SIP);
281 assert_eq!(sip_uri.user_info().unwrap().value, "alice");
282 assert_eq!(sip_uri.user_info().unwrap().password, Some("secretword"));
283 assert_eq!(sip_uri.hostport.host, "atlanta.com");
284 assert_eq!(sip_uri.hostport.port, None);
285 assert_eq!(
286 sip_uri.params().unwrap().get(&"transport"),
287 Some(&Some("tcp"))
288 );
289
290 let (rest, sip_uri) = SipUri::parse_ext(
291 "sip:+1-212-555-1212:1234@gateway.com;user=phone".as_bytes(),
292 true,
293 )
294 .unwrap();
295 assert_eq!(rest.len(), 0);
296 assert_eq!(sip_uri.scheme, RequestUriScheme::SIP);
297 assert_eq!(sip_uri.user_info().unwrap().value, "+1-212-555-1212");
298 assert_eq!(sip_uri.user_info().unwrap().password, Some("1234"));
299 assert_eq!(sip_uri.hostport.host, "gateway.com");
300 assert_eq!(sip_uri.hostport.port, None);
301 assert_eq!(sip_uri.params().unwrap().get(&"user"), Some(&Some("phone")));
302
303 let (rest, sip_uri) = SipUri::parse_ext("sips:1212@gateway.com".as_bytes(), true).unwrap();
304 assert_eq!(rest.len(), 0);
305 assert_eq!(sip_uri.scheme, RequestUriScheme::SIPS);
306 assert_eq!(sip_uri.user_info().unwrap().value, "1212");
307 assert_eq!(sip_uri.hostport.host, "gateway.com");
308
309 let (rest, sip_uri) =
310 SipUri::parse_ext("sip:alice@192.0.2.4:8888".as_bytes(), true).unwrap();
311 assert_eq!(rest.len(), 0);
312 assert_eq!(sip_uri.scheme, RequestUriScheme::SIP);
313 assert_eq!(sip_uri.user_info().unwrap().value, "alice");
314 assert_eq!(sip_uri.hostport.host, "192.0.2.4");
315 assert_eq!(sip_uri.hostport.port, Some(8888));
316
317 let (rest, sip_uri) =
318 SipUri::parse_ext("sip:alice;day=tuesday@atlanta.com".as_bytes(), true).unwrap();
319 assert_eq!(rest.len(), 0);
320 assert_eq!(sip_uri.scheme, RequestUriScheme::SIP);
321 assert_eq!(sip_uri.user_info().unwrap().value, "alice;day=tuesday");
322 assert_eq!(sip_uri.hostport.host, "atlanta.com");
323
324 let (rest, sip_uri) = SipUri::parse_ext(
325 "sips:alice@atlanta.com?subject=project%20x&priority=urgent".as_bytes(),
326 true,
327 )
328 .unwrap();
329 assert_eq!(rest.len(), 0);
330 assert_eq!(
331 sip_uri.headers().unwrap().get(&"subject"),
332 Some(&"project%20x")
333 );
334 assert_eq!(sip_uri.headers().unwrap().get(&"priority"), Some(&"urgent"));
335 assert_eq!(sip_uri.scheme, RequestUriScheme::SIPS);
336 assert_eq!(sip_uri.user_info().unwrap().value, "alice");
337 assert_eq!(sip_uri.hostport.host, "atlanta.com");
338
339 let (rest, sip_uri) = SipUri::parse_ext(
340 "sip:atlanta.com;method=REGISTER?to=alice%40atlanta.com".as_bytes(),
341 true,
342 )
343 .unwrap();
344 assert_eq!(rest.len(), 0);
345 assert_eq!(
346 sip_uri.headers().unwrap().get(&"to"),
347 Some(&"alice%40atlanta.com")
348 );
349 assert_eq!(
350 sip_uri.params().unwrap().get(&"method"),
351 Some(&Some("REGISTER"))
352 );
353 assert_eq!(sip_uri.scheme, RequestUriScheme::SIP);
354 assert_eq!(sip_uri.hostport.host, "atlanta.com");
355 assert_eq!(sip_uri.user_info(), None);
356
357 let (rest, sip_uri) = SipUri::parse_ext(
358 "sips:alice@atlanta.com?subject=project%20x&priority=urgent ;transport=tcp".as_bytes(),
359 false,
360 )
361 .unwrap();
362 assert_eq!(
364 sip_uri.headers().unwrap().get(&"subject"),
365 Some(&"project%20x")
366 );
367 assert_eq!(sip_uri.headers().unwrap().get(&"priority"), Some(&"urgent"));
368 assert_eq!(sip_uri.user_info().unwrap().value, "alice");
369 assert_eq!(sip_uri.scheme, RequestUriScheme::SIPS);
370 assert_eq!(sip_uri.hostport.host, "atlanta.com");
371
372 assert_eq!(sip_uri.params(), None);
373
374 assert_eq!(rest, b" ;transport=tcp");
375 }
376}