Split up parser
authorRichard Whitehouse <github@richardwhiuk.com>
Mon, 20 Nov 2017 00:08:04 +0000 (00:08 +0000)
committerRichard Whitehouse <github@richardwhiuk.com>
Mon, 20 Nov 2017 00:08:04 +0000 (00:08 +0000)
src/parser.rs [deleted file]
src/parser/header.rs [new file with mode: 0644]
src/parser/mod.rs [new file with mode: 0644]
src/parser/top_line.rs [new file with mode: 0644]

diff --git a/src/parser.rs b/src/parser.rs
deleted file mode 100644 (file)
index 81a9131..0000000
+++ /dev/null
@@ -1,1297 +0,0 @@
-use nom;
-use std;
-
-use nom::alpha as alphas;
-use nom::digit as digits;
-use nom::alphanumeric as alphanumerics;
-
-use nom::IResult;
-use nom::ErrorKind::Custom;
-
-use types::{PathSegment, HostPort, Host, Hostname, UriParameter, UriHeader, UriHeaders, SipUri,
-            AbsoluteUri, Uri, HierarchicalPath, Authority, UriPath, UserInfo, AbsolutePath,
-            Scheme, Method, Transport, UserParam, Version, RequestLine, StatusLine, TopLine,
-            Header, MediaMainType, MediaType, MediaFullType, MediaParameter, MediaRange,
-            GenericParam, AcceptParam, AcceptRange, Coding, Encoding, LanguageTag, LanguageRange,
-            Language, AlertParam, Qop, AuthenticationInfo, AuthParam, Algorithm, DigestResponse,
-            Credentials, CallId, Purpose, InfoParam, Info, NameAddr, ContactParam, Target,
-            Contact, DispositionType, Handling, DispositionParam, ContentCoding, Day, Month, Date,
-            Time, DateTime, ErrorUri, FromParam, From, Priority, Domain, DigestChallenge,
-            Challenge, OptionTag, Route, ReplyTo, RetryAfterParam, RetryAfter, Server, ToParam,
-            To, Protocol, SentProtocol, Received, ViaParam, Via, WarningAgent, Warning};
-
-pub fn float(input: &[u8]) -> IResult<&[u8], f32> {
-    flat_map!(input,
-              recognize!(tuple!(opt!(alt!(tag!("+") | tag!("-"))),
-                                alt!(delimited!(digits, tag!("."), opt!(digits)) |
-                                     delimited!(opt!(digits), tag!("."), digits) |
-                                     digits),
-                                opt!(complete!(tuple!(alt!(tag!("e") | tag!("E")),
-                                                      opt!(alt!(tag!("+") | tag!("-"))),
-                                                      digit))))),
-              parse_to!(f32))
-}
-
-fn is_mark(c: u8) -> bool {
-    c == b'-' || c == b'_' || c == b'.' || c == b'!' || c == b'~' || c == b'*' || c == b'\'' ||
-    c == b'(' || c == b')'
-}
-
-fn is_unreserved(c: u8) -> bool {
-    nom::is_alphanumeric(c) || is_mark(c)
-}
-
-fn is_reserved(c: u8) -> bool {
-    c == b';' || c == b'/' || c == b'?' || c == b':' || c == b'@' || c == b'&' || c == b'=' ||
-    c == b'+' || c == b'$' || c == b','
-}
-
-fn is_user_unreserved(c: u8) -> bool {
-    is_unreserved(c) || c == b'&' || c == b'=' || c == b'+' || c == b'$' || c == b',' ||
-    c == b';' || c == b'?' || c == b'/'
-}
-
-fn is_password_unreserved(c: u8) -> bool {
-    is_unreserved(c) || c == b'=' || c == b'+' || c == b'$' || c == b','
-}
-
-fn is_domain_label(c: u8) -> bool {
-    nom::is_alphanumeric(c) || c == b'-'
-}
-
-macro_rules! take_1 (
-  ($input:expr, $submac:ident!( $($args:tt)* )) => (
-    {
-      use nom::Slice;
-      let input = $input;
-
-      match input.iter().next() {
-        Some(c) => {
-          if $submac!(*c, $($args)*) {
-            let res:nom::IResult<&[u8],u8> = nom::IResult::Done(input.slice(1..), *c);
-            res
-          }
-          else
-          {
-            nom::IResult::Error(error_position!(nom::ErrorKind::TakeWhile1, input))
-          }
-        },
-        None    => {
-          nom::IResult::Incomplete(nom::Needed::Size(1))
-        }
-      }
-    }
-  );
-  ($input:expr, $f:expr) => (
-    take_1!($input, call!($f));
-  );
-);
-
-fn is_token(c: u8) -> bool {
-    nom::is_alphanumeric(c) || c == b'-' || c == b'.' || c == b'!' || c == b'%' ||
-    c == b'*' || c == b'_' || c == b'+' || c == b'`' || c == b'\'' || c == b'~'
-}
-
-fn is_word(c: u8) -> bool {
-    is_token(c) || c == b'(' || c == b')' || c == b'<' || c == b'>' || c == b':' ||
-    c == b'\\' || c == b'"' || c == b'/' || c == b'[' || c == b']' ||
-    c == b'?' || c == b'{' || c == b'}'
-}
-
-fn is_lhex_digit(c: u8) -> bool {
-    nom::is_digit(c) || (c >= b'a' && c <= b'f')
-}
-
-named!(token<Vec<u8>>, many1!(take_1!(is_token)));
-named!(word<Vec<u8>>, many1!(take_1!(is_word)));
-
-named!(method<Method>, alt!(
-// RFC 3261
-    tag!("INVITE") => { |_|  Method::INVITE } |
-    tag!("ACK") => { |_|  Method::ACK } |
-    tag!("OPTIONS") => { |_|  Method::OPTIONS } |
-    tag!("BYE") => { |_|  Method::BYE } |
-    tag!("CANCEL") => { |_|  Method::CANCEL } |
-    tag!("REGISTER") => { |_|  Method::REGISTER } |
-// Extensions
-    tag!("MESSAGE") => { |_|  Method::MESSAGE } |
-    tag!("REFER") => { |_|  Method::REFER } |
-    tag!("SUBSCRIBE") => { |_|  Method::SUBSCRIBE } |
-    tag!("NOTIFY") => { |_|  Method::NOTIFY } |
-    token  => { |method| Method::Extension(method) }
-));
-
-named!(alpha<&[u8], u8>, take_1!(nom::is_alphabetic));
-named!(alphanumeric<&[u8], u8>, take_1!(nom::is_alphanumeric));
-named!(digit<&[u8], u8>, take_1!(nom::is_digit));
-named!(hex<&[u8], u8>, take_1!(nom::is_hex_digit));
-named!(lhex<&[u8], u8>, take_1!(is_lhex_digit));
-
-fn escaped(input: &[u8]) -> IResult<&[u8], u8> {
-    let result = preceded!(input, tag!(b"%"), pair!(hex, hex));
-
-    match result {
-        IResult::Done(left, (a, b)) => {
-            let value: u8 = ((a - (b'0' as u8)) << 4) + (b - b'0');
-            IResult::Done(left, value)
-        }
-        IResult::Incomplete(a) => IResult::Incomplete(a),
-        IResult::Error(a) => IResult::Error(a),
-    }
-}
-
-named!(user_unreserved<&[u8], u8>, take_1!(is_user_unreserved));
-named!(password_unreserved<&[u8], u8>, take_1!(is_password_unreserved));
-
-// The BNF splits unreserved and user unreserved, but that's just a waste
-named!(user<&[u8], Vec<u8>>, many1!(alt!(
-    user_unreserved |
-    escaped)));
-
-named!(password<&[u8], Vec<u8>>, many1!(alt!(
-    password_unreserved |
-    escaped)));
-
-named!(userinfo<&[u8], (Vec<u8>, Option<Vec<u8>>)>, terminated!(
-        pair!(
-        user,
-        opt!(preceded!(tag!(b":"), password))),
-    tag!(b"@")));
-
-named!(domain_label<&[u8], Vec<u8>>, alt!(
-    alphanumerics => { |a : &[u8]| a.to_vec() } |
-    tuple!(
-        alphanumeric,
-        take_while1!(is_domain_label),
-        alphanumeric) => { |(a, b, c) : (u8, &[u8], u8)| {
-               let mut v = Vec::with_capacity(b.len() + 2);
-               v.push(a);
-               v.extend_from_slice(b);
-               v.push(c);
-               v
-       }}));
-
-named!(top_label<&[u8], Vec<u8>>, alt!(
-    alphas => { |a : &[u8]| a.to_vec() } |
-    tuple!(
-        alpha,
-        take_while1!(is_domain_label))  => { |(a, b) : (u8, &[u8])| {
-               let mut v = Vec::with_capacity(b.len() + 2);
-               v.push(a);
-               v.extend_from_slice(b);
-               v
-        }}));
-
-named!(hostname<&[u8], Hostname>, tuple!(
-    many0!(terminated!(domain_label, tag!(b"."))),
-    terminated!(top_label, opt!(tag!(b".")))));
-
-fn number<O>(input: &[u8]) -> IResult<&[u8], O>
-    where O: std::str::FromStr
-{
-    match digits(input) {
-        IResult::Done(left, num_str) => {
-            if let Ok(num_utf8) = std::str::from_utf8(num_str) {
-                if let Ok(num_i) = num_utf8.parse::<O>() {
-                    IResult::Done(left, num_i)
-                } else {
-                    IResult::Error(Custom(1))
-                }
-            } else {
-                IResult::Error(Custom(2))
-            }
-        }
-        IResult::Error(e) => IResult::Error(e),
-        IResult::Incomplete(i) => IResult::Incomplete(i),
-    }
-}
-
-named!(ipv4_address<&[u8], (u8, u8, u8, u8)>, tuple!(
-    number,
-    preceded!(tag!(b"."), number),
-    preceded!(tag!(b"."), number),
-    preceded!(tag!(b"."), number)));
-
-fn is_ipv6_char(c: u8) -> bool {
-    nom::is_hex_digit(c) || c == b':'
-}
-
-named!(ipv6_address<&[u8], Vec<u8>>, delimited!(
-    tag!(b"["),
-    many1!(take_1!(is_ipv6_char)),
-    tag!(b"]")));
-
-named!(host<Host>, alt!(
-    hostname => { |h| Host::Hostname(h) } |
-    ipv4_address => { |(a, b, c, d)| Host::Ipv4Address(a,b,c,d) } |
-    ipv6_address => { |i| Host::Ipv6Address(i) }
-));
-
-named!(hostport<&[u8], HostPort>, tuple!(
-    host,
-    opt!(preceded!(tag!(":"), number))));
-
-named!(transport_param<Transport>, alt!(
-    tag!("tcp") => { |_| Transport::Tcp } |
-    tag!("udp") => { |_| Transport::Udp } |
-    tag!("sctp") => { |_| Transport::Sctp } |
-    tag!("tls") => { |_| Transport::Tls } |
-    token => { |token| Transport::Other(token) }
-));
-
-named!(user_param<UserParam>, alt!(
-    tag!("phone") => { |_| UserParam::Phone } |
-    tag!("ip") => { |_| UserParam::Ip } |
-    token => { |token| UserParam::Other(token) }));
-
-fn is_param_unreserved(c: u8) -> bool {
-    is_unreserved(c) || c == b'[' || c == b']' || c == b'/' || c == b':' || c == b'&' ||
-    c == b'+' || c == b'$'
-}
-
-named!(param<&[u8], Vec<u8>>, many1!(alt!(
-    take_1!(is_param_unreserved) |
-    escaped)));
-
-named!(uri_parameter<UriParameter>, alt!(
-    preceded!(tag!("transport="), transport_param) => {
-       |transport| UriParameter::Transport(transport)
-    } |
-    preceded!(tag!("user="), user_param) => { |user| UriParameter::User(user) } |
-    preceded!(tag!("method="), method) => { |method| UriParameter::Method(method) } |
-    preceded!(tag!(b"ttl="), number) => { |ttl| UriParameter::Ttl(ttl) } |
-    preceded!(tag!("maddr="), recognize!(host)) => {
-        |host : &[u8]| UriParameter::Maddr(host.to_vec())
-    } |
-    tag!("lr") => { |ttl| UriParameter::Lr } |
-    pair!(param, opt!(preceded!(tag!(b"="), param))) => {
-        |(key, value)|
-        UriParameter::Other {
-            key: key,
-            value: value
-        }
-    }
-));
-
-named!(uri_parameters<&[u8], Vec<UriParameter>>, many0!(
-    preceded!(char!(';'), uri_parameter)));
-
-fn is_header_unreserved(c: u8) -> bool {
-    is_unreserved(c) || c == b'[' || c == b']' || c == b'/' || c == b'?' || c == b':' ||
-    c == b'+' || c == b'$'
-}
-
-named!(hname<&[u8], Vec<u8>>, many1!(alt!(
-    take_1!(is_header_unreserved) |
-    escaped)));
-
-named!(hvalue<&[u8], Vec<u8>>, many1!(alt!(
-    take_1!(is_header_unreserved) |
-    escaped)));
-
-named!(uri_header<&[u8], UriHeader>, separated_pair!(
-    hname,
-    tag!(b"="),
-    hvalue));
-
-named!(uri_headers<&[u8], UriHeaders>, preceded!(
-    char!('?'),
-    separated_nonempty_list!(
-       tag!(b"&"),
-        uri_header)));
-
-type _SipUri = (Option<UserInfo>, HostPort, Vec<UriParameter>, Option<UriHeaders>);
-
-named!(sip_uri<&[u8], _SipUri>, preceded!(
-    tag!("sip:"),
-    tuple!(
-        opt!(userinfo),
-        hostport,
-        uri_parameters,
-        opt!(uri_headers)
-        )));
-
-named!(sips_uri<&[u8], _SipUri>, preceded!(
-    tag!("sips:"),
-    tuple!(
-        opt!(userinfo),
-        hostport,
-        uri_parameters,
-        opt!(uri_headers)
-        )));
-
-type _SipUriNp = (Option<UserInfo>, HostPort);
-
-named!(sip_uri_np<&[u8], _SipUriNp>, preceded!(
-    tag!("sip:"),
-    tuple!(
-        opt!(userinfo),
-        hostport
-        )));
-
-named!(sips_uri_np<&[u8], _SipUriNp>, preceded!(
-    tag!("sips:"),
-    tuple!(
-        opt!(userinfo),
-        hostport
-        )));
-
-fn is_scheme_unreserved(c: u8) -> bool {
-    nom::is_alphanumeric(c) || c == b'+' || c == b'-' || c == b'.'
-}
-
-named!(scheme<&[u8], Scheme>, tuple!(
-    alpha,
-    many0!(take_1!(is_scheme_unreserved))));
-
-fn is_path_char(c: u8) -> bool {
-    is_unreserved(c) || c == b':' || c == b'@' || c == b'&' || c == b'=' || c == b'+' ||
-    c == b'$' || c == b','
-}
-
-named!(path_param<&[u8], Vec<u8>>, many0!(alt!(
-    escaped |
-    take_1!(is_path_char))));
-
-named!(path_segment<&[u8], PathSegment>, pair!(
-    many0!(take_1!(is_path_char)),
-    opt!(preceded!(tag!(b";"), path_param))));
-
-named!(srvr<&[u8], (Option<UserInfo>, HostPort)>, tuple!(
-        opt!(userinfo),
-        hostport));
-
-fn is_reg_name_char(c: u8) -> bool {
-    is_unreserved(c) || c == b':' || c == b';' || c == b'$' || c == b'@' || c == b'&' ||
-    c == b'=' || c == b'+' || c == b','
-}
-
-named!(reg_name<&[u8], Vec<u8>>, many1!(alt!(
-    take_1!(is_reg_name_char) |
-    escaped)));
-
-named!(authority<&[u8], Authority>, alt!(
-    srvr => { |(u, h)| Authority::Server { userinfo: u, hostport: h } } |
-    reg_name => { |n| Authority::Name(n) } ));
-
-named!(abs_path<&[u8], AbsolutePath>, many1!(
-    preceded!(char!('/'), path_segment)));
-
-named!(net_path<&[u8], (Authority, Option<AbsolutePath>)>, preceded!(tag!("//"), pair!(
-    authority,
-    opt!(abs_path))));
-
-named!(query<&[u8], Vec<u8>>, many0!(uric));
-
-named!(hier_part<&[u8], (HierarchicalPath, Option<Vec<u8>>)>, tuple!(
-    alt!(
-        net_path => { |(a, p)| HierarchicalPath::Network{ authority: a, path: p } } |
-        abs_path => { |p| HierarchicalPath::Absolute(p) }
-    ),
-    opt!(preceded!(char!('?'), query))));
-
-fn is_uri_char_no_slash(c: u8) -> bool {
-    is_unreserved(c) || c == b';' || c == b'?' || c == b':' || c == b'@' || c == b'&' ||
-    c == b'=' || c == b'+' || c == b'$' || c == b','
-}
-
-named!(uric_no_slash<&[u8], u8>, alt!(
-    take_1!(is_uri_char_no_slash) |
-    escaped));
-
-fn is_uri_char(c: u8) -> bool {
-    is_unreserved(c) || is_reserved(c)
-}
-
-named!(uric<&[u8], u8>, alt!(
-        take_1!(is_uri_char) |
-        escaped));
-
-named!(opaque_part<&[u8], (u8, Vec<u8>)>, pair!(
-    uric_no_slash,
-    many0!(uric)));
-
-named!(absolute_uri<&[u8], AbsoluteUri>, separated_pair!(
-    scheme,
-    char!(':'),
-    alt!(
-      hier_part => { |(h,q)| UriPath::Hierarchical { path: h, query: q } } |
-      opaque_part => { |(b, o)| UriPath::Opaque(b, o) }
-    )));
-
-named!(uri<&[u8], Uri>, alt!(
-    sip_uri => { |(u, hp, p, h)| Uri::Sip(SipUri {
-        user_info: u,
-        host_port: hp,
-        params: p,
-        headers: h }) } |
-    sips_uri => { |(u, hp, p, h)| Uri::Sips(SipUri {
-        user_info: u,
-        host_port: hp,
-        params: p,
-        headers: h }) } |
-    absolute_uri => { |(s, p)| Uri::Generic {
-        scheme: s,
-        path: p } }
-));
-
-// Variant without URI parameters or header parameters
-named!(uri_np<&[u8], Uri>, alt!(
-    sip_uri_np => { |(u, hp)| Uri::Sip(SipUri {
-        user_info: u,
-        host_port: hp,
-        params: vec![],
-        headers: None }) } |
-    sips_uri_np => { |(u, hp)| Uri::Sips(SipUri {
-        user_info: u,
-        host_port: hp,
-        params: vec![],
-        headers: None }) } |
-    absolute_uri => { |(s, p)| Uri::Generic {
-        scheme: s,
-        path: p } }
-));
-
-named!(sip_version<&[u8], Version>, preceded!(
-    tag!("SIP/"),
-    dbg_dmp!(separated_pair!(
-       dbg_dmp!(number),
-       dbg_dmp!(tag!(b".")),
-       dbg_dmp!(number)))));
-
-named!(request_line<&[u8], (Method, Uri, Version)>, tuple!(
-    method,
-    delimited!(
-        tag!(" "),
-        uri,
-        tag!(" ")),
-    sip_version));
-
-fn is_reason_phrase_char(c: u8) -> bool {
-    is_reserved(c) || is_unreserved(c) || c == b' ' || c == b'\t'
-}
-
-named!(reason_phrase<Vec<u8>>, many0!(alt!(
-       escaped |
-       take_1!(is_reason_phrase_char))));
-
-named!(status_line<&[u8], (Version, u16, Vec<u8>)>, tuple!(
-       sip_version,
-       delimited!(
-               tag!(" "),
-               number,
-               tag!(" ")
-       ),
-       reason_phrase));
-
-named!(pub top_line<TopLine>, alt!(
-       request_line => { |(m,u,v)| TopLine::RequestLine(RequestLine {
-               method: m,
-               uri: u,
-               version: v
-       })} |
-       status_line => { |(v, c, r)| TopLine::StatusLine(StatusLine {
-               version: v,
-               code: c,
-               reason: r
-       })}));
-
-/// 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!(
-// Discrete Types
-       tag!(b"text") => { |_| MediaMainType::Text } |
-       tag!(b"image") => { |_| MediaMainType::Image } |
-       tag!(b"audio") => { |_| MediaMainType::Audio } |
-       tag!(b"video") => { |_| MediaMainType::Video } |
-       tag!(b"application") => { |_| MediaMainType::Application } |
-// Composite Types
-       tag!(b"message") => { |_| MediaMainType::Message } |
-       tag!(b"multipart") => { |_| MediaMainType::Multipart } |
-// Extensions
-       token => { |x| MediaMainType::Extension(x) }));
-
-// We don't bother splitting IANA, IETF and x- token types.
-use self::token as media_subtype;
-
-use self::token as media_attribute;
-
-fn is_qdtext_char(c: u8) -> bool {
-    c == 0x21 || (c >= 0x23 && c <= 0x5b) || (c >= 0x5d && c <= 0x7e)
-}
-
-named!(qdtext<u8>, take_1!(is_qdtext_char));
-
-fn is_qdpair_char(c: u8) -> bool {
-    c <= 0x09 || c == 0x0B || c == 0x0C || (c >= 0x0E && c <= 0x7f)
-}
-
-named!(qdpair<u8>, preceded!(
-       tag!("\\"),
-       take_1!(is_qdpair_char)));
-
-named!(quoted_string<Vec<u8>>, delimited!(
-       tag!(b"\""),
-       many0!(alt!(
-               qdtext |
-               qdpair)),
-       tag!(b"\"")));
-
-named!(media_value<Vec<u8>>, alt!(
-       token |
-       quoted_string));
-
-named!(media_parameter<MediaParameter>, separated_pair!(
-       media_attribute,
-       tag!(b"="),
-       media_value));
-
-named!(media_type<MediaType>, separated_pair!(
-       media_main_type,
-       tag!(b"/"),
-       media_subtype));
-
-named!(media_range<MediaRange>, tuple!(
-       alt!(
-               tag!(b"*/*") => { |_| MediaFullType::All } |
-               terminated!(media_main_type, tag!(b"/*")) => { |x| MediaFullType::Partial(x) } | /**/
-               media_type => { |(t, st)| MediaFullType::Specific(t, st) }),
-       many0!(
-               preceded!(tag!(b";"), media_parameter))));
-
-named!(generic_param<GenericParam>, separated_pair!(
-       token,
-       tag!(b"="),
-       opt!(token)));
-
-use self::float as qvalue;
-
-named!(qparam<f32>, preceded!(tag!(b"q="), qvalue));
-
-named!(accept_param<AcceptParam>, alt!(
-       qparam => { |x| AcceptParam::Qvalue(x) } |
-       generic_param => { |x| AcceptParam::Generic(x) }));
-
-named!(accept_range<AcceptRange>, tuple!(
-       media_range,
-       many0!(preceded!(
-               tag!(b";"),
-               accept_param))));
-
-named!(accept_header<Vec<AcceptRange>>, preceded!(
-       terminated!(tag!(b"Accept"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               accept_range)));
-
-named!(codings<Coding>, alt!(
-       tag!(b"*") => { |_| Coding::All } |
-       token => { |t| Coding::Content(t) }
-));
-
-named!(encoding<Encoding>, tuple!(
-       codings,
-       many0!(preceded!(
-               tag!(b";"),
-               accept_param))));
-
-named!(accept_encoding_header<Vec<Encoding>>, preceded!(
-       terminated!(tag!(b"Accept-Encoding"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               encoding)));
-
-named!(language_token<Vec<u8>>, many1!(alpha));
-
-named!(language_tag<LanguageTag>, separated_nonempty_list!(
-               tag!(b"-"),
-               language_token));
-
-named!(language_range<LanguageRange>, alt!(
-       tag!(b"*") => { |_| LanguageRange::All } |
-       language_tag => { |x : LanguageTag| LanguageRange::Range(x) }));
-
-named!(language<Language>, tuple!(
-       language_range,
-       many0!(preceded!(
-               tag!(b";"),
-               accept_param))));
-
-named!(accept_language_header<Vec<Language>>, preceded!(
-       terminated!(tag!(b"Accept-Language"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               language)));
-
-named!(alert_param<AlertParam>, tuple!(
-       delimited!(
-               tag!(b"<"),
-               absolute_uri,
-               tag!(b">")
-       ),
-       many0!(generic_param)));
-
-named!(alert_info_header<Vec<AlertParam>>, preceded!(
-       terminated!(tag!(b"Alert-Info"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               alert_param)));
-
-named!(allow_header<Vec<Method>>, preceded!(
-       terminated!(tag!(b"Allow"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               method)));
-
-named!(nextnonce<Vec<u8>>, preceded!(
-       tag!(b"nc="),
-       quoted_string));
-
-named!(qop_value<Qop>, alt!(
-       tag!(b"auth") => { |x| Qop::Auth } |
-       tag!(b"auth-init") => { |x| Qop::AuthInit } |
-       token => { |x| Qop::Token(x) }));
-
-named!(message_qop<Qop>, preceded!(
-       tag!(b"qop="),
-       qop_value));
-
-named!(response_digest<Vec<u8>>, delimited!(
-       tag!(b"\""),
-       many0!(hex),
-       tag!(b"\"")));
-
-named!(response_auth<Vec<u8>>, preceded!(
-       tag!(b"rspauth="),
-       response_digest));
-
-named!(cnonce<Vec<u8>>, preceded!(
-       tag!(b"cnonce="),
-       quoted_string));
-
-named!(nc_value<Vec<u8>>, many1!(lhex));
-
-named!(nonce_count<Vec<u8>>, preceded!(
-       tag!(b"nc="),
-       nc_value));
-
-named!(ainfo<AuthenticationInfo>, alt!(
-       nextnonce => { |n| AuthenticationInfo::NextNonce(n) } |
-       message_qop => { |m| AuthenticationInfo::MessageQop(m) } |
-       response_auth => { |r| AuthenticationInfo::ResponseAuth(r) } |
-       cnonce => { |c| AuthenticationInfo::Cnonce(c) } |
-       nonce_count => { |n| AuthenticationInfo::NonceCount(n) }));
-
-named!(authentication_info_header<Vec<AuthenticationInfo>>, preceded!(
-       terminated!(tag!(b"Authentication-Info"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               ainfo)));
-
-named!(username<Vec<u8>>, preceded!(
-       tag!(b"username="),
-       quoted_string));
-
-named!(realm<Vec<u8>>, preceded!(
-       tag!(b"realm="),
-       quoted_string));
-
-named!(nonce<Vec<u8>>, preceded!(
-       tag!(b"nonce="),
-       quoted_string));
-
-named!(digest_uri<Vec<u8>>, preceded!(
-       tag!(b"digest_uri="),
-       quoted_string));
-
-named!(dresponse<Vec<u8>>, preceded!(
-       tag!(b"response="),
-       response_digest));
-
-named!(algorithm<Algorithm>, alt!(
-       tag!("MD5") => { |_| Algorithm::Md5 } |
-       tag!("MD5-sess") => { |_| Algorithm::Md5Session } |
-       token => { |t| Algorithm::Token(t) }
-));
-
-named!(opaque<Vec<u8>>, preceded!(
-       tag!(b"opaque="),
-       quoted_string));
-
-named!(auth_param<AuthParam>, separated_pair!(
-       token,
-       tag!(b"="),
-       alt!(
-               token |
-               quoted_string)));
-
-named!(digest_response<Vec<DigestResponse>>, many1!(alt!(
-       username => { |u| DigestResponse::Username(u) } |
-       realm => { |r| DigestResponse::Realm(r) } |
-       nonce => { |n| DigestResponse::Nonce(n) } |
-       digest_uri => { |d| DigestResponse::DigestUri(d) } |
-       dresponse => { |d| DigestResponse::Response(d) } |
-       algorithm => { |a| DigestResponse::Algorithm(a) } |
-       cnonce => { |c| DigestResponse::Cnonce(c) } |
-       opaque => { |o| DigestResponse::Opaque(o) } |
-       message_qop => { |m| DigestResponse::MessageQop(m) } |
-       nonce_count => { |n| DigestResponse::NonceCount(n) } |
-       auth_param => { |(k, v)| DigestResponse::AuthParam(k, v) })));
-
-named!(other_response<(Vec<u8>, Vec<AuthParam>)>, separated_pair!(
-       token,
-       tag!(b" "),
-       separated_nonempty_list!(
-               tag!(b","),
-               auth_param)));
-
-named!(credentials<Credentials>, alt!(
-       preceded!(
-               tag!(b"Digest "),
-               digest_response) => { |d| Credentials::Digest(d) } |
-       other_response => { |(s,p)| Credentials::Other(s, p) }));
-
-named!(authorization_header<Credentials>, preceded!(
-       terminated!(tag!(b"Authorization"), hcolon),
-       credentials));
-
-named!(call_id<CallId>, tuple!(
-       word,
-       opt!(preceded!(
-               tag!(b"@"),
-               word))));
-
-named!(call_id_header<CallId>, preceded!(
-       terminated!(alt!(tag!(b"Call-ID") | tag!(b"i")), hcolon),
-       call_id));
-
-named!(purpose<Purpose>, alt!(
-       tag!(b"icon") => { |_| Purpose::Icon } |
-       tag!(b"info") => { |_| Purpose::Info } |
-       tag!(b"card") => { |_| Purpose::Card } |
-       token => { |t| Purpose::Token(t) }));
-
-named!(info_param<InfoParam>, alt!(
-       preceded!(
-               tag!(b"purpose="),
-               purpose) => { |p| InfoParam::Purpose(p) } |
-       generic_param => { |g| InfoParam::Generic(g) }));
-
-named!(info<Info>, tuple!(
-       delimited!(
-               tag!(b"<"),
-               absolute_uri,
-               tag!(b">")
-       ),
-       many0!(preceded!(
-               tag!(b";"),
-               info_param))));
-
-named!(call_info_header<Vec<Info>>, preceded!(
-       terminated!(tag!(b"Call-Info"), hcolon),
-       separated_nonempty_list!(
-               tag!(","),
-               info)));
-
-named!(display_name<Vec<u8>>, alt!(
-       token |
-       quoted_string));
-
-named!(name_addr<NameAddr>, tuple!(
-       opt!(display_name),
-       delimited!(
-               tag!(b"<"),
-               uri,
-               tag!(b">"))));
-
-named!(expires<u32>, preceded!(
-       tag!(b"expires="),
-       number));
-
-named!(contact_param<ContactParam>, alt!(
-       qparam => {|q| ContactParam::Qvalue(q) } |
-       expires => {|e| ContactParam::Expires(e) } |
-       generic_param => {|g| ContactParam::Generic(g) }));
-
-named!(target<Target>,
-       alt!(
-               name_addr => { |(n, u)| Target::Name(n, u) } |
-// With this target variant, parameters conflict - so they aren't allowed
-// See RFC 3261 Section 20.10
-               uri_np => { |u| Target::Uri(u) }));
-
-named!(contact_target<(Target, Vec<ContactParam>)>, tuple!(
-       target,
-       many0!(preceded!(
-               tag!(b";"),
-               contact_param
-       ))));
-
-named!(contact_header<Contact>, preceded!(
-       terminated!(alt!(tag!(b"Contact") | tag!(b"m")), hcolon),
-       alt!(
-               tag!(b"*") => { |_| Contact::Star } |
-               separated_nonempty_list!(
-                       tag!(","),
-                       contact_target) => { |c| Contact::Contact(c) })));
-
-named!(disp_type<DispositionType>, alt!(
-       tag!(b"render") => { |_| DispositionType::Render } |
-       tag!(b"session") => { |_| DispositionType::Session } |
-       tag!(b"icon") => { |_| DispositionType::Icon } |
-       tag!(b"alert") => { |_| DispositionType::Alert } |
-       token => { |t| DispositionType::Token(t) }
-));
-
-named!(handling<Handling>, alt!(
-       tag!(b"optional") => { |_| Handling::Optional } |
-       tag!(b"required") => { |_| Handling::Required } |
-       token => { |t| Handling::Token(t) }));
-
-named!(disp_param<DispositionParam>, alt!(
-       preceded!(tag!(b"handling="), handling) => { |h| DispositionParam::Handling(h) } |
-       generic_param => { |g| DispositionParam::Generic(g) }));
-
-named!(content_disposition_header<(DispositionType, Vec<DispositionParam>)>, preceded!(
-       terminated!(tag!(b"Content-Disposition"), hcolon),
-       tuple!(
-               disp_type,
-               many0!(preceded!(
-                       tag!(b";"),
-                       disp_param)))));
-
-named!(content_encoding_header<Vec<ContentCoding>>, preceded!(
-       terminated!(alt!(tag!(b"Content-Encoding") | tag!(b"e")), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               token)));
-
-named!(content_language_header<Vec<LanguageTag>>, preceded!(
-       terminated!(tag!(b"Content-Language"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               language_tag)));
-
-named!(content_length_header<u32>, preceded!(
-       terminated!(alt!(tag!(b"Content-Length") | tag!(b"l")), hcolon),
-       number));
-
-named!(content_type_header<MediaType>, preceded!(
-       terminated!(alt!(tag!(b"Content-Type") | tag!(b"c")), hcolon),
-       media_type));
-
-named!(cseq_header<(u32, Method)>, preceded!(
-       terminated!(tag!(b"CSeq"), hcolon),
-       separated_pair!(
-               number,
-               tag!(" "),
-               method)));
-
-named!(wkday<Day>, alt!(
-       tag!(b"Mon") => { |_| Day::Monday } |
-       tag!(b"Tue") => { |_| Day::Tuesday } |
-       tag!(b"Wed") => { |_| Day::Wednesday } |
-       tag!(b"Thu") => { |_| Day::Thursday } |
-       tag!(b"Fri") => { |_| Day::Friday } |
-       tag!(b"Sat") => { |_| Day::Saturday } |
-       tag!(b"Sun") => { |_| Day::Sunday }));
-
-named!(month<Month>, alt!(
-       tag!(b"Jan") => { |_| Month::January } |
-       tag!(b"Feb") => { |_| Month::February } |
-       tag!(b"Mar") => { |_| Month::March } |
-       tag!(b"Apr") => { |_| Month::April } |
-       tag!(b"May") => { |_| Month::May } |
-       tag!(b"Jun") => { |_| Month::June } |
-       tag!(b"Jul") => { |_| Month::July } |
-       tag!(b"Aug") => { |_| Month::August } |
-       tag!(b"Sep") => { |_| Month::September } |
-       tag!(b"Oct") => { |_| Month::October } |
-       tag!(b"Nov") => { |_| Month::November } |
-       tag!(b"Dec") => { |_| Month::December }));
-
-named!(date<Date>, tuple!(
-       terminated!(number, tag!(b" ")),
-       terminated!(month, tag!(b" ")),
-       number));
-
-named!(time<Time>, tuple!(
-       terminated!(number, tag!(b":")),
-       terminated!(number, tag!(b":")),
-       number));
-
-named!(date_time<DateTime>, tuple!(
-       terminated!(wkday, tag!(b", ")),
-       terminated!(date, tag!(b" ")),
-       terminated!(time, tag!(b" GMT"))));
-
-named!(date_header<DateTime>, preceded!(
-       terminated!(tag!(b"Date"), hcolon),
-       date_time));
-
-named!(error_uri<ErrorUri>, tuple!(
-       delimited!(
-               tag!(b"<"),
-               absolute_uri,
-               tag!(b">")
-       ),
-       many0!(preceded!(
-               tag!(b";"),
-               generic_param))));
-
-named!(error_info_header<Vec<ErrorUri>>, preceded!(
-       terminated!(tag!(b"Error-Info"), hcolon),
-       separated_nonempty_list!(
-               tag!(","),
-               error_uri)));
-
-named!(expires_header<u32>, preceded!(
-       terminated!(tag!(b"Expires"), hcolon),
-       number));
-
-named!(from_param<FromParam>, alt!(
-       preceded!(tag!("tag="), token) => { |t| FromParam::Tag(t) } |
-       generic_param => { |g| FromParam::Generic(g) }));
-
-named!(from_header<From>, preceded!(
-       terminated!(alt!(tag!(b"From") | tag!("f")), hcolon),
-       tuple!(
-               target,
-               many0!(preceded!(
-                       tag!(b";"),
-                       from_param)))));
-
-named!(in_reply_to_header<Vec<CallId>>, preceded!(
-       terminated!(tag!(b"In-Reply-To"), hcolon),
-       separated_nonempty_list!(
-               tag!(","),
-               call_id)));
-
-named!(max_forwards_header<u32>, preceded!(
-       terminated!(tag!(b"Max-Forwards"), hcolon),
-       number));
-
-named!(mime_version_header<(u32, u32)>, preceded!(
-       terminated!(tag!(b"MIME-Version"), hcolon),
-       separated_pair!(
-               number,
-               tag!(b"."),
-               number)));
-
-named!(min_expires_header<u32>, preceded!(
-       terminated!(tag!(b"Min-Expires"), hcolon),
-       number));
-
-named!(organization_header<Vec<u8>>, preceded!(
-       terminated!(tag!(b"Organization"), hcolon),
-       word));
-
-named!(priority_header<Priority>, preceded!(
-       terminated!(tag!(b"Priority"), hcolon),
-       alt!(
-               tag!(b"emergency") => { |_| Priority::Emergency } |
-               tag!(b"urgent") => { |_| Priority::Urgent } |
-               tag!(b"normal") => { |_| Priority::Normal } |
-               tag!(b"non-urgent") => { |_| Priority::NonUrgent } |
-               token => { |t| Priority::Other(t) })));
-
-named!(domain<Vec<Domain>>, delimited!(
-       tag!(b"domain=\""),
-       separated_nonempty_list!(
-               tag!(" "),
-               alt!(
-                       absolute_uri => { |u| Domain::Uri(u) } |
-                       abs_path => { |p| Domain::Path(p) }
-               )),
-       tag!(b"\"")));
-
-named!(boolean<bool>, alt!(
-       tag!(b"true") => { |_| true } |
-       tag!(b"false") => { |_| false }));
-
-named!(stale<bool>, preceded!(
-       tag!(b"stale="),
-       boolean));
-
-named!(qop_options<Vec<Qop>>, delimited!(
-       tag!(b"qop=\""),
-       separated_nonempty_list!(
-               tag!(b","),
-               qop_value),
-       tag!(b"\"")));
-
-named!(digest_challenge<Vec<DigestChallenge>>, many1!(alt!(
-       realm => { |r| DigestChallenge::Realm(r) } |
-       domain => { |d| DigestChallenge::Domain(d) } |
-       nonce => { |n| DigestChallenge::Nonce(n) } |
-       opaque => { |o| DigestChallenge::Opaque(o) } |
-       stale => { |s| DigestChallenge::Stale(s) } |
-       qop_options => { |q| DigestChallenge::QopOptions(q) } |
-       auth_param => { |(k, v)| DigestChallenge::AuthParam(k, v) })));
-
-use self::other_response as other_challenge;
-
-named!(challenge<Challenge>, alt!(
-       preceded!(tag!(b"Digest "), digest_challenge) => { |d| Challenge::Digest(d) } |
-       other_challenge => { |(s, p)| Challenge::Other(s, p) }));
-
-named!(proxy_authenticate_header<Challenge>, preceded!(
-       terminated!(tag!(b"Proxy-Authenticate"), hcolon),
-       challenge));
-
-named!(proxy_authorization_header<Credentials>, preceded!(
-       terminated!(tag!(b"Proxy-Authorization"), hcolon),
-       credentials));
-
-named!(proxy_require_header<Vec<OptionTag>>, preceded!(
-       terminated!(tag!(b"Proxy-Require"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               token)));
-
-named!(route<Route>, pair!(
-       name_addr,
-       many0!(preceded!(
-               tag!(b";"),
-               generic_param))));
-
-named!(record_route_header<Vec<Route>>, preceded!(
-       terminated!(tag!(b"Record-Route"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               route)));
-
-named!(reply_to<ReplyTo>, pair!(
-       target,
-       many0!(preceded!(
-               tag!(b";"),
-               generic_param))));
-
-named!(reply_to_header<Vec<ReplyTo>>, preceded!(
-       terminated!(tag!(b"Reply-To"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               reply_to)));
-
-named!(require_header<Vec<OptionTag>>, preceded!(
-       terminated!(tag!(b"Require"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               token)));
-
-named!(retry_after_param<RetryAfterParam>, alt!(
-       preceded!(tag!(b"duration="), number) => { |d| RetryAfterParam::Duration(d) } |
-       generic_param => { |g| RetryAfterParam::Generic(g) }));
-
-named!(retry_after_header<RetryAfter>, preceded!(
-       terminated!(tag!(b"Retry-After"), hcolon),
-       pair!(
-               number,
-               many0!(preceded!(
-                       tag!(b";"),
-                       retry_after_param
-               )))));
-
-named!(route_header<Vec<Route>>, preceded!(
-       terminated!(tag!(b"Route"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               route)));
-
-named!(server<Server>, pair!(
-       token,
-       opt!(preceded!(
-               tag!(b"/"),
-               token))));
-
-named!(server_header<Vec<Server>>, preceded!(
-       terminated!(tag!(b"Server"), hcolon),
-       separated_nonempty_list!(
-               tag!(b" "),
-               server)));
-
-named!(subject_header<Vec<u8>>, preceded!(
-       terminated!(alt!(tag!(b"Subject") | tag!(b"s")), hcolon),
-       word));
-
-named!(supported_header<Vec<OptionTag>>, preceded!(
-       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!(
-       terminated!(tag!(b"Timestamp"), hcolon),
-       separated_nonempty_list!(
-               tag!(b" "),
-               delay)));
-
-named!(to_param<ToParam>, alt!(
-       preceded!(tag!("tag="), token) => { |t| ToParam::Tag(t) } |
-       generic_param => { |g| ToParam::Generic(g) }));
-
-named!(to_header<To>, preceded!(
-       terminated!(alt!(tag!(b"To") | tag!("t")), hcolon),
-       tuple!(
-               target,
-               many0!(preceded!(
-                       tag!(b";"),
-                       to_param)))));
-
-named!(unsupported_header<Vec<OptionTag>>, preceded!(
-       terminated!(tag!(b"Unsupported"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               token)));
-
-named!(user_agent_header<Vec<Server>>, preceded!(
-       terminated!(tag!(b"User-Agent"), hcolon),
-       separated_nonempty_list!(
-               tag!(b" "),
-               server)));
-
-named!(protocol_name<Protocol>, alt!(
-       tag!(b"SIP") => { |_| Protocol::SIP } |
-       token => { |t| Protocol::Other(t) }
-));
-
-named!(transport<Transport>, alt!(
-       tag!(b"UDP") => { |_| Transport::Udp } |
-       tag!(b"TCP") => { |_| Transport::Tcp } |
-       tag!(b"TLS") => { |_| Transport::Tls } |
-       tag!(b"SCTP") => { |_| Transport::Sctp } |
-       token => { |t| Transport::Other(t) }));
-
-named!(sent_protocol<SentProtocol>, tuple!(
-       terminated!(protocol_name, tag!("/")),
-       terminated!(token, tag!("/")),
-       transport));
-
-use self::hostport as sent_by;
-
-named!(received<Received>, alt!(
-    ipv4_address => { |(a, b, c, d)| Received::Ipv4Address(a,b,c,d) } |
-    ipv6_address => { |i| Received::Ipv6Address(i) }
-));
-
-named!(via_param<ViaParam>, alt!(
-       preceded!(tag!(b"ttl="), number) => { |t| ViaParam::Ttl(t) } |
-       preceded!(tag!(b"maddr="), host) => { |h| ViaParam::Maddr(h) } |
-       preceded!(tag!(b"received="), received) => { |r| ViaParam::Received(r) } |
-       preceded!(tag!(b"branch="), token) => { |t| ViaParam::Branch(t) } |
-       generic_param => { |g| ViaParam::Extension(g) }
-));
-
-named!(via<Via>, tuple!(
-       terminated!(sent_protocol, tag!(b" ")),
-       sent_by,
-       many0!(preceded!(
-               tag!(b";"),
-               via_param))));
-
-named!(via_header<Vec<Via>>, preceded!(
-       terminated!(alt!(tag!(b"Via") | tag!(b"v")), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               via)));
-
-named!(warning_agent<WarningAgent>, alt!(
-       hostport => { |h| WarningAgent::Host(h) } |
-       token => { |p| WarningAgent::Pseudonym(p) }));
-
-named!(warning<Warning>, tuple!(
-       terminated!(number, tag!(b" ")),
-       terminated!(warning_agent, tag!(b" ")),
-       quoted_string));
-
-named!(warning_header<Vec<Warning>>, preceded!(
-       terminated!(tag!(b"Warning"), hcolon),
-       separated_nonempty_list!(
-               tag!(b","),
-               warning)));
-
-named!(www_authenticate_header<Challenge>, preceded!(
-       terminated!(tag!(b"WWW-Authenticate"), hcolon),
-       challenge));
-
-named!(extension_header<(Vec<u8>, Vec<u8>)>, separated_pair!(
-       token,
-       hcolon,
-       word));
-
-named!(pub header<Header>, alt!(
-// RFC 3261 Headers
-       accept_header => { |a| Header::Accept(a) } |
-       accept_encoding_header => { |a| Header::AcceptEncoding(a) } |
-       accept_language_header => { |a| Header::AcceptLanguage(a) } |
-       alert_info_header => { |a| Header::AlertInfo(a) } |
-       allow_header => { |a| Header::Allow(a) } |
-       authentication_info_header => { |a| Header::AuthenticationInfo(a) } |
-       authorization_header => { |a| Header::Authorization(a) } |
-       call_id_header => { |c| Header::CallId(c) } |
-       call_info_header => { |c| Header::CallInfo(c) } |
-       contact_header => { |c| Header::Contact(c) } |
-       content_disposition_header => { |(t, p)| Header::ContentDisposition(t, p) } |
-       content_encoding_header => { |e| Header::ContentEncoding(e) } |
-       content_language_header => { |l| Header::ContentLanguage(l) } |
-       content_length_header => { |l| Header::ContentLength(l) } |
-       content_type_header => { |t| Header::ContentType(t) } |
-       cseq_header => { |(c, m)| Header::CSeq(c, m) } |
-       date_header => { |d| Header::Date(d) } |
-       error_info_header => { |e| Header::ErrorInfo(e) } |
-       expires_header => { |e| Header::Expires(e) } |
-       from_header => { |f| Header::From(f) } |
-       in_reply_to_header => { |i| Header::InReplyTo(i) } |
-       max_forwards_header => { |m| Header::MaxForwards(m) } |
-       mime_version_header => { |(m, v)| Header::MimeVersion(m, v) } |
-       min_expires_header => { |m| Header::MinExpires(m) } |
-       organization_header => { |o| Header::Organization(o) } |
-       priority_header => { |p| Header::Priority(p) } |
-       proxy_authenticate_header => { |p| Header::ProxyAuthenticate(p) } |
-       proxy_authorization_header => { |p| Header::ProxyAuthorization(p) } |
-       proxy_require_header => { |p| Header::ProxyRequire(p) } |
-       record_route_header => { |r| Header::RecordRoute(r) } |
-       reply_to_header => { |r| Header::ReplyTo(r) } |
-       require_header => { |r| Header::Require(r) } |
-       retry_after_header => { |r| Header::RetryAfter(r) } |
-       route_header => { |r| Header::Route(r) } |
-       server_header => { |s| Header::Server(s) } |
-       subject_header => { |s| Header::Subject(s) } |
-       supported_header => { |s| Header::Supported(s) } |
-       timestamp_header => { |t| Header::Timestamp(t) } |
-       to_header => { |t| Header::To(t) } |
-       unsupported_header => { |u| Header::Unsupported(u) } |
-       user_agent_header => { |u| Header::UserAgent(u) } |
-       via_header => { |v| Header::Via(v) } |
-       warning_header => { |w| Header::Warning(w) } |
-       www_authenticate_header => { |w| Header::WwwAuthenticate(w) } |
-// Custom extension headers
-       extension_header => { |(n, v)| Header::Extension { name: n, value: v } }
-));
diff --git a/src/parser/header.rs b/src/parser/header.rs
new file mode 100644 (file)
index 0000000..c954219
--- /dev/null
@@ -0,0 +1,757 @@
+use parser::*;
+
+/// Headers
+
+// Accept Header
+
+named!(media_main_type<MediaMainType>, alt!(
+// Discrete Types
+       tag!(b"text") => { |_| MediaMainType::Text } |
+       tag!(b"image") => { |_| MediaMainType::Image } |
+       tag!(b"audio") => { |_| MediaMainType::Audio } |
+       tag!(b"video") => { |_| MediaMainType::Video } |
+       tag!(b"application") => { |_| MediaMainType::Application } |
+// Composite Types
+       tag!(b"message") => { |_| MediaMainType::Message } |
+       tag!(b"multipart") => { |_| MediaMainType::Multipart } |
+// Extensions
+       token => { |x| MediaMainType::Extension(x) }));
+
+// We don't bother splitting IANA, IETF and x- token types.
+use self::token as media_subtype;
+
+use self::token as media_attribute;
+
+named!(media_value<Vec<u8>>, alt!(
+       token |
+       quoted_string));
+
+named!(media_parameter<MediaParameter>, separated_pair!(
+       media_attribute,
+       tag!(b"="),
+       media_value));
+
+named!(media_type<MediaType>, separated_pair!(
+       media_main_type,
+       tag!(b"/"),
+       media_subtype));
+
+named!(media_range<MediaRange>, tuple!(
+       alt!(
+               tag!(b"*/*") => { |_| MediaFullType::All } |
+               terminated!(media_main_type, tag!(b"/*")) => { |x| MediaFullType::Partial(x) } | /**/
+               media_type => { |(t, st)| MediaFullType::Specific(t, st) }),
+       many0!(
+               preceded!(tag!(b";"), media_parameter))));
+
+named!(generic_param<GenericParam>, separated_pair!(
+       token,
+       tag!(b"="),
+       opt!(token)));
+
+use self::float as qvalue;
+
+named!(qparam<f32>, preceded!(tag!(b"q="), qvalue));
+
+named!(accept_param<AcceptParam>, alt!(
+       qparam => { |x| AcceptParam::Qvalue(x) } |
+       generic_param => { |x| AcceptParam::Generic(x) }));
+
+named!(accept_range<AcceptRange>, tuple!(
+       media_range,
+       many0!(preceded!(
+               tag!(b";"),
+               accept_param))));
+
+named!(accept_header<Vec<AcceptRange>>, preceded!(
+       terminated!(tag!(b"Accept"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               accept_range)));
+
+named!(codings<Coding>, alt!(
+       tag!(b"*") => { |_| Coding::All } |
+       token => { |t| Coding::Content(t) }
+));
+
+named!(encoding<Encoding>, tuple!(
+       codings,
+       many0!(preceded!(
+               tag!(b";"),
+               accept_param))));
+
+named!(accept_encoding_header<Vec<Encoding>>, preceded!(
+       terminated!(tag!(b"Accept-Encoding"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               encoding)));
+
+named!(language_token<Vec<u8>>, many1!(alpha));
+
+named!(language_tag<LanguageTag>, separated_nonempty_list!(
+               tag!(b"-"),
+               language_token));
+
+named!(language_range<LanguageRange>, alt!(
+       tag!(b"*") => { |_| LanguageRange::All } |
+       language_tag => { |x : LanguageTag| LanguageRange::Range(x) }));
+
+named!(language<Language>, tuple!(
+       language_range,
+       many0!(preceded!(
+               tag!(b";"),
+               accept_param))));
+
+named!(accept_language_header<Vec<Language>>, preceded!(
+       terminated!(tag!(b"Accept-Language"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               language)));
+
+named!(alert_param<AlertParam>, tuple!(
+       delimited!(
+               tag!(b"<"),
+               absolute_uri,
+               tag!(b">")
+       ),
+       many0!(generic_param)));
+
+named!(alert_info_header<Vec<AlertParam>>, preceded!(
+       terminated!(tag!(b"Alert-Info"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               alert_param)));
+
+named!(allow_header<Vec<Method>>, preceded!(
+       terminated!(tag!(b"Allow"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               method)));
+
+named!(nextnonce<Vec<u8>>, preceded!(
+       tag!(b"nc="),
+       quoted_string));
+
+named!(qop_value<Qop>, alt!(
+       tag!(b"auth") => { |x| Qop::Auth } |
+       tag!(b"auth-init") => { |x| Qop::AuthInit } |
+       token => { |x| Qop::Token(x) }));
+
+named!(message_qop<Qop>, preceded!(
+       tag!(b"qop="),
+       qop_value));
+
+named!(response_digest<Vec<u8>>, delimited!(
+       tag!(b"\""),
+       many0!(hex),
+       tag!(b"\"")));
+
+named!(response_auth<Vec<u8>>, preceded!(
+       tag!(b"rspauth="),
+       response_digest));
+
+named!(cnonce<Vec<u8>>, preceded!(
+       tag!(b"cnonce="),
+       quoted_string));
+
+named!(nc_value<Vec<u8>>, many1!(lhex));
+
+named!(nonce_count<Vec<u8>>, preceded!(
+       tag!(b"nc="),
+       nc_value));
+
+named!(ainfo<AuthenticationInfo>, alt!(
+       nextnonce => { |n| AuthenticationInfo::NextNonce(n) } |
+       message_qop => { |m| AuthenticationInfo::MessageQop(m) } |
+       response_auth => { |r| AuthenticationInfo::ResponseAuth(r) } |
+       cnonce => { |c| AuthenticationInfo::Cnonce(c) } |
+       nonce_count => { |n| AuthenticationInfo::NonceCount(n) }));
+
+named!(authentication_info_header<Vec<AuthenticationInfo>>, preceded!(
+       terminated!(tag!(b"Authentication-Info"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               ainfo)));
+
+named!(username<Vec<u8>>, preceded!(
+       tag!(b"username="),
+       quoted_string));
+
+named!(realm<Vec<u8>>, preceded!(
+       tag!(b"realm="),
+       quoted_string));
+
+named!(nonce<Vec<u8>>, preceded!(
+       tag!(b"nonce="),
+       quoted_string));
+
+named!(digest_uri<Vec<u8>>, preceded!(
+       tag!(b"digest_uri="),
+       quoted_string));
+
+named!(dresponse<Vec<u8>>, preceded!(
+       tag!(b"response="),
+       response_digest));
+
+named!(algorithm<Algorithm>, alt!(
+       tag!("MD5") => { |_| Algorithm::Md5 } |
+       tag!("MD5-sess") => { |_| Algorithm::Md5Session } |
+       token => { |t| Algorithm::Token(t) }
+));
+
+named!(opaque<Vec<u8>>, preceded!(
+       tag!(b"opaque="),
+       quoted_string));
+
+named!(auth_param<AuthParam>, separated_pair!(
+       token,
+       tag!(b"="),
+       alt!(
+               token |
+               quoted_string)));
+
+named!(digest_response<Vec<DigestResponse>>, many1!(alt!(
+       username => { |u| DigestResponse::Username(u) } |
+       realm => { |r| DigestResponse::Realm(r) } |
+       nonce => { |n| DigestResponse::Nonce(n) } |
+       digest_uri => { |d| DigestResponse::DigestUri(d) } |
+       dresponse => { |d| DigestResponse::Response(d) } |
+       algorithm => { |a| DigestResponse::Algorithm(a) } |
+       cnonce => { |c| DigestResponse::Cnonce(c) } |
+       opaque => { |o| DigestResponse::Opaque(o) } |
+       message_qop => { |m| DigestResponse::MessageQop(m) } |
+       nonce_count => { |n| DigestResponse::NonceCount(n) } |
+       auth_param => { |(k, v)| DigestResponse::AuthParam(k, v) })));
+
+named!(other_response<(Vec<u8>, Vec<AuthParam>)>, separated_pair!(
+       token,
+       tag!(b" "),
+       separated_nonempty_list!(
+               tag!(b","),
+               auth_param)));
+
+named!(credentials<Credentials>, alt!(
+       preceded!(
+               tag!(b"Digest "),
+               digest_response) => { |d| Credentials::Digest(d) } |
+       other_response => { |(s,p)| Credentials::Other(s, p) }));
+
+named!(authorization_header<Credentials>, preceded!(
+       terminated!(tag!(b"Authorization"), hcolon),
+       credentials));
+
+named!(call_id<CallId>, tuple!(
+       word,
+       opt!(preceded!(
+               tag!(b"@"),
+               word))));
+
+named!(call_id_header<CallId>, preceded!(
+       terminated!(alt!(tag!(b"Call-ID") | tag!(b"i")), hcolon),
+       call_id));
+
+named!(purpose<Purpose>, alt!(
+       tag!(b"icon") => { |_| Purpose::Icon } |
+       tag!(b"info") => { |_| Purpose::Info } |
+       tag!(b"card") => { |_| Purpose::Card } |
+       token => { |t| Purpose::Token(t) }));
+
+named!(info_param<InfoParam>, alt!(
+       preceded!(
+               tag!(b"purpose="),
+               purpose) => { |p| InfoParam::Purpose(p) } |
+       generic_param => { |g| InfoParam::Generic(g) }));
+
+named!(info<Info>, tuple!(
+       delimited!(
+               tag!(b"<"),
+               absolute_uri,
+               tag!(b">")
+       ),
+       many0!(preceded!(
+               tag!(b";"),
+               info_param))));
+
+named!(call_info_header<Vec<Info>>, preceded!(
+       terminated!(tag!(b"Call-Info"), hcolon),
+       separated_nonempty_list!(
+               tag!(","),
+               info)));
+
+named!(display_name<Vec<u8>>, alt!(
+       token |
+       quoted_string));
+
+named!(name_addr<NameAddr>, tuple!(
+       opt!(display_name),
+       delimited!(
+               tag!(b"<"),
+               uri,
+               tag!(b">"))));
+
+named!(expires<u32>, preceded!(
+       tag!(b"expires="),
+       number));
+
+named!(contact_param<ContactParam>, alt!(
+       qparam => {|q| ContactParam::Qvalue(q) } |
+       expires => {|e| ContactParam::Expires(e) } |
+       generic_param => {|g| ContactParam::Generic(g) }));
+
+named!(target<Target>,
+       alt!(
+               name_addr => { |(n, u)| Target::Name(n, u) } |
+// With this target variant, parameters conflict - so they aren't allowed
+// See RFC 3261 Section 20.10
+               uri_np => { |u| Target::Uri(u) }));
+
+named!(contact_target<(Target, Vec<ContactParam>)>, tuple!(
+       target,
+       many0!(preceded!(
+               tag!(b";"),
+               contact_param
+       ))));
+
+named!(contact_header<Contact>, preceded!(
+       terminated!(alt!(tag!(b"Contact") | tag!(b"m")), hcolon),
+       alt!(
+               tag!(b"*") => { |_| Contact::Star } |
+               separated_nonempty_list!(
+                       tag!(","),
+                       contact_target) => { |c| Contact::Contact(c) })));
+
+named!(disp_type<DispositionType>, alt!(
+       tag!(b"render") => { |_| DispositionType::Render } |
+       tag!(b"session") => { |_| DispositionType::Session } |
+       tag!(b"icon") => { |_| DispositionType::Icon } |
+       tag!(b"alert") => { |_| DispositionType::Alert } |
+       token => { |t| DispositionType::Token(t) }
+));
+
+named!(handling<Handling>, alt!(
+       tag!(b"optional") => { |_| Handling::Optional } |
+       tag!(b"required") => { |_| Handling::Required } |
+       token => { |t| Handling::Token(t) }));
+
+named!(disp_param<DispositionParam>, alt!(
+       preceded!(tag!(b"handling="), handling) => { |h| DispositionParam::Handling(h) } |
+       generic_param => { |g| DispositionParam::Generic(g) }));
+
+named!(content_disposition_header<(DispositionType, Vec<DispositionParam>)>, preceded!(
+       terminated!(tag!(b"Content-Disposition"), hcolon),
+       tuple!(
+               disp_type,
+               many0!(preceded!(
+                       tag!(b";"),
+                       disp_param)))));
+
+named!(content_encoding_header<Vec<ContentCoding>>, preceded!(
+       terminated!(alt!(tag!(b"Content-Encoding") | tag!(b"e")), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               token)));
+
+named!(content_language_header<Vec<LanguageTag>>, preceded!(
+       terminated!(tag!(b"Content-Language"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               language_tag)));
+
+named!(content_length_header<u32>, preceded!(
+       terminated!(alt!(tag!(b"Content-Length") | tag!(b"l")), hcolon),
+       number));
+
+named!(content_type_header<MediaType>, preceded!(
+       terminated!(alt!(tag!(b"Content-Type") | tag!(b"c")), hcolon),
+       media_type));
+
+named!(cseq_header<(u32, Method)>, preceded!(
+       terminated!(tag!(b"CSeq"), hcolon),
+       separated_pair!(
+               number,
+               tag!(" "),
+               method)));
+
+named!(wkday<Day>, alt!(
+       tag!(b"Mon") => { |_| Day::Monday } |
+       tag!(b"Tue") => { |_| Day::Tuesday } |
+       tag!(b"Wed") => { |_| Day::Wednesday } |
+       tag!(b"Thu") => { |_| Day::Thursday } |
+       tag!(b"Fri") => { |_| Day::Friday } |
+       tag!(b"Sat") => { |_| Day::Saturday } |
+       tag!(b"Sun") => { |_| Day::Sunday }));
+
+named!(month<Month>, alt!(
+       tag!(b"Jan") => { |_| Month::January } |
+       tag!(b"Feb") => { |_| Month::February } |
+       tag!(b"Mar") => { |_| Month::March } |
+       tag!(b"Apr") => { |_| Month::April } |
+       tag!(b"May") => { |_| Month::May } |
+       tag!(b"Jun") => { |_| Month::June } |
+       tag!(b"Jul") => { |_| Month::July } |
+       tag!(b"Aug") => { |_| Month::August } |
+       tag!(b"Sep") => { |_| Month::September } |
+       tag!(b"Oct") => { |_| Month::October } |
+       tag!(b"Nov") => { |_| Month::November } |
+       tag!(b"Dec") => { |_| Month::December }));
+
+named!(date<Date>, tuple!(
+       terminated!(number, tag!(b" ")),
+       terminated!(month, tag!(b" ")),
+       number));
+
+named!(time<Time>, tuple!(
+       terminated!(number, tag!(b":")),
+       terminated!(number, tag!(b":")),
+       number));
+
+named!(date_time<DateTime>, tuple!(
+       terminated!(wkday, tag!(b", ")),
+       terminated!(date, tag!(b" ")),
+       terminated!(time, tag!(b" GMT"))));
+
+named!(date_header<DateTime>, preceded!(
+       terminated!(tag!(b"Date"), hcolon),
+       date_time));
+
+named!(error_uri<ErrorUri>, tuple!(
+       delimited!(
+               tag!(b"<"),
+               absolute_uri,
+               tag!(b">")
+       ),
+       many0!(preceded!(
+               tag!(b";"),
+               generic_param))));
+
+named!(error_info_header<Vec<ErrorUri>>, preceded!(
+       terminated!(tag!(b"Error-Info"), hcolon),
+       separated_nonempty_list!(
+               tag!(","),
+               error_uri)));
+
+named!(expires_header<u32>, preceded!(
+       terminated!(tag!(b"Expires"), hcolon),
+       number));
+
+named!(from_param<FromParam>, alt!(
+       preceded!(tag!("tag="), token) => { |t| FromParam::Tag(t) } |
+       generic_param => { |g| FromParam::Generic(g) }));
+
+named!(from_header<From>, preceded!(
+       terminated!(alt!(tag!(b"From") | tag!("f")), hcolon),
+       tuple!(
+               target,
+               many0!(preceded!(
+                       tag!(b";"),
+                       from_param)))));
+
+named!(in_reply_to_header<Vec<CallId>>, preceded!(
+       terminated!(tag!(b"In-Reply-To"), hcolon),
+       separated_nonempty_list!(
+               tag!(","),
+               call_id)));
+
+named!(max_forwards_header<u32>, preceded!(
+       terminated!(tag!(b"Max-Forwards"), hcolon),
+       number));
+
+named!(mime_version_header<(u32, u32)>, preceded!(
+       terminated!(tag!(b"MIME-Version"), hcolon),
+       separated_pair!(
+               number,
+               tag!(b"."),
+               number)));
+
+named!(min_expires_header<u32>, preceded!(
+       terminated!(tag!(b"Min-Expires"), hcolon),
+       number));
+
+named!(organization_header<Vec<u8>>, preceded!(
+       terminated!(tag!(b"Organization"), hcolon),
+       word));
+
+named!(priority_header<Priority>, preceded!(
+       terminated!(tag!(b"Priority"), hcolon),
+       alt!(
+               tag!(b"emergency") => { |_| Priority::Emergency } |
+               tag!(b"urgent") => { |_| Priority::Urgent } |
+               tag!(b"normal") => { |_| Priority::Normal } |
+               tag!(b"non-urgent") => { |_| Priority::NonUrgent } |
+               token => { |t| Priority::Other(t) })));
+
+named!(domain<Vec<Domain>>, delimited!(
+       tag!(b"domain=\""),
+       separated_nonempty_list!(
+               tag!(" "),
+               alt!(
+                       absolute_uri => { |u| Domain::Uri(u) } |
+                       abs_path => { |p| Domain::Path(p) }
+               )),
+       tag!(b"\"")));
+
+named!(boolean<bool>, alt!(
+       tag!(b"true") => { |_| true } |
+       tag!(b"false") => { |_| false }));
+
+named!(stale<bool>, preceded!(
+       tag!(b"stale="),
+       boolean));
+
+named!(qop_options<Vec<Qop>>, delimited!(
+       tag!(b"qop=\""),
+       separated_nonempty_list!(
+               tag!(b","),
+               qop_value),
+       tag!(b"\"")));
+
+named!(digest_challenge<Vec<DigestChallenge>>, many1!(alt!(
+       realm => { |r| DigestChallenge::Realm(r) } |
+       domain => { |d| DigestChallenge::Domain(d) } |
+       nonce => { |n| DigestChallenge::Nonce(n) } |
+       opaque => { |o| DigestChallenge::Opaque(o) } |
+       stale => { |s| DigestChallenge::Stale(s) } |
+       qop_options => { |q| DigestChallenge::QopOptions(q) } |
+       auth_param => { |(k, v)| DigestChallenge::AuthParam(k, v) })));
+
+use self::other_response as other_challenge;
+
+named!(challenge<Challenge>, alt!(
+       preceded!(tag!(b"Digest "), digest_challenge) => { |d| Challenge::Digest(d) } |
+       other_challenge => { |(s, p)| Challenge::Other(s, p) }));
+
+named!(proxy_authenticate_header<Challenge>, preceded!(
+       terminated!(tag!(b"Proxy-Authenticate"), hcolon),
+       challenge));
+
+named!(proxy_authorization_header<Credentials>, preceded!(
+       terminated!(tag!(b"Proxy-Authorization"), hcolon),
+       credentials));
+
+named!(proxy_require_header<Vec<OptionTag>>, preceded!(
+       terminated!(tag!(b"Proxy-Require"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               token)));
+
+named!(route<Route>, pair!(
+       name_addr,
+       many0!(preceded!(
+               tag!(b";"),
+               generic_param))));
+
+named!(record_route_header<Vec<Route>>, preceded!(
+       terminated!(tag!(b"Record-Route"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               route)));
+
+named!(reply_to<ReplyTo>, pair!(
+       target,
+       many0!(preceded!(
+               tag!(b";"),
+               generic_param))));
+
+named!(reply_to_header<Vec<ReplyTo>>, preceded!(
+       terminated!(tag!(b"Reply-To"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               reply_to)));
+
+named!(require_header<Vec<OptionTag>>, preceded!(
+       terminated!(tag!(b"Require"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               token)));
+
+named!(retry_after_param<RetryAfterParam>, alt!(
+       preceded!(tag!(b"duration="), number) => { |d| RetryAfterParam::Duration(d) } |
+       generic_param => { |g| RetryAfterParam::Generic(g) }));
+
+named!(retry_after_header<RetryAfter>, preceded!(
+       terminated!(tag!(b"Retry-After"), hcolon),
+       pair!(
+               number,
+               many0!(preceded!(
+                       tag!(b";"),
+                       retry_after_param
+               )))));
+
+named!(route_header<Vec<Route>>, preceded!(
+       terminated!(tag!(b"Route"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               route)));
+
+named!(server<Server>, pair!(
+       token,
+       opt!(preceded!(
+               tag!(b"/"),
+               token))));
+
+named!(server_header<Vec<Server>>, preceded!(
+       terminated!(tag!(b"Server"), hcolon),
+       separated_nonempty_list!(
+               tag!(b" "),
+               server)));
+
+named!(subject_header<Vec<u8>>, preceded!(
+       terminated!(alt!(tag!(b"Subject") | tag!(b"s")), hcolon),
+       word));
+
+named!(supported_header<Vec<OptionTag>>, preceded!(
+       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!(
+       terminated!(tag!(b"Timestamp"), hcolon),
+       separated_nonempty_list!(
+               tag!(b" "),
+               delay)));
+
+named!(to_param<ToParam>, alt!(
+       preceded!(tag!("tag="), token) => { |t| ToParam::Tag(t) } |
+       generic_param => { |g| ToParam::Generic(g) }));
+
+named!(to_header<To>, preceded!(
+       terminated!(alt!(tag!(b"To") | tag!("t")), hcolon),
+       tuple!(
+               target,
+               many0!(preceded!(
+                       tag!(b";"),
+                       to_param)))));
+
+named!(unsupported_header<Vec<OptionTag>>, preceded!(
+       terminated!(tag!(b"Unsupported"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               token)));
+
+named!(user_agent_header<Vec<Server>>, preceded!(
+       terminated!(tag!(b"User-Agent"), hcolon),
+       separated_nonempty_list!(
+               tag!(b" "),
+               server)));
+
+named!(protocol_name<Protocol>, alt!(
+       tag!(b"SIP") => { |_| Protocol::SIP } |
+       token => { |t| Protocol::Other(t) }
+));
+
+named!(transport<Transport>, alt!(
+       tag!(b"UDP") => { |_| Transport::Udp } |
+       tag!(b"TCP") => { |_| Transport::Tcp } |
+       tag!(b"TLS") => { |_| Transport::Tls } |
+       tag!(b"SCTP") => { |_| Transport::Sctp } |
+       token => { |t| Transport::Other(t) }));
+
+named!(sent_protocol<SentProtocol>, tuple!(
+       terminated!(protocol_name, tag!("/")),
+       terminated!(token, tag!("/")),
+       transport));
+
+use self::hostport as sent_by;
+
+named!(received<Received>, alt!(
+    ipv4_address => { |(a, b, c, d)| Received::Ipv4Address(a,b,c,d) } |
+    ipv6_address => { |i| Received::Ipv6Address(i) }
+));
+
+named!(via_param<ViaParam>, alt!(
+       preceded!(tag!(b"ttl="), number) => { |t| ViaParam::Ttl(t) } |
+       preceded!(tag!(b"maddr="), host) => { |h| ViaParam::Maddr(h) } |
+       preceded!(tag!(b"received="), received) => { |r| ViaParam::Received(r) } |
+       preceded!(tag!(b"branch="), token) => { |t| ViaParam::Branch(t) } |
+       generic_param => { |g| ViaParam::Extension(g) }
+));
+
+named!(via<Via>, tuple!(
+       terminated!(sent_protocol, tag!(b" ")),
+       sent_by,
+       many0!(preceded!(
+               tag!(b";"),
+               via_param))));
+
+named!(via_header<Vec<Via>>, preceded!(
+       terminated!(alt!(tag!(b"Via") | tag!(b"v")), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               via)));
+
+named!(warning_agent<WarningAgent>, alt!(
+       hostport => { |h| WarningAgent::Host(h) } |
+       token => { |p| WarningAgent::Pseudonym(p) }));
+
+named!(warning<Warning>, tuple!(
+       terminated!(number, tag!(b" ")),
+       terminated!(warning_agent, tag!(b" ")),
+       quoted_string));
+
+named!(warning_header<Vec<Warning>>, preceded!(
+       terminated!(tag!(b"Warning"), hcolon),
+       separated_nonempty_list!(
+               tag!(b","),
+               warning)));
+
+named!(www_authenticate_header<Challenge>, preceded!(
+       terminated!(tag!(b"WWW-Authenticate"), hcolon),
+       challenge));
+
+named!(extension_header<(Vec<u8>, Vec<u8>)>, separated_pair!(
+       token,
+       hcolon,
+       word));
+
+named!(pub header<Header>, alt!(
+// RFC 3261 Headers
+       accept_header => { |a| Header::Accept(a) } |
+       accept_encoding_header => { |a| Header::AcceptEncoding(a) } |
+       accept_language_header => { |a| Header::AcceptLanguage(a) } |
+       alert_info_header => { |a| Header::AlertInfo(a) } |
+       allow_header => { |a| Header::Allow(a) } |
+       authentication_info_header => { |a| Header::AuthenticationInfo(a) } |
+       authorization_header => { |a| Header::Authorization(a) } |
+       call_id_header => { |c| Header::CallId(c) } |
+       call_info_header => { |c| Header::CallInfo(c) } |
+       contact_header => { |c| Header::Contact(c) } |
+       content_disposition_header => { |(t, p)| Header::ContentDisposition(t, p) } |
+       content_encoding_header => { |e| Header::ContentEncoding(e) } |
+       content_language_header => { |l| Header::ContentLanguage(l) } |
+       content_length_header => { |l| Header::ContentLength(l) } |
+       content_type_header => { |t| Header::ContentType(t) } |
+       cseq_header => { |(c, m)| Header::CSeq(c, m) } |
+       date_header => { |d| Header::Date(d) } |
+       error_info_header => { |e| Header::ErrorInfo(e) } |
+       expires_header => { |e| Header::Expires(e) } |
+       from_header => { |f| Header::From(f) } |
+       in_reply_to_header => { |i| Header::InReplyTo(i) } |
+       max_forwards_header => { |m| Header::MaxForwards(m) } |
+       mime_version_header => { |(m, v)| Header::MimeVersion(m, v) } |
+       min_expires_header => { |m| Header::MinExpires(m) } |
+       organization_header => { |o| Header::Organization(o) } |
+       priority_header => { |p| Header::Priority(p) } |
+       proxy_authenticate_header => { |p| Header::ProxyAuthenticate(p) } |
+       proxy_authorization_header => { |p| Header::ProxyAuthorization(p) } |
+       proxy_require_header => { |p| Header::ProxyRequire(p) } |
+       record_route_header => { |r| Header::RecordRoute(r) } |
+       reply_to_header => { |r| Header::ReplyTo(r) } |
+       require_header => { |r| Header::Require(r) } |
+       retry_after_header => { |r| Header::RetryAfter(r) } |
+       route_header => { |r| Header::Route(r) } |
+       server_header => { |s| Header::Server(s) } |
+       subject_header => { |s| Header::Subject(s) } |
+       supported_header => { |s| Header::Supported(s) } |
+       timestamp_header => { |t| Header::Timestamp(t) } |
+       to_header => { |t| Header::To(t) } |
+       unsupported_header => { |u| Header::Unsupported(u) } |
+       user_agent_header => { |u| Header::UserAgent(u) } |
+       via_header => { |v| Header::Via(v) } |
+       warning_header => { |w| Header::Warning(w) } |
+       www_authenticate_header => { |w| Header::WwwAuthenticate(w) } |
+// Custom extension headers
+       extension_header => { |(n, v)| Header::Extension { name: n, value: v } }
+));
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
new file mode 100644 (file)
index 0000000..84dc80a
--- /dev/null
@@ -0,0 +1,503 @@
+use nom;
+use std;
+
+use nom::alpha as alphas;
+use nom::digit as digits;
+use nom::alphanumeric as alphanumerics;
+
+use nom::IResult;
+use nom::ErrorKind::Custom;
+
+macro_rules! take_1 (
+  ($input:expr, $submac:ident!( $($args:tt)* )) => (
+    {
+      use nom::Slice;
+      let input = $input;
+
+      match input.iter().next() {
+        Some(c) => {
+          if $submac!(*c, $($args)*) {
+            let res:nom::IResult<&[u8],u8> = nom::IResult::Done(input.slice(1..), *c);
+            res
+          }
+          else
+          {
+            nom::IResult::Error(error_position!(nom::ErrorKind::TakeWhile1, input))
+          }
+        },
+        None    => {
+          nom::IResult::Incomplete(nom::Needed::Size(1))
+        }
+      }
+    }
+  );
+  ($input:expr, $f:expr) => (
+    take_1!($input, call!($f));
+  );
+);
+
+mod header;
+mod top_line;
+
+pub use parser::header::header;
+pub use parser::top_line::top_line;
+
+use types::{PathSegment, HostPort, Host, Hostname, UriParameter, UriHeader, UriHeaders, SipUri,
+            AbsoluteUri, Uri, HierarchicalPath, Authority, UriPath, UserInfo, AbsolutePath,
+            Scheme, Method, Transport, UserParam, Version, RequestLine, StatusLine, TopLine,
+            Header, MediaMainType, MediaType, MediaFullType, MediaParameter, MediaRange,
+            GenericParam, AcceptParam, AcceptRange, Coding, Encoding, LanguageTag, LanguageRange,
+            Language, AlertParam, Qop, AuthenticationInfo, AuthParam, Algorithm, DigestResponse,
+            Credentials, CallId, Purpose, InfoParam, Info, NameAddr, ContactParam, Target,
+            Contact, DispositionType, Handling, DispositionParam, ContentCoding, Day, Month, Date,
+            Time, DateTime, ErrorUri, FromParam, From, Priority, Domain, DigestChallenge,
+            Challenge, OptionTag, Route, ReplyTo, RetryAfterParam, RetryAfter, Server, ToParam,
+            To, Protocol, SentProtocol, Received, ViaParam, Via, WarningAgent, Warning};
+
+pub fn float(input: &[u8]) -> IResult<&[u8], f32> {
+    flat_map!(input,
+              recognize!(tuple!(opt!(alt!(tag!("+") | tag!("-"))),
+                                alt!(delimited!(digits, tag!("."), opt!(digits)) |
+                                     delimited!(opt!(digits), tag!("."), digits) |
+                                     digits),
+                                opt!(complete!(tuple!(alt!(tag!("e") | tag!("E")),
+                                                      opt!(alt!(tag!("+") | tag!("-"))),
+                                                      digit))))),
+              parse_to!(f32))
+}
+
+fn is_mark(c: u8) -> bool {
+    c == b'-' || c == b'_' || c == b'.' || c == b'!' || c == b'~' || c == b'*' || c == b'\'' ||
+    c == b'(' || c == b')'
+}
+
+fn is_unreserved(c: u8) -> bool {
+    nom::is_alphanumeric(c) || is_mark(c)
+}
+
+fn is_reserved(c: u8) -> bool {
+    c == b';' || c == b'/' || c == b'?' || c == b':' || c == b'@' || c == b'&' || c == b'=' ||
+    c == b'+' || c == b'$' || c == b','
+}
+
+fn is_user_unreserved(c: u8) -> bool {
+    is_unreserved(c) || c == b'&' || c == b'=' || c == b'+' || c == b'$' || c == b',' ||
+    c == b';' || c == b'?' || c == b'/'
+}
+
+fn is_password_unreserved(c: u8) -> bool {
+    is_unreserved(c) || c == b'=' || c == b'+' || c == b'$' || c == b','
+}
+
+fn is_domain_label(c: u8) -> bool {
+    nom::is_alphanumeric(c) || c == b'-'
+}
+
+fn is_token(c: u8) -> bool {
+    nom::is_alphanumeric(c) || c == b'-' || c == b'.' || c == b'!' || c == b'%' ||
+    c == b'*' || c == b'_' || c == b'+' || c == b'`' || c == b'\'' || c == b'~'
+}
+
+fn is_word(c: u8) -> bool {
+    is_token(c) || c == b'(' || c == b')' || c == b'<' || c == b'>' || c == b':' ||
+    c == b'\\' || c == b'"' || c == b'/' || c == b'[' || c == b']' ||
+    c == b'?' || c == b'{' || c == b'}'
+}
+
+fn is_lhex_digit(c: u8) -> bool {
+    nom::is_digit(c) || (c >= b'a' && c <= b'f')
+}
+
+named!(token<Vec<u8>>, many1!(take_1!(is_token)));
+named!(word<Vec<u8>>, many1!(take_1!(is_word)));
+
+named!(method<Method>, alt!(
+// RFC 3261
+    tag!("INVITE") => { |_|  Method::INVITE } |
+    tag!("ACK") => { |_|  Method::ACK } |
+    tag!("OPTIONS") => { |_|  Method::OPTIONS } |
+    tag!("BYE") => { |_|  Method::BYE } |
+    tag!("CANCEL") => { |_|  Method::CANCEL } |
+    tag!("REGISTER") => { |_|  Method::REGISTER } |
+// Extensions
+    tag!("MESSAGE") => { |_|  Method::MESSAGE } |
+    tag!("REFER") => { |_|  Method::REFER } |
+    tag!("SUBSCRIBE") => { |_|  Method::SUBSCRIBE } |
+    tag!("NOTIFY") => { |_|  Method::NOTIFY } |
+    token  => { |method| Method::Extension(method) }
+));
+
+named!(alpha<&[u8], u8>, take_1!(nom::is_alphabetic));
+named!(alphanumeric<&[u8], u8>, take_1!(nom::is_alphanumeric));
+named!(digit<&[u8], u8>, take_1!(nom::is_digit));
+named!(hex<&[u8], u8>, take_1!(nom::is_hex_digit));
+named!(lhex<&[u8], u8>, take_1!(is_lhex_digit));
+
+fn escaped(input: &[u8]) -> IResult<&[u8], u8> {
+    let result = preceded!(input, tag!(b"%"), pair!(hex, hex));
+
+    match result {
+        IResult::Done(left, (a, b)) => {
+            let value: u8 = ((a - (b'0' as u8)) << 4) + (b - b'0');
+            IResult::Done(left, value)
+        }
+        IResult::Incomplete(a) => IResult::Incomplete(a),
+        IResult::Error(a) => IResult::Error(a),
+    }
+}
+
+named!(user_unreserved<&[u8], u8>, take_1!(is_user_unreserved));
+named!(password_unreserved<&[u8], u8>, take_1!(is_password_unreserved));
+
+// The BNF splits unreserved and user unreserved, but that's just a waste
+named!(user<&[u8], Vec<u8>>, many1!(alt!(
+    user_unreserved |
+    escaped)));
+
+named!(password<&[u8], Vec<u8>>, many1!(alt!(
+    password_unreserved |
+    escaped)));
+
+named!(userinfo<&[u8], (Vec<u8>, Option<Vec<u8>>)>, terminated!(
+        pair!(
+        user,
+        opt!(preceded!(tag!(b":"), password))),
+    tag!(b"@")));
+
+named!(domain_label<&[u8], Vec<u8>>, alt!(
+    alphanumerics => { |a : &[u8]| a.to_vec() } |
+    tuple!(
+        alphanumeric,
+        take_while1!(is_domain_label),
+        alphanumeric) => { |(a, b, c) : (u8, &[u8], u8)| {
+               let mut v = Vec::with_capacity(b.len() + 2);
+               v.push(a);
+               v.extend_from_slice(b);
+               v.push(c);
+               v
+       }}));
+
+named!(top_label<&[u8], Vec<u8>>, alt!(
+    alphas => { |a : &[u8]| a.to_vec() } |
+    tuple!(
+        alpha,
+        take_while1!(is_domain_label))  => { |(a, b) : (u8, &[u8])| {
+               let mut v = Vec::with_capacity(b.len() + 2);
+               v.push(a);
+               v.extend_from_slice(b);
+               v
+        }}));
+
+named!(hostname<&[u8], Hostname>, tuple!(
+    many0!(terminated!(domain_label, tag!(b"."))),
+    terminated!(top_label, opt!(tag!(b".")))));
+
+fn number<O>(input: &[u8]) -> IResult<&[u8], O>
+    where O: std::str::FromStr
+{
+    match digits(input) {
+        IResult::Done(left, num_str) => {
+            if let Ok(num_utf8) = std::str::from_utf8(num_str) {
+                if let Ok(num_i) = num_utf8.parse::<O>() {
+                    IResult::Done(left, num_i)
+                } else {
+                    IResult::Error(Custom(1))
+                }
+            } else {
+                IResult::Error(Custom(2))
+            }
+        }
+        IResult::Error(e) => IResult::Error(e),
+        IResult::Incomplete(i) => IResult::Incomplete(i),
+    }
+}
+
+named!(ipv4_address<&[u8], (u8, u8, u8, u8)>, tuple!(
+    number,
+    preceded!(tag!(b"."), number),
+    preceded!(tag!(b"."), number),
+    preceded!(tag!(b"."), number)));
+
+fn is_ipv6_char(c: u8) -> bool {
+    nom::is_hex_digit(c) || c == b':'
+}
+
+named!(ipv6_address<&[u8], Vec<u8>>, delimited!(
+    tag!(b"["),
+    many1!(take_1!(is_ipv6_char)),
+    tag!(b"]")));
+
+named!(host<Host>, alt!(
+    hostname => { |h| Host::Hostname(h) } |
+    ipv4_address => { |(a, b, c, d)| Host::Ipv4Address(a,b,c,d) } |
+    ipv6_address => { |i| Host::Ipv6Address(i) }
+));
+
+named!(hostport<&[u8], HostPort>, tuple!(
+    host,
+    opt!(preceded!(tag!(":"), number))));
+
+named!(transport_param<Transport>, alt!(
+    tag!("tcp") => { |_| Transport::Tcp } |
+    tag!("udp") => { |_| Transport::Udp } |
+    tag!("sctp") => { |_| Transport::Sctp } |
+    tag!("tls") => { |_| Transport::Tls } |
+    token => { |token| Transport::Other(token) }
+));
+
+named!(user_param<UserParam>, alt!(
+    tag!("phone") => { |_| UserParam::Phone } |
+    tag!("ip") => { |_| UserParam::Ip } |
+    token => { |token| UserParam::Other(token) }));
+
+fn is_param_unreserved(c: u8) -> bool {
+    is_unreserved(c) || c == b'[' || c == b']' || c == b'/' || c == b':' || c == b'&' ||
+    c == b'+' || c == b'$'
+}
+
+named!(param<&[u8], Vec<u8>>, many1!(alt!(
+    take_1!(is_param_unreserved) |
+    escaped)));
+
+named!(uri_parameter<UriParameter>, alt!(
+    preceded!(tag!("transport="), transport_param) => {
+       |transport| UriParameter::Transport(transport)
+    } |
+    preceded!(tag!("user="), user_param) => { |user| UriParameter::User(user) } |
+    preceded!(tag!("method="), method) => { |method| UriParameter::Method(method) } |
+    preceded!(tag!(b"ttl="), number) => { |ttl| UriParameter::Ttl(ttl) } |
+    preceded!(tag!("maddr="), recognize!(host)) => {
+        |host : &[u8]| UriParameter::Maddr(host.to_vec())
+    } |
+    tag!("lr") => { |ttl| UriParameter::Lr } |
+    pair!(param, opt!(preceded!(tag!(b"="), param))) => {
+        |(key, value)|
+        UriParameter::Other {
+            key: key,
+            value: value
+        }
+    }
+));
+
+named!(uri_parameters<&[u8], Vec<UriParameter>>, many0!(
+    preceded!(char!(';'), uri_parameter)));
+
+fn is_header_unreserved(c: u8) -> bool {
+    is_unreserved(c) || c == b'[' || c == b']' || c == b'/' || c == b'?' || c == b':' ||
+    c == b'+' || c == b'$'
+}
+
+named!(hname<&[u8], Vec<u8>>, many1!(alt!(
+    take_1!(is_header_unreserved) |
+    escaped)));
+
+named!(hvalue<&[u8], Vec<u8>>, many1!(alt!(
+    take_1!(is_header_unreserved) |
+    escaped)));
+
+named!(uri_header<&[u8], UriHeader>, separated_pair!(
+    hname,
+    tag!(b"="),
+    hvalue));
+
+named!(uri_headers<&[u8], UriHeaders>, preceded!(
+    char!('?'),
+    separated_nonempty_list!(
+       tag!(b"&"),
+        uri_header)));
+
+type _SipUri = (Option<UserInfo>, HostPort, Vec<UriParameter>, Option<UriHeaders>);
+
+named!(sip_uri<&[u8], _SipUri>, preceded!(
+    tag!("sip:"),
+    tuple!(
+        opt!(userinfo),
+        hostport,
+        uri_parameters,
+        opt!(uri_headers)
+        )));
+
+named!(sips_uri<&[u8], _SipUri>, preceded!(
+    tag!("sips:"),
+    tuple!(
+        opt!(userinfo),
+        hostport,
+        uri_parameters,
+        opt!(uri_headers)
+        )));
+
+type _SipUriNp = (Option<UserInfo>, HostPort);
+
+named!(sip_uri_np<&[u8], _SipUriNp>, preceded!(
+    tag!("sip:"),
+    tuple!(
+        opt!(userinfo),
+        hostport
+        )));
+
+named!(sips_uri_np<&[u8], _SipUriNp>, preceded!(
+    tag!("sips:"),
+    tuple!(
+        opt!(userinfo),
+        hostport
+        )));
+
+fn is_scheme_unreserved(c: u8) -> bool {
+    nom::is_alphanumeric(c) || c == b'+' || c == b'-' || c == b'.'
+}
+
+named!(scheme<&[u8], Scheme>, tuple!(
+    alpha,
+    many0!(take_1!(is_scheme_unreserved))));
+
+fn is_path_char(c: u8) -> bool {
+    is_unreserved(c) || c == b':' || c == b'@' || c == b'&' || c == b'=' || c == b'+' ||
+    c == b'$' || c == b','
+}
+
+named!(path_param<&[u8], Vec<u8>>, many0!(alt!(
+    escaped |
+    take_1!(is_path_char))));
+
+named!(path_segment<&[u8], PathSegment>, pair!(
+    many0!(take_1!(is_path_char)),
+    opt!(preceded!(tag!(b";"), path_param))));
+
+named!(srvr<&[u8], (Option<UserInfo>, HostPort)>, tuple!(
+        opt!(userinfo),
+        hostport));
+
+fn is_reg_name_char(c: u8) -> bool {
+    is_unreserved(c) || c == b':' || c == b';' || c == b'$' || c == b'@' || c == b'&' ||
+    c == b'=' || c == b'+' || c == b','
+}
+
+named!(reg_name<&[u8], Vec<u8>>, many1!(alt!(
+    take_1!(is_reg_name_char) |
+    escaped)));
+
+named!(authority<&[u8], Authority>, alt!(
+    srvr => { |(u, h)| Authority::Server { userinfo: u, hostport: h } } |
+    reg_name => { |n| Authority::Name(n) } ));
+
+named!(abs_path<&[u8], AbsolutePath>, many1!(
+    preceded!(char!('/'), path_segment)));
+
+named!(net_path<&[u8], (Authority, Option<AbsolutePath>)>, preceded!(tag!("//"), pair!(
+    authority,
+    opt!(abs_path))));
+
+named!(query<&[u8], Vec<u8>>, many0!(uric));
+
+named!(hier_part<&[u8], (HierarchicalPath, Option<Vec<u8>>)>, tuple!(
+    alt!(
+        net_path => { |(a, p)| HierarchicalPath::Network{ authority: a, path: p } } |
+        abs_path => { |p| HierarchicalPath::Absolute(p) }
+    ),
+    opt!(preceded!(char!('?'), query))));
+
+fn is_uri_char_no_slash(c: u8) -> bool {
+    is_unreserved(c) || c == b';' || c == b'?' || c == b':' || c == b'@' || c == b'&' ||
+    c == b'=' || c == b'+' || c == b'$' || c == b','
+}
+
+named!(uric_no_slash<&[u8], u8>, alt!(
+    take_1!(is_uri_char_no_slash) |
+    escaped));
+
+fn is_uri_char(c: u8) -> bool {
+    is_unreserved(c) || is_reserved(c)
+}
+
+named!(uric<&[u8], u8>, alt!(
+        take_1!(is_uri_char) |
+        escaped));
+
+named!(opaque_part<&[u8], (u8, Vec<u8>)>, pair!(
+    uric_no_slash,
+    many0!(uric)));
+
+named!(absolute_uri<&[u8], AbsoluteUri>, separated_pair!(
+    scheme,
+    char!(':'),
+    alt!(
+      hier_part => { |(h,q)| UriPath::Hierarchical { path: h, query: q } } |
+      opaque_part => { |(b, o)| UriPath::Opaque(b, o) }
+    )));
+
+named!(uri<&[u8], Uri>, alt!(
+    sip_uri => { |(u, hp, p, h)| Uri::Sip(SipUri {
+        user_info: u,
+        host_port: hp,
+        params: p,
+        headers: h }) } |
+    sips_uri => { |(u, hp, p, h)| Uri::Sips(SipUri {
+        user_info: u,
+        host_port: hp,
+        params: p,
+        headers: h }) } |
+    absolute_uri => { |(s, p)| Uri::Generic {
+        scheme: s,
+        path: p } }
+));
+
+// Variant without URI parameters or header parameters
+named!(uri_np<&[u8], Uri>, alt!(
+    sip_uri_np => { |(u, hp)| Uri::Sip(SipUri {
+        user_info: u,
+        host_port: hp,
+        params: vec![],
+        headers: None }) } |
+    sips_uri_np => { |(u, hp)| Uri::Sips(SipUri {
+        user_info: u,
+        host_port: hp,
+        params: vec![],
+        headers: None }) } |
+    absolute_uri => { |(s, p)| Uri::Generic {
+        scheme: s,
+        path: p } }
+));
+
+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));
+
+fn is_qdtext_char(c: u8) -> bool {
+    c == 0x21 || (c >= 0x23 && c <= 0x5b) || (c >= 0x5d && c <= 0x7e)
+}
+
+named!(qdtext<u8>, take_1!(is_qdtext_char));
+
+fn is_qdpair_char(c: u8) -> bool {
+    c <= 0x09 || c == 0x0B || c == 0x0C || (c >= 0x0E && c <= 0x7f)
+}
+
+named!(qdpair<u8>, preceded!(
+       tag!("\\"),
+       take_1!(is_qdpair_char)));
+
+named!(quoted_string<Vec<u8>>, delimited!(
+       tag!(b"\""),
+       many0!(alt!(
+               qdtext |
+               qdpair)),
+       tag!(b"\"")));
diff --git a/src/parser/top_line.rs b/src/parser/top_line.rs
new file mode 100644 (file)
index 0000000..18b4c01
--- /dev/null
@@ -0,0 +1,45 @@
+use parser::*;
+
+named!(sip_version<&[u8], Version>, preceded!(
+    tag!("SIP/"),
+    dbg_dmp!(separated_pair!(
+       dbg_dmp!(number),
+       dbg_dmp!(tag!(b".")),
+       dbg_dmp!(number)))));
+
+named!(request_line<&[u8], (Method, Uri, Version)>, tuple!(
+    method,
+    delimited!(
+        tag!(" "),
+        uri,
+        tag!(" ")),
+    sip_version));
+
+fn is_reason_phrase_char(c: u8) -> bool {
+    is_reserved(c) || is_unreserved(c) || c == b' ' || c == b'\t'
+}
+
+named!(reason_phrase<Vec<u8>>, many0!(alt!(
+       escaped |
+       take_1!(is_reason_phrase_char))));
+
+named!(status_line<&[u8], (Version, u16, Vec<u8>)>, tuple!(
+       sip_version,
+       delimited!(
+               tag!(" "),
+               number,
+               tag!(" ")
+       ),
+       reason_phrase));
+
+named!(pub top_line<TopLine>, alt!(
+       request_line => { |(m,u,v)| TopLine::RequestLine(RequestLine {
+               method: m,
+               uri: u,
+               version: v
+       })} |
+       status_line => { |(v, c, r)| TopLine::StatusLine(StatusLine {
+               version: v,
+               code: c,
+               reason: r
+       })}));