rust/sip: convert parser to nom7 functions

pull/6581/head
Pierre Chifflier 4 years ago committed by Victor Julien
parent 1046a7d1a3
commit d27125d77a

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

@ -17,12 +17,11 @@
// written by Giuseppe Longo <giuseppe@glongo.it> // written by Giuseppe Longo <giuseppe@glongo.it>
extern crate nom;
use crate::applayer::{self, *}; use crate::applayer::{self, *};
use crate::core; use crate::core;
use crate::core::{sc_detect_engine_state_free, AppProto, Flow, ALPROTO_UNKNOWN}; use crate::core::{sc_detect_engine_state_free, AppProto, Flow, ALPROTO_UNKNOWN};
use crate::sip::parser::*; use crate::sip::parser::*;
use nom7::Err;
use std; use std;
use std::ffi::CString; use std::ffi::CString;
@ -98,7 +97,7 @@ impl SIPState {
self.transactions.push(tx); self.transactions.push(tx);
return true; return true;
} }
Err(nom::Err::Incomplete(_)) => { Err(Err::Incomplete(_)) => {
self.set_event(SIPEvent::IncompleteData); self.set_event(SIPEvent::IncompleteData);
return false; return false;
} }
@ -120,7 +119,7 @@ impl SIPState {
self.transactions.push(tx); self.transactions.push(tx);
return true; return true;
} }
Err(nom::Err::Incomplete(_)) => { Err(Err::Incomplete(_)) => {
self.set_event(SIPEvent::IncompleteData); self.set_event(SIPEvent::IncompleteData);
return false; return false;
} }
@ -135,7 +134,7 @@ impl SIPState {
impl SIPTransaction { impl SIPTransaction {
pub fn new(id: u64) -> SIPTransaction { pub fn new(id: u64) -> SIPTransaction {
SIPTransaction { SIPTransaction {
id: id, id,
de_state: None, de_state: None,
request: None, request: None,
response: None, response: None,

Loading…
Cancel
Save