Full HCOLON support
authorRichard Whitehouse <github@richardwhiuk.com>
Sun, 19 Nov 2017 23:38:55 +0000 (23:38 +0000)
committerRichard Whitehouse <github@richardwhiuk.com>
Sun, 19 Nov 2017 23:38:55 +0000 (23:38 +0000)
src/codec.rs
src/parser.rs

index 8ade42c150912b62bca33a947ce7433a31b2ea85..d72bd89aa0daca844784dd20633d51eba094f183 100644 (file)
@@ -480,35 +480,38 @@ mod tests {
         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);
index 06fb0d6877aa00a0adb3410a0d59fc6c345b6ee7..81a9131580a48c679a59e32575e2a4bd9d717773 100644 (file)
@@ -498,6 +498,29 @@ named!(pub top_line<TopLine>, alt!(
 
 /// 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!(
@@ -581,7 +604,7 @@ named!(accept_range<AcceptRange>, tuple!(
                accept_param))));
 
 named!(accept_header<Vec<AcceptRange>>, preceded!(
-       tag!(b"Accept:"),
+       terminated!(tag!(b"Accept"), hcolon),
        separated_nonempty_list!(
                tag!(b","),
                accept_range)));
@@ -598,7 +621,7 @@ named!(encoding<Encoding>, tuple!(
                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)));
@@ -620,7 +643,7 @@ named!(language<Language>, tuple!(
                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)));
@@ -634,13 +657,13 @@ named!(alert_param<AlertParam>, tuple!(
        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)));
@@ -685,7 +708,7 @@ named!(ainfo<AuthenticationInfo>, alt!(
        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)));
@@ -754,7 +777,7 @@ named!(credentials<Credentials>, alt!(
        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!(
@@ -764,7 +787,7 @@ 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!(
@@ -790,7 +813,7 @@ named!(info<Info>, tuple!(
                info_param))));
 
 named!(call_info_header<Vec<Info>>, preceded!(
-       tag!(b"Call-Info:"),
+       terminated!(tag!(b"Call-Info"), hcolon),
        separated_nonempty_list!(
                tag!(","),
                info)));
@@ -830,7 +853,7 @@ named!(contact_target<(Target, Vec<ContactParam>)>, tuple!(
        ))));
 
 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!(
@@ -855,7 +878,7 @@ named!(disp_param<DispositionParam>, alt!(
        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!(
@@ -863,27 +886,27 @@ named!(content_disposition_header<(DispositionType, Vec<DispositionParam>)>, pre
                        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!(" "),
@@ -928,7 +951,7 @@ named!(date_time<DateTime>, tuple!(
        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!(
@@ -942,13 +965,13 @@ 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!(
@@ -956,7 +979,7 @@ 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!(
@@ -964,32 +987,32 @@ named!(from_header<From>, 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 } |
@@ -1038,15 +1061,15 @@ named!(challenge<Challenge>, alt!(
        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)));
@@ -1058,7 +1081,7 @@ named!(route<Route>, pair!(
                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)));
@@ -1070,13 +1093,13 @@ named!(reply_to<ReplyTo>, pair!(
                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)));
@@ -1086,7 +1109,7 @@ named!(retry_after_param<RetryAfterParam>, alt!(
        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!(
@@ -1095,7 +1118,7 @@ named!(retry_after_header<RetryAfter>, preceded!(
                )))));
 
 named!(route_header<Vec<Route>>, preceded!(
-       tag!(b"Route:"),
+       terminated!(tag!(b"Route"), hcolon),
        separated_nonempty_list!(
                tag!(b","),
                route)));
@@ -1107,17 +1130,17 @@ named!(server<Server>, pair!(
                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)));
@@ -1125,7 +1148,7 @@ named!(supported_header<Vec<OptionTag>>, preceded!(
 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)));
@@ -1135,7 +1158,7 @@ named!(to_param<ToParam>, alt!(
        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!(
@@ -1143,13 +1166,13 @@ named!(to_header<To>, 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)));
@@ -1194,7 +1217,7 @@ named!(via<Via>, tuple!(
                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)));
@@ -1209,18 +1232,18 @@ named!(warning<Warning>, tuple!(
        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!(