#[cfg(test)]
mod uri_test;
use shared::error::*;
use std::fmt;
pub const SCHEME: &str = "stun";
pub const SCHEME_SECURE: &str = "stuns";
#[derive(PartialEq, Eq, Debug)]
pub struct Uri {
pub scheme: String,
pub host: String,
pub port: Option<u16>,
}
impl fmt::Display for Uri {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let host = if self.host.contains("::") {
format!("[{}]", self.host)
} else {
self.host.clone()
};
if let Some(port) = self.port {
write!(f, "{}:{}:{}", self.scheme, host, port)
} else {
write!(f, "{}:{}", self.scheme, host)
}
}
}
impl Uri {
pub fn parse_uri(raw: &str) -> Result<Self> {
if raw.contains("//") {
return Err(Error::ErrInvalidUrl);
}
let mut s = raw.to_string();
let pos = raw.find(':');
let p = pos.ok_or(Error::ErrSchemeType)?;
s.replace_range(p..p + 1, "://");
let raw_parts = url::Url::parse(&s)?;
let scheme = raw_parts.scheme().into();
if scheme != SCHEME && scheme != SCHEME_SECURE {
return Err(Error::ErrSchemeType);
}
let host = raw_parts
.host_str()
.ok_or(Error::ErrHost)?
.trim()
.trim_start_matches('[')
.trim_end_matches(']')
.to_owned();
let port = raw_parts.port();
Ok(Uri { scheme, host, port })
}
}