1 #[cfg(test)] 2 mod uri_test; 3 4 use crate::error::*; 5 6 use std::fmt; 7 8 // SCHEME definitions from RFC 7064 Section 3.2. 9 10 pub const SCHEME: &str = "stun"; 11 pub const SCHEME_SECURE: &str = "stuns"; 12 13 // URI as defined in RFC 7064. 14 #[derive(PartialEq, Eq, Debug)] 15 pub struct Uri { 16 pub scheme: String, 17 pub host: String, 18 pub port: Option<u16>, 19 } 20 21 impl fmt::Display for Uri { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 23 let host = if self.host.contains("::") { 24 "[".to_owned() + self.host.as_str() + "]" 25 } else { 26 self.host.clone() 27 }; 28 29 if let Some(port) = self.port { 30 write!(f, "{}:{}:{}", self.scheme, host, port) 31 } else { 32 write!(f, "{}:{}", self.scheme, host) 33 } 34 } 35 } 36 37 impl Uri { 38 // parse_uri parses URI from string. parse_uri(raw: &str) -> Result<Self>39 pub fn parse_uri(raw: &str) -> Result<Self> { 40 // work around for url crate 41 if raw.contains("//") { 42 return Err(Error::ErrInvalidUrl); 43 } 44 45 let mut s = raw.to_string(); 46 let pos = raw.find(':'); 47 if let Some(p) = pos { 48 s.replace_range(p..p + 1, "://"); 49 } else { 50 return Err(Error::ErrSchemeType); 51 } 52 53 let raw_parts = url::Url::parse(&s)?; 54 55 let scheme = raw_parts.scheme().into(); 56 if scheme != SCHEME && scheme != SCHEME_SECURE { 57 return Err(Error::ErrSchemeType); 58 } 59 60 let host = if let Some(host) = raw_parts.host_str() { 61 host.trim() 62 .trim_start_matches('[') 63 .trim_end_matches(']') 64 .to_owned() 65 } else { 66 return Err(Error::ErrHost); 67 }; 68 69 let port = raw_parts.port(); 70 71 Ok(Uri { scheme, host, port }) 72 } 73 } 74