diff --git a/src/headers/header.rs b/src/headers/header.rs index 81f99e7..4c6c23d 100644 --- a/src/headers/header.rs +++ b/src/headers/header.rs @@ -63,6 +63,11 @@ pub enum Header { Warning(Warning), WwwAuthenticate(WwwAuthenticate), } +impl Header { + pub fn other, S2: Into>(name: S1, value: S2) -> Header { + Header::Other(name.into(), value.into()) + } +} impl std::fmt::Display for Header { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -154,41 +159,54 @@ pub mod tokenizer { Ok(Header::Authorization(Authorization::new(tokenizer.value))) } s if s.eq_ignore_ascii_case("CSeq") => Ok(Header::CSeq(CSeq::new(tokenizer.value))), - s if s.eq_ignore_ascii_case("Call-Id") => { + s if ["Call-Id", "i"].iter().any(|t| s.eq_ignore_ascii_case(t)) => { Ok(Header::CallId(CallId::new(tokenizer.value))) } s if s.eq_ignore_ascii_case("Call-Info") => { Ok(Header::CallInfo(CallInfo::new(tokenizer.value))) } - s if s.eq_ignore_ascii_case("Contact") => { + s if ["Contact", "m"].iter().any(|t| s.eq_ignore_ascii_case(t)) => { Ok(Header::Contact(Contact::new(tokenizer.value))) } s if s.eq_ignore_ascii_case("Content-Disposition") => Ok( Header::ContentDisposition(ContentDisposition::new(tokenizer.value)), ), - s if s.eq_ignore_ascii_case("Content-Encoding") => Ok(Header::ContentEncoding( - ContentEncoding::new(tokenizer.value), - )), + s if ["Content-Encoding", "e"] + .iter() + .any(|t| s.eq_ignore_ascii_case(t)) => + { + Ok(Header::ContentEncoding(ContentEncoding::new( + tokenizer.value, + ))) + } s if s.eq_ignore_ascii_case("Content-Language") => Ok(Header::ContentLanguage( ContentLanguage::new(tokenizer.value), )), - s if s.eq_ignore_ascii_case("Content-Length") => { + s if ["Content-Length", "l"] + .iter() + .any(|t| s.eq_ignore_ascii_case(t)) => + { Ok(Header::ContentLength(ContentLength::new(tokenizer.value))) } - s if s.eq_ignore_ascii_case("Content-Type") => { + s if ["Content-Type", "c"] + .iter() + .any(|t| s.eq_ignore_ascii_case(t)) => + { Ok(Header::ContentType(ContentType::new(tokenizer.value))) } s if s.eq_ignore_ascii_case("Date") => Ok(Header::Date(Date::new(tokenizer.value))), s if s.eq_ignore_ascii_case("Error-Info") => { Ok(Header::ErrorInfo(ErrorInfo::new(tokenizer.value))) } - s if s.eq_ignore_ascii_case("Event") => { + s if ["Event", "o"].iter().any(|t| s.eq_ignore_ascii_case(t)) => { Ok(Header::Event(Event::new(tokenizer.value))) } s if s.eq_ignore_ascii_case("Expires") => { Ok(Header::Expires(Expires::new(tokenizer.value))) } - s if s.eq_ignore_ascii_case("From") => Ok(Header::From(From::new(tokenizer.value))), + s if ["From", "f"].iter().any(|t| s.eq_ignore_ascii_case(t)) => { + Ok(Header::From(From::new(tokenizer.value))) + } s if s.eq_ignore_ascii_case("In-Reply-To") => { Ok(Header::InReplyTo(InReplyTo::new(tokenizer.value))) } @@ -234,23 +252,27 @@ pub mod tokenizer { s if s.eq_ignore_ascii_case("Server") => { Ok(Header::Server(Server::new(tokenizer.value))) } - s if s.eq_ignore_ascii_case("Subject") => { + s if ["Subject", "s"].iter().any(|t| s.eq_ignore_ascii_case(t)) => { Ok(Header::Subject(Subject::new(tokenizer.value))) } - s if s.eq_ignore_ascii_case("Supported") => { + s if ["Supported", "k"].iter().any(|t| s.eq_ignore_ascii_case(t)) => { Ok(Header::Supported(Supported::new(tokenizer.value))) } s if s.eq_ignore_ascii_case("Timestamp") => { Ok(Header::Timestamp(Timestamp::new(tokenizer.value))) } - s if s.eq_ignore_ascii_case("To") => Ok(Header::To(To::new(tokenizer.value))), + s if ["To", "t"].iter().any(|t| s.eq_ignore_ascii_case(t)) => { + Ok(Header::To(To::new(tokenizer.value))) + } s if s.eq_ignore_ascii_case("Unsupported") => { Ok(Header::Unsupported(Unsupported::new(tokenizer.value))) } s if s.eq_ignore_ascii_case("User-Agent") => { Ok(Header::UserAgent(UserAgent::new(tokenizer.value))) } - s if s.eq_ignore_ascii_case("Via") => Ok(Header::Via(Via::new(tokenizer.value))), + s if ["Via", "v"].iter().any(|t| s.eq_ignore_ascii_case(t)) => { + Ok(Header::Via(Via::new(tokenizer.value))) + } s if s.eq_ignore_ascii_case("Warning") => { Ok(Header::Warning(Warning::new(tokenizer.value))) } diff --git a/tests/message/message.rs b/tests/message/message.rs index 479098b..0ae812f 100644 --- a/tests/message/message.rs +++ b/tests/message/message.rs @@ -153,6 +153,121 @@ mod parser { ); } + #[test] + fn parser_compact_mode() { + assert_eq!( + SipMessage::try_from( + concat!( + "REGISTER sips:ss2.biloxi.example.com SIP/2.0\r\n", + "v: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashd92\r\n", + "Max-Forwards: 70\r\n", + "f: Bob ;tag=ja743ks76zlflH\r\n", + "t: Bob \r\n", + "i: 1j9FpLxk3uxtm8tn@biloxi.example.com\r\n", + "CSeq: 2 REGISTER\r\n", + "m: \r\n", + "Authorization: Digest username=\"bob\", realm=\"atlanta.example.com\" nonce=\"ea9c8e88df84f1cec4341ae6cbe5a359\", opaque=\"\" uri=\"sips:ss2.biloxi.example.com\", response=\"dfe56131d1958046689d83306477ecc\"\r\n", + "l: 0\r\n\r\n", + "a simple body\r\n", + "and some complex: characters\r\n", + "Ok?" + ).as_bytes() + ), + Ok(SipMessage::Request(Request { + method: common::method::Method::Register, + uri: uri::Uri { + scheme: Some(uri::scheme::Scheme::Sips), + auth: None, + host_with_port: uri::HostWithPort { + host: uri::Host::Domain("ss2.biloxi.example.com".into()), + port: None + }, + params: vec![], + headers: vec![] + }, + version: common::version::Version::V2, + headers: vec![ + Via::new("SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashd92").into(), + MaxForwards::new("70").into(), + From::new("Bob ;tag=ja743ks76zlflH").into(), + To::new("Bob ").into(), + CallId::new("1j9FpLxk3uxtm8tn@biloxi.example.com").into(), + CSeq::new("2 REGISTER").into(), + Contact::new("").into(), + Authorization::new("Digest username=\"bob\", realm=\"atlanta.example.com\" nonce=\"ea9c8e88df84f1cec4341ae6cbe5a359\", opaque=\"\" uri=\"sips:ss2.biloxi.example.com\", response=\"dfe56131d1958046689d83306477ecc\"").into(), + ContentLength::new("0").into(), + ].into(), + body: concat!( + "a simple body\r\n", + "and some complex: characters\r\n", + "Ok?" + ).as_bytes().to_vec() + })), + ); + } + + #[test] + fn parser_compact_mode_all() { + assert_eq!( + SipMessage::try_from( + concat!( + "REGISTER sips:ss2.biloxi.example.com SIP/2.0\r\n", + "a: Accept-Contact\r\n", + "b: Referred-By\r\n", + "c: Content-Type\r\n", + "e: Content-Encoding\r\n", + "f: From\r\n", + "i: Call-ID\r\n", + "k: Supported\r\n", + "l: Content-Length\r\n", + "m: Contact\r\n", + "o: Event\r\n", + "r: Refer-To\r\n", + "s: Subject\r\n", + "t: To\r\n", + "u: Allow-Events\r\n", + "v: Via\r\n", + "\r\n", + "Body", + ) + .as_bytes() + ), + Ok(SipMessage::Request(Request { + method: common::method::Method::Register, + uri: uri::Uri { + scheme: Some(uri::scheme::Scheme::Sips), + auth: None, + host_with_port: uri::HostWithPort { + host: uri::Host::Domain("ss2.biloxi.example.com".into()), + port: None + }, + params: vec![], + headers: vec![] + }, + version: common::version::Version::V2, + headers: vec![ + Header::other("a", "Accept-Contact"), + Header::other("b", "Referred-By"), + ContentType::new("Content-Type").into(), + ContentEncoding::new("Content-Encoding").into(), + From::new("From").into(), + CallId::new("Call-ID").into(), + Supported::new("Supported").into(), + ContentLength::new("Content-Length").into(), + Contact::new("Contact").into(), + Event::new("Event").into(), + Header::other("r", "Refer-To"), + Subject::new("Subject").into(), + To::new("To").into(), + Header::other("u", "Allow-Events"), + Via::new("Via").into(), + ] + .into(), + body: b"Body".to_vec() + })), + ); + } + #[test] fn parser3() { assert_eq!(