// written by Giuseppe Longo <giuseppe@glono.it>
-use nom::*;
-use nom::IResult;
-use nom::character::{is_alphabetic, is_alphanumeric, is_space};
-use nom::character::streaming::crlf;
+use nom7::bytes::streaming::{take, take_while, take_while1};
+use nom7::character::streaming::{char, crlf};
+use nom7::character::{is_alphabetic, is_alphanumeric, is_space};
+use nom7::combinator::map_res;
+use nom7::sequence::delimited;
+use nom7::{Err, IResult, Needed};
use std;
use std::collections::HashMap;
is_alphanumeric(b) || is_token_char(b) || b"\"#$&(),/;:<=>?@[]{}()^|~\\\t\n\r ".contains(&b)
}
-named!(pub sip_parse_request<&[u8], Request>,
- do_parse!(
- method: parse_method >> char!(' ') >>
- path: parse_request_uri >> char!(' ') >>
- version: parse_version >> crlf >>
- headers: parse_headers >>
- crlf >>
- (Request { method: method.into(), path: path.into(), version: version.into(), headers: headers})
- )
-);
-
-named!(pub sip_parse_response<&[u8], Response>,
- do_parse!(
- version: parse_version >> char!(' ') >>
- code: parse_code >> char!(' ') >>
- reason: parse_reason >> crlf >>
- (Response { version: version.into(), code: code.into(), reason: reason.into() })
- )
-);
-
-named!(#[inline], parse_method<&[u8], &str>,
- map_res!(take_while!(is_method_char), std::str::from_utf8)
-);
-
-named!(#[inline], parse_request_uri<&[u8], &str>,
- map_res!(take_while1!(is_request_uri_char), std::str::from_utf8)
-);
-
-named!(#[inline], parse_version<&[u8], &str>,
- map_res!(take_while1!(is_version_char), std::str::from_utf8)
-);
-
-named!(#[inline], parse_code<&[u8], &str>,
- map_res!(take!(3), std::str::from_utf8)
-);
-
-named!(#[inline], parse_reason<&[u8], &str>,
- map_res!(take_while!(is_reason_phrase), std::str::from_utf8)
-);
-
-named!(#[inline], header_name<&[u8], &str>,
- map_res!(take_while!(is_header_name), std::str::from_utf8)
-);
-
-named!(#[inline], header_value<&[u8], &str>,
- map_res!(parse_header_value, std::str::from_utf8)
-);
-
-named!(
- hcolon<char>,
- delimited!(take_while!(is_space), char!(':'), take_while!(is_space))
-);
-
-named!(
- message_header<Header>,
- do_parse!(
- n: header_name
- >> hcolon
- >> v: header_value
- >> crlf
- >> (Header {
- name: String::from(n),
- value: String::from(v)
- })
- )
-);
-
-named!(pub sip_take_line<&[u8], Option<String> >,
- do_parse!(
- line: map_res!(take_while1!(is_reason_phrase), std::str::from_utf8) >>
- (Some(line.into()))
- )
-);
+pub fn sip_parse_request(i: &[u8]) -> IResult<&[u8], Request> {
+ let (i, method) = parse_method(i)?;
+ let (i, _) = char(' ')(i)?;
+ let (i, path) = parse_request_uri(i)?;
+ let (i, _) = char(' ')(i)?;
+ let (i, version) = parse_version(i)?;
+ let (i, _) = crlf(i)?;
+ let (i, headers) = parse_headers(i)?;
+ let (i, _) = crlf(i)?;
+ Ok((
+ i,
+ Request {
+ method: method.into(),
+ path: path.into(),
+ version: version.into(),
+ headers,
+ },
+ ))
+}
+
+pub fn sip_parse_response(i: &[u8]) -> IResult<&[u8], Response> {
+ let (i, version) = parse_version(i)?;
+ let (i, _) = char(' ')(i)?;
+ let (i, code) = parse_code(i)?;
+ let (i, _) = char(' ')(i)?;
+ let (i, reason) = parse_reason(i)?;
+ let (i, _) = crlf(i)?;
+ Ok((
+ i,
+ Response {
+ version: version.into(),
+ code: code.into(),
+ reason: reason.into(),
+ },
+ ))
+}
+
+#[inline]
+fn parse_method(i: &[u8]) -> IResult<&[u8], &str> {
+ map_res(take_while(is_method_char), std::str::from_utf8)(i)
+}
+
+#[inline]
+fn parse_request_uri(i: &[u8]) -> IResult<&[u8], &str> {
+ map_res(take_while1(is_request_uri_char), std::str::from_utf8)(i)
+}
+
+#[inline]
+fn parse_version(i: &[u8]) -> IResult<&[u8], &str> {
+ map_res(take_while1(is_version_char), std::str::from_utf8)(i)
+}
+
+#[inline]
+fn parse_code(i: &[u8]) -> IResult<&[u8], &str> {
+ map_res(take(3_usize), std::str::from_utf8)(i)
+}
+
+#[inline]
+fn parse_reason(i: &[u8]) -> IResult<&[u8], &str> {
+ map_res(take_while(is_reason_phrase), std::str::from_utf8)(i)
+}
+
+#[inline]
+fn header_name(i: &[u8]) -> IResult<&[u8], &str> {
+ map_res(take_while(is_header_name), std::str::from_utf8)(i)
+}
+
+#[inline]
+fn header_value(i: &[u8]) -> IResult<&[u8], &str> {
+ map_res(parse_header_value, std::str::from_utf8)(i)
+}
+
+#[inline]
+fn hcolon(i: &[u8]) -> IResult<&[u8], char> {
+ delimited(take_while(is_space), char(':'), take_while(is_space))(i)
+}
+
+fn message_header(i: &[u8]) -> IResult<&[u8], Header> {
+ let (i, n) = header_name(i)?;
+ let (i, _) = hcolon(i)?;
+ let (i, v) = header_value(i)?;
+ let (i, _) = crlf(i)?;
+ Ok((
+ i,
+ Header {
+ name: String::from(n),
+ value: String::from(v),
+ },
+ ))
+}
+
+pub fn sip_take_line(i: &[u8]) -> IResult<&[u8], Option<String>> {
+ let (i, line) = map_res(take_while1(is_reason_phrase), std::str::from_utf8)(i)?;
+ Ok((i, Some(line.into())))
+}
pub fn parse_headers(mut input: &[u8]) -> IResult<&[u8], HashMap<String, String>> {
let mut headers_map: HashMap<String, String> = HashMap::new();
loop {
- match crlf(input) as IResult<&[u8],_> {
+ match crlf(input) as IResult<&[u8], _> {
Ok((_, _)) => {
break;
}
b'\n' => {
idx += 1;
if idx >= buf.len() {
- return Err(Err::Incomplete(Needed::Size(1)));
+ return Err(Err::Incomplete(Needed::new(1)));
}
match buf[idx] {
b' ' | b'\t' => {
b => {
trail_spaces = 0;
if !is_header_value(b) {
- return Err(Err::Incomplete(Needed::Size(1)));
+ return Err(Err::Incomplete(Needed::new(1)));
}
end_pos = idx + 1;
}
\r\n"
.as_bytes();
- match sip_parse_request(buf) {
- Ok((_, req)) => {
- assert_eq!(req.method, "REGISTER");
- assert_eq!(req.path, "sip:sip.cybercity.dk");
- assert_eq!(req.version, "SIP/2.0");
- assert_eq!(req.headers["Content-Length"], "0");
- }
- _ => {
- assert!(false);
- }
- }
+ let (_, req) = sip_parse_request(buf).expect("parsing failed");
+ assert_eq!(req.method, "REGISTER");
+ assert_eq!(req.path, "sip:sip.cybercity.dk");
+ assert_eq!(req.version, "SIP/2.0");
+ assert_eq!(req.headers["Content-Length"], "0");
}
#[test]