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>
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;
@ -84,84 +86,106 @@ fn is_header_value(b: u8) -> bool {
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;
}
@ -186,7 +210,7 @@ fn parse_header_value(buf: &[u8]) -> IResult<&[u8], &[u8]> {
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' => {
@ -205,7 +229,7 @@ fn parse_header_value(buf: &[u8]) -> IResult<&[u8], &[u8]> {
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;
}
@ -251,17 +275,11 @@ mod tests {
\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]

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

Loading…
Cancel
Save