1use crate::accept::{SipAccept, SipAcceptError};
8use crate::accept_encoding::{SipAcceptEncoding, SipAcceptEncodingError};
9use crate::accept_language::{SipAcceptLanguage, SipAcceptLanguageError};
10use crate::auth::{SipAuthError, SipAuthValue};
11use crate::contact::ContactValue;
12use crate::header_addr::{ParseSipHeaderAddrError, SipHeaderAddr};
13use crate::history_info::{HistoryInfo, HistoryInfoError};
14use crate::security::{SipSecurity, SipSecurityError};
15use crate::uri_info::{UriInfo, UriInfoError};
16use crate::via::{SipVia, SipViaError};
17use crate::warning::{SipWarning, SipWarningError};
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct ParseSipHeaderError(pub String);
22
23impl std::fmt::Display for ParseSipHeaderError {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 write!(f, "unknown SIP header: {}", self.0)
26 }
27}
28
29impl std::error::Error for ParseSipHeaderError {}
30
31define_header_enum! {
32 error_type: ParseSipHeaderError,
33 pub enum SipHeader {
39 Accept => "Accept",
41 AcceptContact => "Accept-Contact",
43 AcceptEncoding => "Accept-Encoding",
45 AcceptLanguage => "Accept-Language",
47 AcceptResourcePriority => "Accept-Resource-Priority",
49 AdditionalIdentity => "Additional-Identity",
51 AlertInfo => "Alert-Info",
53 AlertmsgError => "AlertMsg-Error",
55 Allow => "Allow",
57 AllowEvents => "Allow-Events",
59 AnswerMode => "Answer-Mode",
61 AttestationInfo => "Attestation-Info",
63 AuthenticationInfo => "Authentication-Info",
65 Authorization => "Authorization",
67 CallId => "Call-ID",
69 CallInfo => "Call-Info",
71 CellularNetworkInfo => "Cellular-Network-Info",
73 Contact => "Contact",
75 ContentDisposition => "Content-Disposition",
77 ContentEncoding => "Content-Encoding",
79 ContentId => "Content-ID",
81 ContentLanguage => "Content-Language",
83 ContentLength => "Content-Length",
85 ContentType => "Content-Type",
87 Cseq => "CSeq",
89 Date => "Date",
91 DcInfo => "DC-Info",
93 Encryption => "Encryption",
95 ErrorInfo => "Error-Info",
97 Event => "Event",
99 Expires => "Expires",
101 FeatureCaps => "Feature-Caps",
103 FlowTimer => "Flow-Timer",
105 From => "From",
107 Geolocation => "Geolocation",
109 GeolocationError => "Geolocation-Error",
111 GeolocationRouting => "Geolocation-Routing",
113 Hide => "Hide",
115 HistoryInfo => "History-Info",
117 Identity => "Identity",
119 IdentityInfo => "Identity-Info",
121 InfoPackage => "Info-Package",
123 InReplyTo => "In-Reply-To",
125 Join => "Join",
127 MaxBreadth => "Max-Breadth",
129 MaxForwards => "Max-Forwards",
131 MimeVersion => "MIME-Version",
133 MinExpires => "Min-Expires",
135 MinSe => "Min-SE",
137 Organization => "Organization",
139 OriginationId => "Origination-Id",
141 PAccessNetworkInfo => "P-Access-Network-Info",
143 PAnswerState => "P-Answer-State",
145 PAssertedIdentity => "P-Asserted-Identity",
147 PAssertedService => "P-Asserted-Service",
149 PAssociatedUri => "P-Associated-URI",
151 PCalledPartyId => "P-Called-Party-ID",
153 PChargeInfo => "P-Charge-Info",
155 PChargingFunctionAddresses => "P-Charging-Function-Addresses",
157 PChargingVector => "P-Charging-Vector",
159 PDcsTracePartyId => "P-DCS-Trace-Party-ID",
161 PDcsOsps => "P-DCS-OSPS",
163 PDcsBillingInfo => "P-DCS-Billing-Info",
165 PDcsLaes => "P-DCS-LAES",
167 PDcsRedirect => "P-DCS-Redirect",
169 PEarlyMedia => "P-Early-Media",
171 PMediaAuthorization => "P-Media-Authorization",
173 PPreferredIdentity => "P-Preferred-Identity",
175 PPreferredService => "P-Preferred-Service",
177 PPrivateNetworkIndication => "P-Private-Network-Indication",
179 PProfileKey => "P-Profile-Key",
181 PRefusedUriList => "P-Refused-URI-List",
183 PServedUser => "P-Served-User",
185 PUserDatabase => "P-User-Database",
187 PVisitedNetworkId => "P-Visited-Network-ID",
189 Path => "Path",
191 PermissionMissing => "Permission-Missing",
193 PolicyContact => "Policy-Contact",
195 PolicyId => "Policy-ID",
197 Priority => "Priority",
199 PriorityShare => "Priority-Share",
201 PriorityVerstat => "Priority-Verstat",
203 PrivAnswerMode => "Priv-Answer-Mode",
205 Privacy => "Privacy",
207 ProxyAuthenticate => "Proxy-Authenticate",
209 ProxyAuthorization => "Proxy-Authorization",
211 ProxyRequire => "Proxy-Require",
213 Rack => "RAck",
215 Reason => "Reason",
217 ReasonPhrase => "Reason-Phrase",
219 RecordRoute => "Record-Route",
221 RecvInfo => "Recv-Info",
223 ReferEventsAt => "Refer-Events-At",
225 ReferSub => "Refer-Sub",
227 ReferTo => "Refer-To",
229 ReferredBy => "Referred-By",
231 RejectContact => "Reject-Contact",
233 RelayedCharge => "Relayed-Charge",
235 Replaces => "Replaces",
237 ReplyTo => "Reply-To",
239 RequestDisposition => "Request-Disposition",
241 Require => "Require",
243 ResourcePriority => "Resource-Priority",
245 ResourceShare => "Resource-Share",
247 ResponseKey => "Response-Key",
249 ResponseSource => "Response-Source",
251 RestorationInfo => "Restoration-Info",
253 RetryAfter => "Retry-After",
255 Route => "Route",
257 Rseq => "RSeq",
259 SecurityClient => "Security-Client",
261 SecurityServer => "Security-Server",
263 SecurityVerify => "Security-Verify",
265 Server => "Server",
267 ServiceInteractInfo => "Service-Interact-Info",
269 ServiceRoute => "Service-Route",
271 SessionExpires => "Session-Expires",
273 SessionId => "Session-ID",
275 SipEtag => "SIP-ETag",
277 SipIfMatch => "SIP-If-Match",
279 Subject => "Subject",
281 SubscriptionState => "Subscription-State",
283 Supported => "Supported",
285 SuppressIfMatch => "Suppress-If-Match",
287 TargetDialog => "Target-Dialog",
289 Timestamp => "Timestamp",
291 To => "To",
293 TriggerConsent => "Trigger-Consent",
295 Unsupported => "Unsupported",
297 UserAgent => "User-Agent",
299 UserToUser => "User-to-User",
301 Via => "Via",
303 Warning => "Warning",
305 WwwAuthenticate => "WWW-Authenticate",
307 #[cfg(feature = "draft")]
310 Diversion => "Diversion",
311 #[cfg(feature = "draft")]
313 RemotePartyId => "Remote-Party-ID",
314 }
315}
316
317const COMPACT_FORMS: &[(u8, SipHeader)] = &[
322 (b'a', SipHeader::AcceptContact),
323 (b'b', SipHeader::ReferredBy),
324 (b'c', SipHeader::ContentType),
325 (b'd', SipHeader::RequestDisposition),
326 (b'e', SipHeader::ContentEncoding),
327 (b'f', SipHeader::From),
328 (b'i', SipHeader::CallId),
329 (b'j', SipHeader::RejectContact),
330 (b'k', SipHeader::Supported),
331 (b'l', SipHeader::ContentLength),
332 (b'm', SipHeader::Contact),
333 (b'n', SipHeader::IdentityInfo),
334 (b'o', SipHeader::Event),
335 (b'r', SipHeader::ReferTo),
336 (b's', SipHeader::Subject),
337 (b't', SipHeader::To),
338 (b'u', SipHeader::AllowEvents),
339 (b'v', SipHeader::Via),
340 (b'x', SipHeader::SessionExpires),
341 (b'y', SipHeader::Identity),
342];
343
344impl SipHeader {
345 pub fn from_compact(ch: u8) -> Option<Self> {
349 let lower = ch.to_ascii_lowercase();
350 COMPACT_FORMS
351 .iter()
352 .find(|(c, _)| *c == lower)
353 .map(|(_, h)| *h)
354 }
355
356 pub fn compact_form(&self) -> Option<char> {
358 COMPACT_FORMS
359 .iter()
360 .find(|(_, h)| h == self)
361 .map(|(c, _)| *c as char)
362 }
363
364 pub fn is_multi_valued(&self) -> bool {
369 if matches!(
370 self,
371 Self::Via
373 | Self::Route
374 | Self::RecordRoute
375 | Self::Contact
376 | Self::Allow
377 | Self::Supported
378 | Self::Require
379 | Self::ProxyRequire
380 | Self::Unsupported
381 | Self::Authorization
382 | Self::ProxyAuthorization
383 | Self::WwwAuthenticate
384 | Self::ProxyAuthenticate
385 | Self::Warning
386 | Self::ErrorInfo
387 | Self::CallInfo
388 | Self::AlertInfo
389 | Self::Accept
390 | Self::AcceptEncoding
391 | Self::AcceptLanguage
392 | Self::ContentEncoding
393 | Self::ContentLanguage
394 | Self::InReplyTo
395 | Self::PAssertedIdentity
397 | Self::PPreferredIdentity
398 | Self::AllowEvents
400 | Self::SecurityClient
402 | Self::SecurityServer
403 | Self::SecurityVerify
404 | Self::Path
406 | Self::ServiceRoute
408 | Self::HistoryInfo
410 ) {
411 return true;
412 }
413
414 #[cfg(feature = "draft")]
415 if matches!(
416 self,
417 Self::Diversion
419 | Self::RemotePartyId
421 ) {
422 return true;
423 }
424
425 false
426 }
427
428 pub fn parse_name(name: &str) -> Result<Self, ParseSipHeaderError> {
433 if name.len() == 1 {
434 if let Some(h) = Self::from_compact(name.as_bytes()[0]) {
435 return Ok(h);
436 }
437 }
438 name.parse()
439 }
440}
441
442pub trait SipHeaderLookup {
468 fn sip_header_str(&self, name: &str) -> Option<&str>;
470
471 fn sip_header(&self, name: SipHeader) -> Option<&str> {
473 self.sip_header_str(name.as_str())
474 }
475
476 fn sip_header_all_str<'a>(&'a self, name: &str) -> Vec<&'a str> {
484 self.sip_header_str(name)
485 .into_iter()
486 .collect()
487 }
488
489 fn sip_header_all(&self, name: SipHeader) -> Vec<&str> {
491 self.sip_header_all_str(name.as_str())
492 }
493
494 fn call_info(&self) -> Result<Option<UriInfo>, UriInfoError> {
498 match self.sip_header(SipHeader::CallInfo) {
499 Some(s) => UriInfo::parse(s).map(Some),
500 None => Ok(None),
501 }
502 }
503
504 fn history_info(&self) -> Result<Option<HistoryInfo>, HistoryInfoError> {
508 match self.sip_header(SipHeader::HistoryInfo) {
509 Some(s) => HistoryInfo::parse(s).map(Some),
510 None => Ok(None),
511 }
512 }
513
514 fn p_asserted_identity(&self) -> Result<Vec<SipHeaderAddr>, ParseSipHeaderAddrError> {
519 parse_addr_list(self.sip_header_all(SipHeader::PAssertedIdentity))
520 }
521
522 fn p_preferred_identity(&self) -> Result<Vec<SipHeaderAddr>, ParseSipHeaderAddrError> {
524 parse_addr_list(self.sip_header_all(SipHeader::PPreferredIdentity))
525 }
526
527 fn route(&self) -> Result<Vec<SipHeaderAddr>, ParseSipHeaderAddrError> {
529 parse_addr_list(self.sip_header_all(SipHeader::Route))
530 }
531
532 fn record_route(&self) -> Result<Vec<SipHeaderAddr>, ParseSipHeaderAddrError> {
534 parse_addr_list(self.sip_header_all(SipHeader::RecordRoute))
535 }
536
537 fn path(&self) -> Result<Vec<SipHeaderAddr>, ParseSipHeaderAddrError> {
539 parse_addr_list(self.sip_header_all(SipHeader::Path))
540 }
541
542 fn service_route(&self) -> Result<Vec<SipHeaderAddr>, ParseSipHeaderAddrError> {
544 parse_addr_list(self.sip_header_all(SipHeader::ServiceRoute))
545 }
546
547 fn contact(&self) -> Result<Vec<ContactValue>, ParseSipHeaderAddrError> {
552 match self.sip_header(SipHeader::Contact) {
553 Some(s) => crate::contact::parse_contact_list(s),
554 None => Ok(Vec::new()),
555 }
556 }
557
558 fn alert_info(&self) -> Result<Option<UriInfo>, UriInfoError> {
560 match self.sip_header(SipHeader::AlertInfo) {
561 Some(s) => UriInfo::parse(s).map(Some),
562 None => Ok(None),
563 }
564 }
565
566 fn error_info(&self) -> Result<Option<UriInfo>, UriInfoError> {
568 match self.sip_header(SipHeader::ErrorInfo) {
569 Some(s) => UriInfo::parse(s).map(Some),
570 None => Ok(None),
571 }
572 }
573
574 fn allow(&self) -> Vec<&str> {
576 split_trim(self.sip_header(SipHeader::Allow))
577 }
578
579 fn supported(&self) -> Vec<&str> {
581 split_trim(self.sip_header(SipHeader::Supported))
582 }
583
584 fn require_header(&self) -> Vec<&str> {
586 split_trim(self.sip_header(SipHeader::Require))
587 }
588
589 fn proxy_require(&self) -> Vec<&str> {
591 split_trim(self.sip_header(SipHeader::ProxyRequire))
592 }
593
594 fn unsupported(&self) -> Vec<&str> {
596 split_trim(self.sip_header(SipHeader::Unsupported))
597 }
598
599 fn allow_events(&self) -> Vec<&str> {
601 split_trim(self.sip_header(SipHeader::AllowEvents))
602 }
603
604 fn content_encoding(&self) -> Vec<&str> {
606 split_trim(self.sip_header(SipHeader::ContentEncoding))
607 }
608
609 fn content_language(&self) -> Vec<&str> {
611 split_trim(self.sip_header(SipHeader::ContentLanguage))
612 }
613
614 fn in_reply_to(&self) -> Vec<&str> {
616 split_trim(self.sip_header(SipHeader::InReplyTo))
617 }
618
619 fn via(&self) -> Result<Option<SipVia>, SipViaError> {
621 match self.sip_header(SipHeader::Via) {
622 Some(s) => SipVia::parse(s).map(Some),
623 None => Ok(None),
624 }
625 }
626
627 fn authorization(&self) -> Result<Vec<SipAuthValue>, SipAuthError> {
632 self.sip_header_all(SipHeader::Authorization)
633 .into_iter()
634 .map(|s| s.parse::<SipAuthValue>())
635 .collect()
636 }
637
638 fn proxy_authorization(&self) -> Result<Vec<SipAuthValue>, SipAuthError> {
640 self.sip_header_all(SipHeader::ProxyAuthorization)
641 .into_iter()
642 .map(|s| s.parse::<SipAuthValue>())
643 .collect()
644 }
645
646 fn www_authenticate(&self) -> Result<Vec<SipAuthValue>, SipAuthError> {
648 self.sip_header_all(SipHeader::WwwAuthenticate)
649 .into_iter()
650 .map(|s| s.parse::<SipAuthValue>())
651 .collect()
652 }
653
654 fn proxy_authenticate(&self) -> Result<Vec<SipAuthValue>, SipAuthError> {
656 self.sip_header_all(SipHeader::ProxyAuthenticate)
657 .into_iter()
658 .map(|s| s.parse::<SipAuthValue>())
659 .collect()
660 }
661
662 fn warning(&self) -> Result<Option<SipWarning>, SipWarningError> {
664 match self.sip_header(SipHeader::Warning) {
665 Some(s) => SipWarning::parse(s).map(Some),
666 None => Ok(None),
667 }
668 }
669
670 fn security_client(&self) -> Result<Option<SipSecurity>, SipSecurityError> {
672 match self.sip_header(SipHeader::SecurityClient) {
673 Some(s) => SipSecurity::parse(s).map(Some),
674 None => Ok(None),
675 }
676 }
677
678 fn security_server(&self) -> Result<Option<SipSecurity>, SipSecurityError> {
680 match self.sip_header(SipHeader::SecurityServer) {
681 Some(s) => SipSecurity::parse(s).map(Some),
682 None => Ok(None),
683 }
684 }
685
686 fn security_verify(&self) -> Result<Option<SipSecurity>, SipSecurityError> {
688 match self.sip_header(SipHeader::SecurityVerify) {
689 Some(s) => SipSecurity::parse(s).map(Some),
690 None => Ok(None),
691 }
692 }
693
694 fn accept(&self) -> Result<Option<SipAccept>, SipAcceptError> {
696 match self.sip_header(SipHeader::Accept) {
697 Some(s) => SipAccept::parse(s).map(Some),
698 None => Ok(None),
699 }
700 }
701
702 fn accept_encoding(&self) -> Result<Option<SipAcceptEncoding>, SipAcceptEncodingError> {
704 match self.sip_header(SipHeader::AcceptEncoding) {
705 Some(s) => SipAcceptEncoding::parse(s).map(Some),
706 None => Ok(None),
707 }
708 }
709
710 fn accept_language(&self) -> Result<Option<SipAcceptLanguage>, SipAcceptLanguageError> {
712 match self.sip_header(SipHeader::AcceptLanguage) {
713 Some(s) => SipAcceptLanguage::parse(s).map(Some),
714 None => Ok(None),
715 }
716 }
717
718 #[cfg(feature = "draft")]
720 fn diversion(&self) -> Result<Vec<SipHeaderAddr>, ParseSipHeaderAddrError> {
721 parse_addr_list(self.sip_header_all(SipHeader::Diversion))
722 }
723
724 #[cfg(feature = "draft")]
726 fn remote_party_id(&self) -> Result<Vec<SipHeaderAddr>, ParseSipHeaderAddrError> {
727 parse_addr_list(self.sip_header_all(SipHeader::RemotePartyId))
728 }
729}
730
731fn parse_addr_list(raw: Vec<&str>) -> Result<Vec<SipHeaderAddr>, ParseSipHeaderAddrError> {
732 if raw.is_empty() {
733 return Ok(Vec::new());
734 }
735 raw.into_iter()
736 .flat_map(|s| crate::split_comma_entries(s))
737 .map(|s| {
738 s.trim()
739 .parse::<SipHeaderAddr>()
740 })
741 .collect()
742}
743
744fn split_trim(raw: Option<&str>) -> Vec<&str> {
745 match raw {
746 Some(s) => crate::split_comma_entries(s)
747 .into_iter()
748 .map(str::trim)
749 .collect(),
750 None => Vec::new(),
751 }
752}
753
754impl SipHeaderLookup for std::collections::HashMap<String, String> {
755 fn sip_header_str(&self, name: &str) -> Option<&str> {
756 self.get(name)
757 .map(|s| s.as_str())
758 }
759}
760
761impl SipHeaderLookup for std::collections::HashMap<String, Vec<String>> {
762 fn sip_header_str(&self, name: &str) -> Option<&str> {
763 self.get(name)
764 .and_then(|v| v.first())
765 .map(|s| s.as_str())
766 }
767
768 fn sip_header_all_str(&self, name: &str) -> Vec<&str> {
769 self.get(name)
770 .map(|v| {
771 v.iter()
772 .map(|s| s.as_str())
773 .collect()
774 })
775 .unwrap_or_default()
776 }
777}
778
779#[cfg(test)]
780mod tests {
781 use super::*;
782 use std::collections::HashMap;
783
784 #[test]
785 fn display_round_trip() {
786 assert_eq!(SipHeader::CallInfo.to_string(), "Call-Info");
787 assert_eq!(SipHeader::HistoryInfo.to_string(), "History-Info");
788 assert_eq!(
789 SipHeader::PAssertedIdentity.to_string(),
790 "P-Asserted-Identity"
791 );
792 }
793
794 #[test]
795 fn as_ref_str() {
796 let h: &str = SipHeader::CallInfo.as_ref();
797 assert_eq!(h, "Call-Info");
798 }
799
800 #[test]
801 fn from_str_case_insensitive() {
802 assert_eq!("call-info".parse::<SipHeader>(), Ok(SipHeader::CallInfo));
803 assert_eq!("CALL-INFO".parse::<SipHeader>(), Ok(SipHeader::CallInfo));
804 assert_eq!(
805 "history-info".parse::<SipHeader>(),
806 Ok(SipHeader::HistoryInfo)
807 );
808 assert_eq!(
809 "p-asserted-identity".parse::<SipHeader>(),
810 Ok(SipHeader::PAssertedIdentity)
811 );
812 assert_eq!(
813 "P-ASSERTED-IDENTITY".parse::<SipHeader>(),
814 Ok(SipHeader::PAssertedIdentity)
815 );
816 }
817
818 #[test]
819 fn from_str_unknown() {
820 assert!("X-Custom"
821 .parse::<SipHeader>()
822 .is_err());
823 }
824
825 #[test]
826 fn from_str_round_trip_all() {
827 let variants = [
828 SipHeader::Accept,
829 SipHeader::AcceptContact,
830 SipHeader::AcceptEncoding,
831 SipHeader::AcceptLanguage,
832 SipHeader::AcceptResourcePriority,
833 SipHeader::AdditionalIdentity,
834 SipHeader::AlertInfo,
835 SipHeader::AlertmsgError,
836 SipHeader::Allow,
837 SipHeader::AllowEvents,
838 SipHeader::AnswerMode,
839 SipHeader::AttestationInfo,
840 SipHeader::AuthenticationInfo,
841 SipHeader::Authorization,
842 SipHeader::CallId,
843 SipHeader::CallInfo,
844 SipHeader::CellularNetworkInfo,
845 SipHeader::Contact,
846 SipHeader::ContentDisposition,
847 SipHeader::ContentEncoding,
848 SipHeader::ContentId,
849 SipHeader::ContentLanguage,
850 SipHeader::ContentLength,
851 SipHeader::ContentType,
852 SipHeader::Cseq,
853 SipHeader::Date,
854 SipHeader::DcInfo,
855 SipHeader::Encryption,
856 SipHeader::ErrorInfo,
857 SipHeader::Event,
858 SipHeader::Expires,
859 SipHeader::FeatureCaps,
860 SipHeader::FlowTimer,
861 SipHeader::From,
862 SipHeader::Geolocation,
863 SipHeader::GeolocationError,
864 SipHeader::GeolocationRouting,
865 SipHeader::Hide,
866 SipHeader::HistoryInfo,
867 SipHeader::Identity,
868 SipHeader::IdentityInfo,
869 SipHeader::InfoPackage,
870 SipHeader::InReplyTo,
871 SipHeader::Join,
872 SipHeader::MaxBreadth,
873 SipHeader::MaxForwards,
874 SipHeader::MimeVersion,
875 SipHeader::MinExpires,
876 SipHeader::MinSe,
877 SipHeader::Organization,
878 SipHeader::OriginationId,
879 SipHeader::PAccessNetworkInfo,
880 SipHeader::PAnswerState,
881 SipHeader::PAssertedIdentity,
882 SipHeader::PAssertedService,
883 SipHeader::PAssociatedUri,
884 SipHeader::PCalledPartyId,
885 SipHeader::PChargeInfo,
886 SipHeader::PChargingFunctionAddresses,
887 SipHeader::PChargingVector,
888 SipHeader::PDcsTracePartyId,
889 SipHeader::PDcsOsps,
890 SipHeader::PDcsBillingInfo,
891 SipHeader::PDcsLaes,
892 SipHeader::PDcsRedirect,
893 SipHeader::PEarlyMedia,
894 SipHeader::PMediaAuthorization,
895 SipHeader::PPreferredIdentity,
896 SipHeader::PPreferredService,
897 SipHeader::PPrivateNetworkIndication,
898 SipHeader::PProfileKey,
899 SipHeader::PRefusedUriList,
900 SipHeader::PServedUser,
901 SipHeader::PUserDatabase,
902 SipHeader::PVisitedNetworkId,
903 SipHeader::Path,
904 SipHeader::PermissionMissing,
905 SipHeader::PolicyContact,
906 SipHeader::PolicyId,
907 SipHeader::Priority,
908 SipHeader::PriorityShare,
909 SipHeader::PriorityVerstat,
910 SipHeader::PrivAnswerMode,
911 SipHeader::Privacy,
912 SipHeader::ProxyAuthenticate,
913 SipHeader::ProxyAuthorization,
914 SipHeader::ProxyRequire,
915 SipHeader::Rack,
916 SipHeader::Reason,
917 SipHeader::ReasonPhrase,
918 SipHeader::RecordRoute,
919 SipHeader::RecvInfo,
920 SipHeader::ReferEventsAt,
921 SipHeader::ReferSub,
922 SipHeader::ReferTo,
923 SipHeader::ReferredBy,
924 SipHeader::RejectContact,
925 SipHeader::RelayedCharge,
926 SipHeader::Replaces,
927 SipHeader::ReplyTo,
928 SipHeader::RequestDisposition,
929 SipHeader::Require,
930 SipHeader::ResourcePriority,
931 SipHeader::ResourceShare,
932 SipHeader::ResponseKey,
933 SipHeader::ResponseSource,
934 SipHeader::RestorationInfo,
935 SipHeader::RetryAfter,
936 SipHeader::Route,
937 SipHeader::Rseq,
938 SipHeader::SecurityClient,
939 SipHeader::SecurityServer,
940 SipHeader::SecurityVerify,
941 SipHeader::Server,
942 SipHeader::ServiceInteractInfo,
943 SipHeader::ServiceRoute,
944 SipHeader::SessionExpires,
945 SipHeader::SessionId,
946 SipHeader::SipEtag,
947 SipHeader::SipIfMatch,
948 SipHeader::Subject,
949 SipHeader::SubscriptionState,
950 SipHeader::Supported,
951 SipHeader::SuppressIfMatch,
952 SipHeader::TargetDialog,
953 SipHeader::Timestamp,
954 SipHeader::To,
955 SipHeader::TriggerConsent,
956 SipHeader::Unsupported,
957 SipHeader::UserAgent,
958 SipHeader::UserToUser,
959 SipHeader::Via,
960 SipHeader::Warning,
961 SipHeader::WwwAuthenticate,
962 ];
963 for v in variants {
964 let wire = v.to_string();
965 let parsed: SipHeader = wire
966 .parse()
967 .unwrap();
968 assert_eq!(parsed, v, "round-trip failed for {wire}");
969 }
970 }
971
972 fn headers_with(pairs: &[(&str, &str)]) -> HashMap<String, String> {
973 pairs
974 .iter()
975 .map(|(k, v)| (k.to_string(), v.to_string()))
976 .collect()
977 }
978
979 #[test]
980 fn sip_header_by_enum() {
981 let h = headers_with(&[("Call-Info", "<urn:x>;purpose=icon")]);
982 assert_eq!(
983 h.sip_header(SipHeader::CallInfo),
984 Some("<urn:x>;purpose=icon")
985 );
986 }
987
988 #[test]
989 fn call_info_raw_lookup() {
990 let h = headers_with(&[(
991 "Call-Info",
992 "<urn:emergency:uid:callid:test:bcf.example.com>;purpose=emergency-CallId",
993 )]);
994 assert_eq!(
995 h.sip_header(SipHeader::CallInfo),
996 Some("<urn:emergency:uid:callid:test:bcf.example.com>;purpose=emergency-CallId")
997 );
998 }
999
1000 #[test]
1001 fn call_info_typed() {
1002 let h = headers_with(&[(
1003 "Call-Info",
1004 "<urn:emergency:uid:callid:test:bcf.example.com>;purpose=emergency-CallId",
1005 )]);
1006 let ci = h
1007 .call_info()
1008 .unwrap()
1009 .unwrap();
1010 assert_eq!(ci.len(), 1);
1011 assert_eq!(ci.entries()[0].purpose(), Some("emergency-CallId"));
1012 }
1013
1014 #[test]
1015 fn call_info_absent() {
1016 let h = headers_with(&[]);
1017 assert_eq!(
1018 h.call_info()
1019 .unwrap(),
1020 None
1021 );
1022 }
1023
1024 #[test]
1025 fn p_asserted_identity_typed() {
1026 let h = headers_with(&[(
1027 "P-Asserted-Identity",
1028 r#""EXAMPLE CO" <sip:+15551234567@198.51.100.1>"#,
1029 )]);
1030 let pais = h
1031 .p_asserted_identity()
1032 .unwrap();
1033 assert_eq!(pais.len(), 1);
1034 assert_eq!(pais[0].display_name(), Some("EXAMPLE CO"));
1035 }
1036
1037 #[test]
1038 fn p_asserted_identity_multi_value() {
1039 let h = headers_with(&[(
1040 "P-Asserted-Identity",
1041 r#""EXAMPLE CO" <sip:+15551234567@198.51.100.1>, <tel:+15551234567>"#,
1042 )]);
1043 let pais = h
1044 .p_asserted_identity()
1045 .unwrap();
1046 assert_eq!(pais.len(), 2);
1047 assert_eq!(pais[0].display_name(), Some("EXAMPLE CO"));
1048 assert!(pais[1]
1049 .uri()
1050 .to_string()
1051 .contains("+15551234567"));
1052 }
1053
1054 #[test]
1055 fn p_asserted_identity_absent() {
1056 let h = headers_with(&[]);
1057 assert!(h
1058 .p_asserted_identity()
1059 .unwrap()
1060 .is_empty());
1061 }
1062
1063 #[test]
1064 fn history_info_raw_lookup() {
1065 let h = headers_with(&[(
1066 "History-Info",
1067 "<sip:alice@esrp.example.com>;index=1,<sip:sos@psap.example.com>;index=1.1",
1068 )]);
1069 assert!(h
1070 .sip_header(SipHeader::HistoryInfo)
1071 .unwrap()
1072 .contains("esrp.example.com"));
1073 }
1074
1075 #[test]
1076 fn history_info_typed() {
1077 let h = headers_with(&[(
1078 "History-Info",
1079 "<sip:alice@esrp.example.com>;index=1,<sip:sos@psap.example.com>;index=1.1",
1080 )]);
1081 let hi = h
1082 .history_info()
1083 .unwrap()
1084 .unwrap();
1085 assert_eq!(hi.len(), 2);
1086 assert_eq!(hi.entries()[0].index(), Some("1"));
1087 assert_eq!(hi.entries()[1].index(), Some("1.1"));
1088 }
1089
1090 #[test]
1091 fn history_info_absent() {
1092 let h = headers_with(&[]);
1093 assert_eq!(
1094 h.history_info()
1095 .unwrap(),
1096 None
1097 );
1098 }
1099
1100 #[test]
1101 fn sip_header_all_str_default() {
1102 let h = headers_with(&[("Via", "SIP/2.0/UDP host1")]);
1103 let all = h.sip_header_all(SipHeader::Via);
1104 assert_eq!(all.len(), 1);
1105 assert_eq!(all[0], "SIP/2.0/UDP host1");
1106 }
1107
1108 #[test]
1109 fn sip_header_all_str_absent() {
1110 let h = headers_with(&[]);
1111 assert!(h
1112 .sip_header_all(SipHeader::Via)
1113 .is_empty());
1114 }
1115
1116 #[test]
1117 fn hashmap_vec_impl() {
1118 let mut h: HashMap<String, Vec<String>> = HashMap::new();
1119 h.insert(
1120 "Via".into(),
1121 vec!["SIP/2.0/UDP host1".into(), "SIP/2.0/UDP host2".into()],
1122 );
1123 assert_eq!(h.sip_header_str("Via"), Some("SIP/2.0/UDP host1"));
1124 let all = h.sip_header_all_str("Via");
1125 assert_eq!(all.len(), 2);
1126 assert_eq!(all[0], "SIP/2.0/UDP host1");
1127 assert_eq!(all[1], "SIP/2.0/UDP host2");
1128 }
1129
1130 #[test]
1131 fn extract_from_sip_message() {
1132 let msg = concat!(
1133 "INVITE sip:bob@host SIP/2.0\r\n",
1134 "Call-Info: <urn:emergency:uid:callid:abc>;purpose=emergency-CallId\r\n",
1135 "History-Info: <sip:esrp@example.com>;index=1\r\n",
1136 "P-Asserted-Identity: \"Corp\" <sip:+15551234567@198.51.100.1>\r\n",
1137 "\r\n",
1138 );
1139 let ci = SipHeader::CallInfo.extract_from(msg);
1140 assert_eq!(ci.len(), 1);
1141 assert_eq!(
1142 ci[0],
1143 "<urn:emergency:uid:callid:abc>;purpose=emergency-CallId"
1144 );
1145
1146 let hi = SipHeader::HistoryInfo.extract_from(msg);
1147 assert_eq!(hi.len(), 1);
1148 assert_eq!(hi[0], "<sip:esrp@example.com>;index=1");
1149
1150 let pai = SipHeader::PAssertedIdentity.extract_from(msg);
1151 assert_eq!(pai.len(), 1);
1152 assert_eq!(pai[0], "\"Corp\" <sip:+15551234567@198.51.100.1>");
1153 }
1154
1155 #[test]
1156 fn extract_from_missing() {
1157 let msg = concat!(
1158 "INVITE sip:bob@host SIP/2.0\r\n",
1159 "From: Alice <sip:alice@host>\r\n",
1160 "\r\n",
1161 );
1162 assert!(SipHeader::CallInfo
1163 .extract_from(msg)
1164 .is_empty());
1165 assert!(SipHeader::PAssertedIdentity
1166 .extract_from(msg)
1167 .is_empty());
1168 }
1169
1170 #[test]
1171 fn missing_headers_return_none() {
1172 let h = headers_with(&[]);
1173 assert_eq!(h.sip_header(SipHeader::CallInfo), None);
1174 assert_eq!(
1175 h.call_info()
1176 .unwrap(),
1177 None
1178 );
1179 assert_eq!(h.sip_header(SipHeader::HistoryInfo), None);
1180 assert_eq!(
1181 h.history_info()
1182 .unwrap(),
1183 None
1184 );
1185 assert_eq!(h.sip_header(SipHeader::PAssertedIdentity), None);
1186 assert!(h
1187 .p_asserted_identity()
1188 .unwrap()
1189 .is_empty());
1190 }
1191
1192 #[test]
1193 fn route_accessor() {
1194 let h = headers_with(&[(
1195 "Route",
1196 "<sip:proxy1.example.com;lr>, <sip:proxy2.example.com;lr>",
1197 )]);
1198 let routes = h
1199 .route()
1200 .unwrap();
1201 assert_eq!(routes.len(), 2);
1202 assert!(routes[0]
1203 .uri()
1204 .to_string()
1205 .contains("proxy1"));
1206 assert!(routes[1]
1207 .uri()
1208 .to_string()
1209 .contains("proxy2"));
1210 }
1211
1212 #[test]
1213 fn route_absent() {
1214 let h = headers_with(&[]);
1215 assert!(h
1216 .route()
1217 .unwrap()
1218 .is_empty());
1219 }
1220
1221 #[test]
1222 fn record_route_accessor() {
1223 let h = headers_with(&[("Record-Route", "<sip:ss1.example.com;lr>")]);
1224 let rr = h
1225 .record_route()
1226 .unwrap();
1227 assert_eq!(rr.len(), 1);
1228 }
1229
1230 #[test]
1231 fn allow_accessor() {
1232 let h = headers_with(&[("Allow", "INVITE, ACK, OPTIONS, BYE")]);
1233 let methods = h.allow();
1234 assert_eq!(methods, vec!["INVITE", "ACK", "OPTIONS", "BYE"]);
1235 }
1236
1237 #[test]
1238 fn allow_absent() {
1239 let h = headers_with(&[]);
1240 assert!(h
1241 .allow()
1242 .is_empty());
1243 }
1244
1245 #[test]
1246 fn supported_accessor() {
1247 let h = headers_with(&[("Supported", "100rel, timer")]);
1248 let opts = h.supported();
1249 assert_eq!(opts, vec!["100rel", "timer"]);
1250 }
1251
1252 #[test]
1253 fn require_header_accessor() {
1254 let h = headers_with(&[("Require", "100rel")]);
1255 assert_eq!(h.require_header(), vec!["100rel"]);
1256 }
1257
1258 #[test]
1259 fn alert_info_accessor() {
1260 let h = headers_with(&[("Alert-Info", "<http://www.example.com/sounds/moo.wav>")]);
1261 let ai = h
1262 .alert_info()
1263 .unwrap()
1264 .unwrap();
1265 assert_eq!(ai.len(), 1);
1266 assert!(ai.entries()[0]
1267 .data
1268 .contains("moo.wav"));
1269 }
1270
1271 #[test]
1272 fn error_info_accessor() {
1273 let h = headers_with(&[("Error-Info", "<sip:not-in-service@example.com>")]);
1274 let ei = h
1275 .error_info()
1276 .unwrap()
1277 .unwrap();
1278 assert_eq!(ei.len(), 1);
1279 }
1280
1281 #[test]
1282 fn p_preferred_identity_accessor() {
1283 let h = headers_with(&[(
1284 "P-Preferred-Identity",
1285 r#""User" <sip:+15551234567@198.51.100.1>"#,
1286 )]);
1287 let ppi = h
1288 .p_preferred_identity()
1289 .unwrap();
1290 assert_eq!(ppi.len(), 1);
1291 assert_eq!(ppi[0].display_name(), Some("User"));
1292 }
1293
1294 #[test]
1295 fn content_encoding_accessor() {
1296 let h = headers_with(&[("Content-Encoding", "gzip")]);
1297 assert_eq!(h.content_encoding(), vec!["gzip"]);
1298 }
1299
1300 #[test]
1301 fn contact_accessor() {
1302 let h = headers_with(&[("Contact", "<sip:alice@198.51.100.1>")]);
1303 let contacts = h
1304 .contact()
1305 .unwrap();
1306 assert_eq!(contacts.len(), 1);
1307 assert!(matches!(&contacts[0], ContactValue::Addr(_)));
1308 }
1309
1310 #[test]
1311 fn contact_wildcard() {
1312 let h = headers_with(&[("Contact", "*")]);
1313 let contacts = h
1314 .contact()
1315 .unwrap();
1316 assert_eq!(contacts.len(), 1);
1317 assert!(matches!(contacts[0], ContactValue::Wildcard));
1318 }
1319
1320 #[test]
1321 fn contact_absent() {
1322 let h = headers_with(&[]);
1323 assert!(h
1324 .contact()
1325 .unwrap()
1326 .is_empty());
1327 }
1328
1329 #[test]
1330 fn in_reply_to_accessor() {
1331 let h = headers_with(&[("In-Reply-To", "call1@example.com, call2@example.com")]);
1332 let calls = h.in_reply_to();
1333 assert_eq!(calls.len(), 2);
1334 assert_eq!(calls[0], "call1@example.com");
1335 }
1336
1337 #[test]
1338 fn via_accessor() {
1339 let h = headers_with(&[("Via", "SIP/2.0/UDP 198.51.100.1:5060;branch=z9hG4bK776")]);
1340 let via = h
1341 .via()
1342 .unwrap()
1343 .unwrap();
1344 assert_eq!(via.len(), 1);
1345 assert_eq!(via.entries()[0].transport(), "UDP");
1346 assert_eq!(via.entries()[0].host(), "198.51.100.1");
1347 }
1348
1349 #[test]
1350 fn authorization_accessor() {
1351 let h = headers_with(&[(
1352 "Authorization",
1353 "Digest username=\"alice\", realm=\"example.com\", nonce=\"abc123\"",
1354 )]);
1355 let auth = h
1356 .authorization()
1357 .unwrap();
1358 assert_eq!(auth.len(), 1);
1359 assert_eq!(auth[0].scheme(), "Digest");
1360 assert_eq!(auth[0].username(), Some("alice"));
1361 assert_eq!(auth[0].realm(), Some("example.com"));
1362 }
1363
1364 #[test]
1365 fn www_authenticate_accessor() {
1366 let h = headers_with(&[(
1367 "WWW-Authenticate",
1368 "Digest realm=\"example.com\", nonce=\"xyz789\"",
1369 )]);
1370 let challenges = h
1371 .www_authenticate()
1372 .unwrap();
1373 assert_eq!(challenges.len(), 1);
1374 assert_eq!(challenges[0].realm(), Some("example.com"));
1375 }
1376
1377 #[test]
1378 fn warning_accessor() {
1379 let h = headers_with(&[(
1380 "Warning",
1381 "301 198.51.100.1 \"Incompatible network protocol\"",
1382 )]);
1383 let w = h
1384 .warning()
1385 .unwrap()
1386 .unwrap();
1387 assert_eq!(w.len(), 1);
1388 assert_eq!(w.entries()[0].code(), 301);
1389 }
1390
1391 #[test]
1392 fn security_client_accessor() {
1393 let h = headers_with(&[("Security-Client", "tls;q=0.2, digest;d-qop=auth;q=0.1")]);
1394 let sec = h
1395 .security_client()
1396 .unwrap()
1397 .unwrap();
1398 assert_eq!(sec.len(), 2);
1399 assert_eq!(sec.entries()[0].mechanism(), "tls");
1400 }
1401
1402 #[test]
1403 fn accept_accessor() {
1404 let h = headers_with(&[("Accept", "application/sdp, application/pidf+xml;q=0.5")]);
1405 let accept = h
1406 .accept()
1407 .unwrap()
1408 .unwrap();
1409 assert_eq!(accept.len(), 2);
1410 assert_eq!(accept.entries()[0].media_range(), "application/sdp");
1411 }
1412
1413 #[test]
1414 fn accept_encoding_accessor() {
1415 let h = headers_with(&[("Accept-Encoding", "gzip;q=1.0, identity;q=0.5")]);
1416 let ae = h
1417 .accept_encoding()
1418 .unwrap()
1419 .unwrap();
1420 assert_eq!(ae.len(), 2);
1421 assert_eq!(ae.entries()[0].encoding(), "gzip");
1422 }
1423
1424 #[test]
1425 fn accept_language_accessor() {
1426 let h = headers_with(&[("Accept-Language", "en;q=0.9, fr;q=0.8")]);
1427 let al = h
1428 .accept_language()
1429 .unwrap()
1430 .unwrap();
1431 assert_eq!(al.len(), 2);
1432 assert_eq!(al.entries()[0].language(), "en");
1433 }
1434}
1435
1436#[cfg(test)]
1437mod compact_form_tests {
1438 use super::*;
1439
1440 #[test]
1441 fn from_compact_known() {
1442 assert_eq!(SipHeader::from_compact(b'f'), Some(SipHeader::From));
1443 assert_eq!(SipHeader::from_compact(b'F'), Some(SipHeader::From));
1444 assert_eq!(SipHeader::from_compact(b'v'), Some(SipHeader::Via));
1445 assert_eq!(SipHeader::from_compact(b'i'), Some(SipHeader::CallId));
1446 assert_eq!(SipHeader::from_compact(b'm'), Some(SipHeader::Contact));
1447 assert_eq!(SipHeader::from_compact(b't'), Some(SipHeader::To));
1448 assert_eq!(SipHeader::from_compact(b'c'), Some(SipHeader::ContentType));
1449 }
1450
1451 #[test]
1452 fn from_compact_unknown() {
1453 assert_eq!(SipHeader::from_compact(b'z'), None);
1454 assert_eq!(SipHeader::from_compact(b'g'), None);
1455 }
1456
1457 #[test]
1458 fn compact_form_roundtrip() {
1459 assert_eq!(SipHeader::From.compact_form(), Some('f'));
1460 assert_eq!(SipHeader::Via.compact_form(), Some('v'));
1461 assert_eq!(SipHeader::CallId.compact_form(), Some('i'));
1462 assert_eq!(SipHeader::Contact.compact_form(), Some('m'));
1463 }
1464
1465 #[test]
1466 fn compact_form_absent() {
1467 assert_eq!(SipHeader::HistoryInfo.compact_form(), None);
1468 assert_eq!(SipHeader::PAssertedIdentity.compact_form(), None);
1469 }
1470
1471 #[test]
1472 fn parse_name_compact() {
1473 assert_eq!(SipHeader::parse_name("f"), Ok(SipHeader::From));
1474 assert_eq!(SipHeader::parse_name("F"), Ok(SipHeader::From));
1475 assert_eq!(SipHeader::parse_name("v"), Ok(SipHeader::Via));
1476 }
1477
1478 #[test]
1479 fn parse_name_full() {
1480 assert_eq!(SipHeader::parse_name("From"), Ok(SipHeader::From));
1481 assert_eq!(SipHeader::parse_name("Via"), Ok(SipHeader::Via));
1482 }
1483
1484 #[test]
1485 fn parse_name_unknown() {
1486 assert!(SipHeader::parse_name("X-Custom").is_err());
1487 }
1488
1489 #[test]
1490 fn all_compact_forms_resolve() {
1491 let expected = [
1492 ('a', SipHeader::AcceptContact),
1493 ('b', SipHeader::ReferredBy),
1494 ('c', SipHeader::ContentType),
1495 ('d', SipHeader::RequestDisposition),
1496 ('e', SipHeader::ContentEncoding),
1497 ('f', SipHeader::From),
1498 ('i', SipHeader::CallId),
1499 ('j', SipHeader::RejectContact),
1500 ('k', SipHeader::Supported),
1501 ('l', SipHeader::ContentLength),
1502 ('m', SipHeader::Contact),
1503 ('n', SipHeader::IdentityInfo),
1504 ('o', SipHeader::Event),
1505 ('r', SipHeader::ReferTo),
1506 ('s', SipHeader::Subject),
1507 ('t', SipHeader::To),
1508 ('u', SipHeader::AllowEvents),
1509 ('v', SipHeader::Via),
1510 ('x', SipHeader::SessionExpires),
1511 ('y', SipHeader::Identity),
1512 ];
1513 for (ch, header) in expected {
1514 assert_eq!(
1515 SipHeader::from_compact(ch as u8),
1516 Some(header),
1517 "compact form '{ch}' failed"
1518 );
1519 assert_eq!(
1520 header.compact_form(),
1521 Some(ch),
1522 "compact_form() for {} failed",
1523 header
1524 );
1525 }
1526 }
1527}
1528
1529#[cfg(test)]
1530mod multi_valued_tests {
1531 use super::*;
1532
1533 #[test]
1534 fn rfc3261_multi_valued_headers() {
1535 assert!(SipHeader::Via.is_multi_valued());
1536 assert!(SipHeader::Route.is_multi_valued());
1537 assert!(SipHeader::RecordRoute.is_multi_valued());
1538 assert!(SipHeader::Contact.is_multi_valued());
1539 assert!(SipHeader::Allow.is_multi_valued());
1540 assert!(SipHeader::Supported.is_multi_valued());
1541 assert!(SipHeader::Require.is_multi_valued());
1542 assert!(SipHeader::ProxyRequire.is_multi_valued());
1543 assert!(SipHeader::Unsupported.is_multi_valued());
1544 assert!(SipHeader::Authorization.is_multi_valued());
1545 assert!(SipHeader::ProxyAuthorization.is_multi_valued());
1546 assert!(SipHeader::WwwAuthenticate.is_multi_valued());
1547 assert!(SipHeader::ProxyAuthenticate.is_multi_valued());
1548 assert!(SipHeader::Warning.is_multi_valued());
1549 assert!(SipHeader::ErrorInfo.is_multi_valued());
1550 assert!(SipHeader::CallInfo.is_multi_valued());
1551 assert!(SipHeader::AlertInfo.is_multi_valued());
1552 assert!(SipHeader::Accept.is_multi_valued());
1553 assert!(SipHeader::AcceptEncoding.is_multi_valued());
1554 assert!(SipHeader::AcceptLanguage.is_multi_valued());
1555 assert!(SipHeader::ContentEncoding.is_multi_valued());
1556 assert!(SipHeader::ContentLanguage.is_multi_valued());
1557 assert!(SipHeader::InReplyTo.is_multi_valued());
1558 }
1559
1560 #[test]
1561 fn extension_multi_valued_headers() {
1562 assert!(SipHeader::PAssertedIdentity.is_multi_valued());
1563 assert!(SipHeader::PPreferredIdentity.is_multi_valued());
1564 assert!(SipHeader::AllowEvents.is_multi_valued());
1565 assert!(SipHeader::SecurityClient.is_multi_valued());
1566 assert!(SipHeader::SecurityServer.is_multi_valued());
1567 assert!(SipHeader::SecurityVerify.is_multi_valued());
1568 assert!(SipHeader::Path.is_multi_valued());
1569 assert!(SipHeader::ServiceRoute.is_multi_valued());
1570 assert!(SipHeader::HistoryInfo.is_multi_valued());
1571 }
1572
1573 #[test]
1574 fn single_valued_headers() {
1575 assert!(!SipHeader::From.is_multi_valued());
1576 assert!(!SipHeader::To.is_multi_valued());
1577 assert!(!SipHeader::CallId.is_multi_valued());
1578 assert!(!SipHeader::Cseq.is_multi_valued());
1579 assert!(!SipHeader::MaxForwards.is_multi_valued());
1580 assert!(!SipHeader::ContentType.is_multi_valued());
1581 assert!(!SipHeader::ContentLength.is_multi_valued());
1582 assert!(!SipHeader::Expires.is_multi_valued());
1583 assert!(!SipHeader::Date.is_multi_valued());
1584 assert!(!SipHeader::Subject.is_multi_valued());
1585 assert!(!SipHeader::ReplyTo.is_multi_valued());
1586 assert!(!SipHeader::Server.is_multi_valued());
1587 assert!(!SipHeader::UserAgent.is_multi_valued());
1588 }
1589
1590 #[test]
1591 #[cfg(feature = "draft")]
1592 fn draft_multi_valued_headers() {
1593 assert!(SipHeader::Diversion.is_multi_valued());
1594 assert!(SipHeader::RemotePartyId.is_multi_valued());
1595 }
1596
1597 #[test]
1598 #[cfg(feature = "draft")]
1599 fn draft_parse_roundtrip() {
1600 let d: SipHeader = "Diversion"
1601 .parse()
1602 .unwrap();
1603 assert_eq!(d, SipHeader::Diversion);
1604 assert_eq!(d.to_string(), "Diversion");
1605
1606 let r: SipHeader = "remote-party-id"
1607 .parse()
1608 .unwrap();
1609 assert_eq!(r, SipHeader::RemotePartyId);
1610 assert_eq!(r.to_string(), "Remote-Party-ID");
1611 }
1612}
1613
1614#[cfg(test)]
1615mod special_case_tests {
1616 use super::*;
1617
1618 #[test]
1619 fn cseq_variants() {
1620 assert_eq!("CSeq".parse::<SipHeader>(), Ok(SipHeader::Cseq));
1621 assert_eq!("cseq".parse::<SipHeader>(), Ok(SipHeader::Cseq));
1622 assert_eq!("CSEQ".parse::<SipHeader>(), Ok(SipHeader::Cseq));
1623 assert_eq!(SipHeader::Cseq.to_string(), "CSeq");
1624 }
1625
1626 #[test]
1627 fn www_authenticate_variants() {
1628 assert_eq!(
1629 "WWW-Authenticate".parse::<SipHeader>(),
1630 Ok(SipHeader::WwwAuthenticate)
1631 );
1632 assert_eq!(
1633 "www-authenticate".parse::<SipHeader>(),
1634 Ok(SipHeader::WwwAuthenticate)
1635 );
1636 assert_eq!(SipHeader::WwwAuthenticate.to_string(), "WWW-Authenticate");
1637 }
1638
1639 #[test]
1640 fn rack_rseq_variants() {
1641 assert_eq!("RAck".parse::<SipHeader>(), Ok(SipHeader::Rack));
1642 assert_eq!("rack".parse::<SipHeader>(), Ok(SipHeader::Rack));
1643 assert_eq!(SipHeader::Rack.to_string(), "RAck");
1644
1645 assert_eq!("RSeq".parse::<SipHeader>(), Ok(SipHeader::Rseq));
1646 assert_eq!("rseq".parse::<SipHeader>(), Ok(SipHeader::Rseq));
1647 assert_eq!(SipHeader::Rseq.to_string(), "RSeq");
1648 }
1649
1650 #[test]
1651 fn user_to_user_variants() {
1652 assert_eq!(
1653 "User-to-User".parse::<SipHeader>(),
1654 Ok(SipHeader::UserToUser)
1655 );
1656 assert_eq!(
1657 "user-to-user".parse::<SipHeader>(),
1658 Ok(SipHeader::UserToUser)
1659 );
1660 assert_eq!(SipHeader::UserToUser.to_string(), "User-to-User");
1661 }
1662
1663 #[test]
1664 fn p_header_variants() {
1665 assert_eq!(
1666 "P-DCS-Trace-Party-ID".parse::<SipHeader>(),
1667 Ok(SipHeader::PDcsTracePartyId)
1668 );
1669 assert_eq!(
1670 "p-dcs-trace-party-id".parse::<SipHeader>(),
1671 Ok(SipHeader::PDcsTracePartyId)
1672 );
1673 assert_eq!(
1674 SipHeader::PDcsTracePartyId.to_string(),
1675 "P-DCS-Trace-Party-ID"
1676 );
1677 }
1678}