@@ -74,15 +74,45 @@ macro_rules! header_pop {
7474}
7575
7676pub fn extract_uri_from_contact ( line : & str ) -> Result < rsip:: Uri > {
77- if let Ok ( mut uri) = rsip:: headers:: Contact :: from ( line) . uri ( ) {
78- uri. params
79- . retain ( |p| matches ! ( p, rsip:: Param :: Transport ( _) ) ) ;
77+ if let Ok ( uri) = rsip:: headers:: Contact :: from ( line) . uri ( ) {
8078 return Ok ( uri) ;
8179 }
8280
83- match line. split ( '<' ) . nth ( 1 ) . and_then ( |s| s. split ( '>' ) . next ( ) ) {
84- Some ( uri) => rsip:: Uri :: try_from ( uri) . map_err ( Into :: into) ,
85- None => Err ( Error :: Error ( "no uri found" . to_string ( ) ) ) ,
81+ let tokenizer = CustomContactTokenizer :: from_str ( line) ?;
82+ let mut uri = rsip:: Uri :: try_from ( tokenizer. uri ( ) ) . map_err ( Error :: from) ?;
83+ uri. params . retain ( |p| {
84+ if let rsip:: Param :: Transport ( rsip:: Transport :: Udp ) = p {
85+ false
86+ } else {
87+ true
88+ }
89+ } ) ;
90+ apply_tokenizer_params ( & mut uri, & tokenizer) ;
91+ return Ok ( uri) ;
92+ }
93+
94+ fn apply_tokenizer_params ( uri : & mut rsip:: Uri , tokenizer : & CustomContactTokenizer ) {
95+ for ( name, value) in tokenizer. params . iter ( ) . map ( |p| ( p. name , p. value ) ) {
96+ if name. eq_ignore_ascii_case ( "transport" ) {
97+ continue ;
98+ }
99+ let mut updated = false ;
100+ for param in uri. params . iter_mut ( ) {
101+ if let rsip:: Param :: Other ( key, existing_value) = param {
102+ if key. value ( ) . eq_ignore_ascii_case ( name) {
103+ * existing_value =
104+ value. map ( |v| rsip:: param:: OtherParamValue :: new ( v. to_string ( ) ) ) ;
105+ updated = true ;
106+ break ;
107+ }
108+ }
109+ }
110+ if !updated {
111+ uri. params . push ( rsip:: Param :: Other (
112+ rsip:: param:: OtherParam :: new ( name) ,
113+ value. map ( |v| rsip:: param:: OtherParamValue :: new ( v. to_string ( ) ) ) ,
114+ ) ) ;
115+ }
86116 }
87117}
88118
@@ -104,6 +134,114 @@ pub fn destination_from_request(request: &rsip::Request) -> Option<SipAddr> {
104134 . or_else ( || SipAddr :: try_from ( & request. uri ) . ok ( ) )
105135}
106136
137+ use nom:: {
138+ branch:: alt,
139+ bytes:: complete:: { is_not, take_until} ,
140+ character:: complete:: { char, multispace0} ,
141+ combinator:: { map, opt, rest} ,
142+ multi:: separated_list0,
143+ sequence:: { delimited, preceded} ,
144+ IResult ,
145+ } ;
146+
147+ #[ derive( Debug ) ]
148+ pub ( crate ) struct CustomContactTokenizer < ' a > {
149+ uri : & ' a str ,
150+ params : Vec < CustomContactParamToken < ' a > > ,
151+ }
152+
153+ #[ derive( Debug ) ]
154+ struct CustomContactParamToken < ' a > {
155+ name : & ' a str ,
156+ value : Option < & ' a str > ,
157+ }
158+
159+ impl < ' a > CustomContactTokenizer < ' a > {
160+ pub ( crate ) fn from_str ( input : & ' a str ) -> super :: Result < Self > {
161+ let trimmed = input. trim ( ) ;
162+ if trimmed. is_empty ( ) {
163+ return Err ( Error :: Error ( "empty contact header" . into ( ) ) ) ;
164+ }
165+
166+ match custom_contact_tokenize ( trimmed) {
167+ Ok ( ( _rem, tokenizer) ) => Ok ( tokenizer) ,
168+ Err ( _) => Ok ( Self :: from_plain ( trimmed) ) ,
169+ }
170+ }
171+
172+ fn from_plain ( uri : & ' a str ) -> Self {
173+ Self {
174+ uri,
175+ params : custom_contact_parse_params ( uri) ,
176+ }
177+ }
178+
179+ pub ( crate ) fn uri ( & self ) -> & ' a str {
180+ self . uri
181+ }
182+ }
183+
184+ fn custom_contact_tokenize < ' a > ( input : & ' a str ) -> IResult < & ' a str , CustomContactTokenizer < ' a > > {
185+ alt ( (
186+ custom_contact_with_brackets,
187+ custom_contact_without_brackets,
188+ ) ) ( input)
189+ }
190+
191+ fn custom_contact_with_brackets < ' a > (
192+ input : & ' a str ,
193+ ) -> IResult < & ' a str , CustomContactTokenizer < ' a > > {
194+ let ( input, _) = multispace0 ( input) ?;
195+ let ( input, _) = opt ( take_until ( "<" ) ) ( input) ?;
196+ let ( input, _) = char ( '<' ) ( input) ?;
197+ let ( input, uri) = take_until ( ">" ) ( input) ?;
198+ let ( input, _) = char ( '>' ) ( input) ?;
199+
200+ let uri = uri. trim ( ) ;
201+ let params = custom_contact_parse_params ( uri) ;
202+
203+ Ok ( ( input, CustomContactTokenizer { uri, params } ) )
204+ }
205+
206+ fn custom_contact_without_brackets < ' a > (
207+ input : & ' a str ,
208+ ) -> IResult < & ' a str , CustomContactTokenizer < ' a > > {
209+ let ( input, uri) = map ( rest, |s : & str | s. trim ( ) ) ( input) ?;
210+ let params = custom_contact_parse_params ( uri) ;
211+ Ok ( ( input, CustomContactTokenizer { uri, params } ) )
212+ }
213+
214+ fn custom_contact_parse_params < ' a > ( uri : & ' a str ) -> Vec < CustomContactParamToken < ' a > > {
215+ let path = uri. split_once ( '?' ) . map_or ( uri, |( path, _) | path) ;
216+ if let Some ( idx) = path. find ( ';' ) {
217+ let params_str = & path[ idx + 1 ..] ;
218+ if params_str. is_empty ( ) {
219+ return Vec :: new ( ) ;
220+ }
221+
222+ match separated_list0 ( char ( ';' ) , custom_contact_param) ( params_str) {
223+ Ok ( ( _, params) ) => params. into_iter ( ) . filter ( |p| !p. name . is_empty ( ) ) . collect ( ) ,
224+ Err ( _) => Vec :: new ( ) ,
225+ }
226+ } else {
227+ Vec :: new ( )
228+ }
229+ }
230+
231+ fn custom_contact_param < ' a > ( input : & ' a str ) -> IResult < & ' a str , CustomContactParamToken < ' a > > {
232+ let ( input, _) = multispace0 ( input) ?;
233+ let ( input, name) = map ( is_not ( "=; \t \r \n ?" ) , |v : & str | v. trim ( ) ) ( input) ?;
234+ let ( input, value) = opt ( preceded (
235+ char ( '=' ) ,
236+ alt ( (
237+ delimited ( char ( '"' ) , take_until ( "\" " ) , char ( '"' ) ) ,
238+ map ( is_not ( "; \t \r \n ?" ) , |v : & str | v. trim ( ) ) ,
239+ ) ) ,
240+ ) ) ( input) ?;
241+
242+ Ok ( ( input, CustomContactParamToken { name, value } ) )
243+ }
244+
107245#[ test]
108246fn test_rsip_headers_ext ( ) {
109247 use rsip:: { Header , Headers } ;
0 commit comments