env_logger::init().unwrap();
let message =
- decode_sip_message("MESSAGE sip:test.com \
- SIP/2.0\r\nAccept:text/plain\r\nAccept-Encoding:\
- *\r\nAccept-Language:en-gb\r\nAlert-Info:<http://www.example.\
- com/sounds/moo.wav>\r\nAllow:MESSAGE\r\nAuthentication-Info:\
- qop=auth\r\nAuthorization:Digest \
- username=\"Alice\"\r\nCall-ID:\
- f81d4fae-7dec-11d0-a765-00a0c91e6bf6@foo.bar.com\r\nCall-Info:\
+ decode_sip_message("MESSAGE sip:test.com SIP/2.0\r\nAccept: \
+ text/plain\r\nAccept-Encoding: *\r\nAccept-Language: \
+ en-gb\r\nAlert-Info: \
+ <http://www.example.com/sounds/moo.wav>\r\nAllow: \
+ MESSAGE\r\nAuthentication-Info: qop=auth\r\nAuthorization:Digest \
+ username=\"Alice\"\r\nCall-ID: \
+ f81d4fae-7dec-11d0-a765-00a0c91e6bf6@foo.bar.com\r\nCall-Info: \
<http://wwww.example.com/alice/photo.jpg>;\
- purpose=icon\r\nContact:*\r\nContent-Disposition:\
- session\r\nContent-Encoding:gzip\r\nContent-Language:\
- en-gb\r\nContent-Length:0\r\nContent-Type:text/plain\r\nCSeq:1 \
- MESSAGE\r\nDate:Sat, 13 Nov 2010 23:29:00 \
- GMT\r\nError-Info:<sip:not-in-service-recording@atlanta.\
- com>\r\nExpires:30\r\nFrom:sip:+12125551212@server.phone2net.com;\
- tag=887s\r\nIn-Reply-To:70710@saturn.bell-tel.com,17320@saturn.\
- bell-tel.com\r\nMax-Forwards:32\r\nMIME-Version:2.\
- 0\r\nMin-Expires:30\r\nOrganization:Foobar\r\nPriority:\
- normal\r\nProxy-Authenticate:Digest \
- realm=\"atlanta.com\"\r\nProxy-Authorization:Digest \
- username=\"Bob\"\r\nProxy-Require:foo\r\nRecord-Route:<sip:\
- server10.biloxi.com;lr>\r\nReply-To:<sip:bob@biloxi.\
- com>\r\nRequire:baz\r\nRetry-After:18000;duration=3600\r\nRoute:\
- <sip:bigbox3.site3.atlanta.com;lr>\r\nServer:rust-sip \
- tokio\r\nSubject:Foobaz\r\nSupported:rec\r\nTimestamp:1 \
- 2\r\nTo:<sip:operator@cs.columbia.edu>;tag=287447\r\nUnsupported:\
- 100rel\r\nUser-Agent:rust-sip\r\nVia:SIP/2.0/UDP \
- pc33.atlanta.com;branch=z9hG4bK776asdhds\r\nWarning:370 devnull \
- \"Failure\"\r\nWWW-Authenticate:Digest \
- realm=\"biloxi.com\"\r\nX-Extension:test\r\n\r\n");
+ purpose=icon\r\nContact: *\r\nContent-Disposition: \
+ session\r\nContent-Encoding: gzip\r\nContent-Language: \
+ en-gb\r\nContent-Length: 0\r\nContent-Type: text/plain\r\nCSeq: \
+ 1 MESSAGE\r\nDate: Sat, 13 Nov 2010 23:29:00 GMT\r\nError-Info: \
+ <sip:not-in-service-recording@atlanta.com>\r\nExpires: \
+ 30\r\nFrom: sip:+12125551212@server.phone2net.com; \
+ tag=887s\r\nIn-Reply-To: \
+ 70710@saturn.bell-tel.com,17320@saturn.bell-tel.\
+ com\r\nMax-Forwards: 32\r\nMIME-Version:2.0\r\nMin-Expires: \
+ 30\r\nOrganization:Foobar\r\nPriority: \
+ normal\r\nProxy-Authenticate: Digest \
+ realm=\"atlanta.com\"\r\nProxy-Authorization: Digest \
+ username=\"Bob\"\r\nProxy-Require: foo\r\nRecord-Route: \
+ <sip:server10.biloxi.com;lr>\r\nReply-To: \
+ <sip:bob@biloxi.com>\r\nRequire: \
+ baz\r\nRetry-After:18000;duration=3600\r\nRoute: \
+ <sip:bigbox3.site3.atlanta.com;lr>\r\nServer: rust-sip \
+ tokio\r\nSubject: Foobaz\r\nSupported: rec\r\nTimestamp: 1 \
+ 2\r\nTo: <sip:operator@cs.columbia.edu>;\
+ tag=287447\r\nUnsupported: 100rel\r\nUser-Agent: \
+ rust-sip\r\nVia: SIP/2.0/UDP \
+ pc33.atlanta.com;branch=z9hG4bK776asdhds\r\nWarning: 370 devnull \
+ \"Failure\"\r\nWWW-Authenticate: Digest \
+ realm=\"biloxi.com\"\r\nX-Extension: test\r\n\r\n");
if let Message::Request(request) = message {
assert_eq!(request.request_line.0.method, Method::MESSAGE);
/// Headers
+fn is_spacetab(c: u8) -> bool {
+ c == b' ' || c == b'\t'
+}
+
+fn is_whitespace(c: u8) -> bool {
+ is_spacetab(c)
+}
+
+named!(spacetab<u8>, take_1!(is_spacetab));
+
+named!(crlf, tag!(b"\r\n"));
+
+named!(lws<(Option<(Vec<u8>, &[u8])>, Vec<u8>)>, pair!(
+ opt!(pair!(many0!(take_1!(is_whitespace)), crlf)),
+ many1!(take_1!(is_whitespace))));
+
+named!(sws<Option<(Option<(Vec<u8>, &[u8])>, Vec<u8>)>>, opt!(lws));
+
+named!(hcolon, delimited!(
+ many0!(spacetab),
+ tag!(b":"),
+ sws));
+
// Accept Header
named!(media_main_type<MediaMainType>, alt!(
accept_param))));
named!(accept_header<Vec<AcceptRange>>, preceded!(
- tag!(b"Accept:"),
+ terminated!(tag!(b"Accept"), hcolon),
separated_nonempty_list!(
tag!(b","),
accept_range)));
accept_param))));
named!(accept_encoding_header<Vec<Encoding>>, preceded!(
- tag!(b"Accept-Encoding:"),
+ terminated!(tag!(b"Accept-Encoding"), hcolon),
separated_nonempty_list!(
tag!(b","),
encoding)));
accept_param))));
named!(accept_language_header<Vec<Language>>, preceded!(
- tag!(b"Accept-Language:"),
+ terminated!(tag!(b"Accept-Language"), hcolon),
separated_nonempty_list!(
tag!(b","),
language)));
many0!(generic_param)));
named!(alert_info_header<Vec<AlertParam>>, preceded!(
- tag!(b"Alert-Info:"),
+ terminated!(tag!(b"Alert-Info"), hcolon),
separated_nonempty_list!(
tag!(b","),
alert_param)));
named!(allow_header<Vec<Method>>, preceded!(
- tag!(b"Allow:"),
+ terminated!(tag!(b"Allow"), hcolon),
separated_nonempty_list!(
tag!(b","),
method)));
nonce_count => { |n| AuthenticationInfo::NonceCount(n) }));
named!(authentication_info_header<Vec<AuthenticationInfo>>, preceded!(
- tag!(b"Authentication-Info:"),
+ terminated!(tag!(b"Authentication-Info"), hcolon),
separated_nonempty_list!(
tag!(b","),
ainfo)));
other_response => { |(s,p)| Credentials::Other(s, p) }));
named!(authorization_header<Credentials>, preceded!(
- tag!(b"Authorization:"),
+ terminated!(tag!(b"Authorization"), hcolon),
credentials));
named!(call_id<CallId>, tuple!(
word))));
named!(call_id_header<CallId>, preceded!(
- alt!(tag!(b"Call-ID:") | tag!(b"i")),
+ terminated!(alt!(tag!(b"Call-ID") | tag!(b"i")), hcolon),
call_id));
named!(purpose<Purpose>, alt!(
info_param))));
named!(call_info_header<Vec<Info>>, preceded!(
- tag!(b"Call-Info:"),
+ terminated!(tag!(b"Call-Info"), hcolon),
separated_nonempty_list!(
tag!(","),
info)));
))));
named!(contact_header<Contact>, preceded!(
- alt!(tag!(b"Contact:") | tag!(b"m")),
+ terminated!(alt!(tag!(b"Contact") | tag!(b"m")), hcolon),
alt!(
tag!(b"*") => { |_| Contact::Star } |
separated_nonempty_list!(
generic_param => { |g| DispositionParam::Generic(g) }));
named!(content_disposition_header<(DispositionType, Vec<DispositionParam>)>, preceded!(
- tag!(b"Content-Disposition:"),
+ terminated!(tag!(b"Content-Disposition"), hcolon),
tuple!(
disp_type,
many0!(preceded!(
disp_param)))));
named!(content_encoding_header<Vec<ContentCoding>>, preceded!(
- alt!(tag!(b"Content-Encoding:") | tag!(b"e:")),
+ terminated!(alt!(tag!(b"Content-Encoding") | tag!(b"e")), hcolon),
separated_nonempty_list!(
tag!(b","),
token)));
named!(content_language_header<Vec<LanguageTag>>, preceded!(
- tag!(b"Content-Language:"),
+ terminated!(tag!(b"Content-Language"), hcolon),
separated_nonempty_list!(
tag!(b","),
language_tag)));
named!(content_length_header<u32>, preceded!(
- alt!(tag!(b"Content-Length:") | tag!(b"l:")),
+ terminated!(alt!(tag!(b"Content-Length") | tag!(b"l")), hcolon),
number));
named!(content_type_header<MediaType>, preceded!(
- alt!(tag!(b"Content-Type:") | tag!(b"c:")),
+ terminated!(alt!(tag!(b"Content-Type") | tag!(b"c")), hcolon),
media_type));
named!(cseq_header<(u32, Method)>, preceded!(
- tag!(b"CSeq:"),
+ terminated!(tag!(b"CSeq"), hcolon),
separated_pair!(
number,
tag!(" "),
terminated!(time, tag!(b" GMT"))));
named!(date_header<DateTime>, preceded!(
- tag!(b"Date:"),
+ terminated!(tag!(b"Date"), hcolon),
date_time));
named!(error_uri<ErrorUri>, tuple!(
generic_param))));
named!(error_info_header<Vec<ErrorUri>>, preceded!(
- tag!(b"Error-Info:"),
+ terminated!(tag!(b"Error-Info"), hcolon),
separated_nonempty_list!(
tag!(","),
error_uri)));
named!(expires_header<u32>, preceded!(
- tag!(b"Expires:"),
+ terminated!(tag!(b"Expires"), hcolon),
number));
named!(from_param<FromParam>, alt!(
generic_param => { |g| FromParam::Generic(g) }));
named!(from_header<From>, preceded!(
- alt!(tag!(b"From:") | tag!("f:")),
+ terminated!(alt!(tag!(b"From") | tag!("f")), hcolon),
tuple!(
target,
many0!(preceded!(
from_param)))));
named!(in_reply_to_header<Vec<CallId>>, preceded!(
- tag!(b"In-Reply-To:"),
+ terminated!(tag!(b"In-Reply-To"), hcolon),
separated_nonempty_list!(
tag!(","),
call_id)));
named!(max_forwards_header<u32>, preceded!(
- tag!(b"Max-Forwards:"),
+ terminated!(tag!(b"Max-Forwards"), hcolon),
number));
named!(mime_version_header<(u32, u32)>, preceded!(
- tag!(b"MIME-Version:"),
+ terminated!(tag!(b"MIME-Version"), hcolon),
separated_pair!(
number,
tag!(b"."),
number)));
named!(min_expires_header<u32>, preceded!(
- tag!(b"Min-Expires:"),
+ terminated!(tag!(b"Min-Expires"), hcolon),
number));
named!(organization_header<Vec<u8>>, preceded!(
- tag!(b"Organization:"),
+ terminated!(tag!(b"Organization"), hcolon),
word));
named!(priority_header<Priority>, preceded!(
- tag!(b"Priority:"),
+ terminated!(tag!(b"Priority"), hcolon),
alt!(
tag!(b"emergency") => { |_| Priority::Emergency } |
tag!(b"urgent") => { |_| Priority::Urgent } |
other_challenge => { |(s, p)| Challenge::Other(s, p) }));
named!(proxy_authenticate_header<Challenge>, preceded!(
- tag!(b"Proxy-Authenticate:"),
+ terminated!(tag!(b"Proxy-Authenticate"), hcolon),
challenge));
named!(proxy_authorization_header<Credentials>, preceded!(
- tag!(b"Proxy-Authorization:"),
+ terminated!(tag!(b"Proxy-Authorization"), hcolon),
credentials));
named!(proxy_require_header<Vec<OptionTag>>, preceded!(
- tag!(b"Proxy-Require:"),
+ terminated!(tag!(b"Proxy-Require"), hcolon),
separated_nonempty_list!(
tag!(b","),
token)));
generic_param))));
named!(record_route_header<Vec<Route>>, preceded!(
- tag!(b"Record-Route:"),
+ terminated!(tag!(b"Record-Route"), hcolon),
separated_nonempty_list!(
tag!(b","),
route)));
generic_param))));
named!(reply_to_header<Vec<ReplyTo>>, preceded!(
- tag!(b"Reply-To:"),
+ terminated!(tag!(b"Reply-To"), hcolon),
separated_nonempty_list!(
tag!(b","),
reply_to)));
named!(require_header<Vec<OptionTag>>, preceded!(
- tag!(b"Require:"),
+ terminated!(tag!(b"Require"), hcolon),
separated_nonempty_list!(
tag!(b","),
token)));
generic_param => { |g| RetryAfterParam::Generic(g) }));
named!(retry_after_header<RetryAfter>, preceded!(
- tag!(b"Retry-After:"),
+ terminated!(tag!(b"Retry-After"), hcolon),
pair!(
number,
many0!(preceded!(
)))));
named!(route_header<Vec<Route>>, preceded!(
- tag!(b"Route:"),
+ terminated!(tag!(b"Route"), hcolon),
separated_nonempty_list!(
tag!(b","),
route)));
token))));
named!(server_header<Vec<Server>>, preceded!(
- tag!(b"Server:"),
+ terminated!(tag!(b"Server"), hcolon),
separated_nonempty_list!(
tag!(b" "),
server)));
named!(subject_header<Vec<u8>>, preceded!(
- alt!(tag!(b"Subject:") | tag!(b"s")),
+ terminated!(alt!(tag!(b"Subject") | tag!(b"s")), hcolon),
word));
named!(supported_header<Vec<OptionTag>>, preceded!(
- alt!(tag!(b"Supported:") | tag!(b"k")),
+ terminated!(alt!(tag!(b"Supported") | tag!(b"k")), hcolon),
separated_nonempty_list!(
tag!(b","),
token)));
use self::float as delay;
named!(timestamp_header<Vec<f32>>, preceded!(
- tag!(b"Timestamp:"),
+ terminated!(tag!(b"Timestamp"), hcolon),
separated_nonempty_list!(
tag!(b" "),
delay)));
generic_param => { |g| ToParam::Generic(g) }));
named!(to_header<To>, preceded!(
- alt!(tag!(b"To:") | tag!("t:")),
+ terminated!(alt!(tag!(b"To") | tag!("t")), hcolon),
tuple!(
target,
many0!(preceded!(
to_param)))));
named!(unsupported_header<Vec<OptionTag>>, preceded!(
- tag!(b"Unsupported:"),
+ terminated!(tag!(b"Unsupported"), hcolon),
separated_nonempty_list!(
tag!(b","),
token)));
named!(user_agent_header<Vec<Server>>, preceded!(
- tag!(b"User-Agent:"),
+ terminated!(tag!(b"User-Agent"), hcolon),
separated_nonempty_list!(
tag!(b" "),
server)));
via_param))));
named!(via_header<Vec<Via>>, preceded!(
- alt!(tag!(b"Via:") | tag!("v:")),
+ terminated!(alt!(tag!(b"Via") | tag!(b"v")), hcolon),
separated_nonempty_list!(
tag!(b","),
via)));
quoted_string));
named!(warning_header<Vec<Warning>>, preceded!(
- tag!(b"Warning:"),
+ terminated!(tag!(b"Warning"), hcolon),
separated_nonempty_list!(
tag!(b","),
warning)));
named!(www_authenticate_header<Challenge>, preceded!(
- tag!(b"WWW-Authenticate:"),
+ terminated!(tag!(b"WWW-Authenticate"), hcolon),
challenge));
named!(extension_header<(Vec<u8>, Vec<u8>)>, separated_pair!(
token,
- tag!(":"),
+ hcolon,
word));
named!(pub header<Header>, alt!(