use std::borrow::Cow;
use std::convert::{Infallible, TryFrom};
use std::error::Error;
use std::fmt::{self, Display, Formatter, Write};
use std::hash::{Hash, Hasher};
use std::mem;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::ops::Deref;
use std::str;
use crate::utility::{
get_percent_encoded_value, normalize_string, percent_encoded_equality, percent_encoded_hash,
UNRESERVED_CHAR_MAP,
};
#[rustfmt::skip]
const IPV4_AND_REGISTERED_NAME_CHAR_MAP: [u8; 256] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b'!', 0, 0, b'$', b'%', b'&',b'\'', b'(', b')', b'*', b'+', b',', b'-', b'.', 0, b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', 0, b';', 0, b'=', 0, 0, 0, b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', 0, 0, 0, 0, b'_', 0, b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', 0, 0, 0, b'~', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
#[rustfmt::skip]
const IPV_FUTURE_CHAR_MAP: [u8; 256] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b'!', 0, 0, b'$', 0, b'&',b'\'', b'(', b')', b'*', b'+', b',', b'-', b'.', 0, b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', b';', 0, b'=', 0, 0, 0, b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', 0, 0, 0, 0, b'_', 0, b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', 0, 0, 0, b'~', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
#[rustfmt::skip]
const USER_INFO_CHAR_MAP: [u8; 256] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b'!', 0, 0, b'$', b'%', b'&',b'\'', b'(', b')', b'*', b'+', b',', b'-', b'.', 0, b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', b';', 0, b'=', 0, 0, 0, b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', 0, 0, 0, 0, b'_', 0, b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', 0, 0, 0, b'~', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Authority<'authority> {
host: Host<'authority>,
password: Option<Password<'authority>>,
port: Option<u16>,
username: Option<Username<'authority>>,
}
impl<'authority> Authority<'authority> {
pub fn as_borrowed(&self) -> Authority {
let host = match &self.host {
Host::RegisteredName(name) => Host::RegisteredName(name.as_borrowed()),
Host::IPv4Address(ipv4) => Host::IPv4Address(*ipv4),
Host::IPv6Address(ipv6) => Host::IPv6Address(*ipv6),
};
let password = self.password.as_ref().map(Password::as_borrowed);
let username = self.username.as_ref().map(Username::as_borrowed);
Authority {
host,
password,
port: self.port,
username,
}
}
pub fn from_parts<
'new_authority,
TUsername,
TPassword,
THost,
TUsernameError,
TPasswordError,
THostError,
>(
username: Option<TUsername>,
password: Option<TPassword>,
host: THost,
port: Option<u16>,
) -> Result<Authority<'new_authority>, AuthorityError>
where
Username<'new_authority>: TryFrom<TUsername, Error = TUsernameError>,
Password<'new_authority>: TryFrom<TPassword, Error = TPasswordError>,
Host<'new_authority>: TryFrom<THost, Error = THostError>,
AuthorityError: From<TUsernameError> + From<TPasswordError> + From<THostError>,
{
let username = match username {
Some(username) => Some(Username::try_from(username)?),
None => None,
};
let password = match password {
Some(password) => Some(Password::try_from(password)?),
None => None,
};
let host = Host::try_from(host)?;
Ok(Authority {
host,
password,
port,
username,
})
}
pub fn has_password(&self) -> bool {
self.password.is_some()
}
pub fn has_port(&self) -> bool {
self.port.is_some()
}
pub fn has_username(&self) -> bool {
self.username.is_some()
}
pub fn host(&self) -> &Host<'authority> {
&self.host
}
pub fn into_owned(self) -> Authority<'static> {
let password = self.password.map(Password::into_owned);
let username = self.username.map(Username::into_owned);
let host = match self.host {
Host::RegisteredName(name) => Host::RegisteredName(name.into_owned()),
Host::IPv4Address(ipv4) => Host::IPv4Address(ipv4),
Host::IPv6Address(ipv6) => Host::IPv6Address(ipv6),
};
Authority {
host,
port: self.port,
password,
username,
}
}
pub fn into_parts(
self,
) -> (
Option<Username<'authority>>,
Option<Password<'authority>>,
Host<'authority>,
Option<u16>,
) {
(self.username, self.password, self.host, self.port)
}
pub fn is_normalized(&self) -> bool {
if let Some(username) = self.username.as_ref() {
if !username.is_normalized() {
return false;
}
}
if let Some(password) = self.password.as_ref() {
if !password.is_normalized() {
return false;
}
}
self.host.is_normalized()
}
pub fn map_host<TMapper>(&mut self, mapper: TMapper) -> &Host<'authority>
where
TMapper: FnOnce(Host<'authority>) -> Host<'authority>,
{
let temp_host = Host::RegisteredName(RegisteredName {
normalized: true,
registered_name: Cow::from(""),
});
let host = mapper(mem::replace(&mut self.host, temp_host));
self.set_host(host)
.expect("mapped host resulted in invalid state")
}
pub fn map_password<TMapper>(&mut self, mapper: TMapper) -> Option<&Password<'authority>>
where
TMapper: FnOnce(Option<Password<'authority>>) -> Option<Password<'authority>>,
{
let password = mapper(self.password.take());
self.set_password(password)
.expect("mapped password resulted in invalid state")
}
pub fn map_port<TMapper>(&mut self, mapper: TMapper) -> Option<u16>
where
TMapper: FnOnce(Option<u16>) -> Option<u16>,
{
let port = mapper(self.port);
self.set_port(port)
}
pub fn map_username<TMapper>(&mut self, mapper: TMapper) -> Option<&Username<'authority>>
where
TMapper: FnOnce(Option<Username<'authority>>) -> Option<Username<'authority>>,
{
let username = mapper(self.username.take());
self.set_username(username)
.expect("mapped username resulted in invalid state")
}
pub fn normalize(&mut self) {
if let Some(username) = self.username.as_mut() {
username.normalize();
}
if let Some(password) = self.password.as_mut() {
password.normalize();
}
self.host.normalize();
}
pub fn password(&self) -> Option<&Password<'authority>> {
self.password.as_ref()
}
pub fn port(&self) -> Option<u16> {
self.port
}
pub fn set_host<THost, THostError>(
&mut self,
host: THost,
) -> Result<&Host<'authority>, AuthorityError>
where
Host<'authority>: TryFrom<THost, Error = THostError>,
AuthorityError: From<THostError>,
{
self.host = Host::try_from(host)?;
Ok(self.host())
}
pub fn set_password<TPassword, TPasswordError>(
&mut self,
password: Option<TPassword>,
) -> Result<Option<&Password<'authority>>, AuthorityError>
where
Password<'authority>: TryFrom<TPassword, Error = TPasswordError>,
AuthorityError: From<TPasswordError>,
{
self.password = match password {
Some(password) => {
let password = Password::try_from(password)?;
if self.username.is_none() {
self.username = Some(Username {
normalized: true,
username: Cow::from(""),
});
}
Some(password)
}
None => None,
};
Ok(self.password())
}
pub fn set_port(&mut self, port: Option<u16>) -> Option<u16> {
self.port = port;
self.port
}
pub fn set_username<TUsername, TUsernameError>(
&mut self,
username: Option<TUsername>,
) -> Result<Option<&Username<'authority>>, AuthorityError>
where
Username<'authority>: TryFrom<TUsername, Error = TUsernameError>,
AuthorityError: From<TUsernameError>,
{
self.username = match username {
Some(username) => Some(Username::try_from(username)?),
None => {
self.password = None;
None
}
};
Ok(self.username())
}
pub fn username(&self) -> Option<&Username<'authority>> {
self.username.as_ref()
}
}
impl Display for Authority<'_> {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
if let Some(ref username) = self.username {
username.fmt(formatter)?;
if let Some(ref password) = self.password {
formatter.write_char(':')?;
password.fmt(formatter)?;
}
formatter.write_char('@')?;
}
self.host.fmt(formatter)?;
if let Some(port) = self.port {
formatter.write_char(':')?;
port.fmt(formatter)?;
}
Ok(())
}
}
impl<'authority> From<Authority<'authority>> for String {
fn from(value: Authority<'authority>) -> String {
value.to_string()
}
}
impl<'authority> TryFrom<&'authority [u8]> for Authority<'authority> {
type Error = AuthorityError;
fn try_from(value: &'authority [u8]) -> Result<Self, Self::Error> {
let (authority, rest) = parse_authority(value)?;
if rest.is_empty() {
Ok(authority)
} else if authority.has_port() {
Err(AuthorityError::Port(PortError::InvalidCharacter))
} else if authority.host().is_ipv6_address() {
Err(AuthorityError::Host(HostError::InvalidIPv6Character))
} else {
Err(AuthorityError::Host(
HostError::InvalidIPv4OrRegisteredNameCharacter,
))
}
}
}
impl<'authority> TryFrom<&'authority str> for Authority<'authority> {
type Error = AuthorityError;
fn try_from(value: &'authority str) -> Result<Self, Self::Error> {
Authority::try_from(value.as_bytes())
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Host<'host> {
IPv4Address(Ipv4Addr),
IPv6Address(Ipv6Addr),
RegisteredName(RegisteredName<'host>),
}
impl Host<'_> {
pub fn as_borrowed(&self) -> Host {
use self::Host::*;
match self {
IPv4Address(ipv4) => IPv4Address(*ipv4),
IPv6Address(ipv6) => IPv6Address(*ipv6),
RegisteredName(name) => RegisteredName(name.as_borrowed()),
}
}
pub fn into_owned(self) -> Host<'static> {
use self::Host::*;
match self {
IPv4Address(ipv4) => IPv4Address(ipv4),
IPv6Address(ipv6) => IPv6Address(ipv6),
RegisteredName(name) => RegisteredName(name.into_owned()),
}
}
pub fn is_ipv4_address(&self) -> bool {
match self {
Host::IPv4Address(_) => true,
_ => false,
}
}
pub fn is_ipv6_address(&self) -> bool {
match self {
Host::IPv6Address(_) => true,
_ => false,
}
}
pub fn is_normalized(&self) -> bool {
match self {
Host::RegisteredName(name) => name.is_normalized(),
_ => true,
}
}
pub fn is_registered_name(&self) -> bool {
match self {
Host::RegisteredName(_) => true,
_ => false,
}
}
pub fn normalize(&mut self) {
if let Host::RegisteredName(name) = self {
name.normalize()
}
}
}
impl Display for Host<'_> {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
use self::Host::*;
match self {
IPv4Address(address) => address.fmt(formatter),
IPv6Address(address) => {
formatter.write_char('[')?;
address.fmt(formatter)?;
formatter.write_char(']')
}
RegisteredName(name) => formatter.write_str(name.as_str()),
}
}
}
impl<'host> From<Host<'host>> for String {
fn from(value: Host<'host>) -> String {
value.to_string()
}
}
impl From<IpAddr> for Host<'static> {
fn from(value: IpAddr) -> Self {
match value {
IpAddr::V4(address) => Host::IPv4Address(address),
IpAddr::V6(address) => Host::IPv6Address(address),
}
}
}
impl From<Ipv4Addr> for Host<'static> {
fn from(value: Ipv4Addr) -> Self {
Host::IPv4Address(value)
}
}
impl From<Ipv6Addr> for Host<'static> {
fn from(value: Ipv6Addr) -> Self {
Host::IPv6Address(value)
}
}
impl<'host> TryFrom<&'host [u8]> for Host<'host> {
type Error = HostError;
fn try_from(value: &'host [u8]) -> Result<Self, Self::Error> {
if value.is_empty() {
let registered_name = RegisteredName {
normalized: true,
registered_name: Cow::from(""),
};
return Ok(Host::RegisteredName(registered_name));
}
match (value.get(0), value.get(value.len() - 1)) {
(Some(b'['), Some(b']')) => {
match value.get(1..3) {
Some(&[prefix, version])
if prefix.to_ascii_lowercase() == b'v' && version.is_ascii_hexdigit() =>
{
let ipvfuture = &value[3..value.len() - 1];
if check_ipvfuture(ipvfuture) {
return Err(HostError::AddressMechanismNotSupported);
} else {
return Err(HostError::InvalidIPvFutureCharacter);
}
}
_ => (),
}
let ipv6 = &value[1..value.len() - 1];
if !check_ipv6(ipv6) {
return Err(HostError::InvalidIPv6Character);
}
let ipv6: Ipv6Addr = unsafe { str::from_utf8_unchecked(ipv6) }
.parse()
.map_err(|_| HostError::InvalidIPv6Format)?;
Ok(Host::IPv6Address(ipv6))
}
_ => {
let (valid, normalized) = check_ipv4_or_registered_name(value);
if valid {
let value_string = unsafe { str::from_utf8_unchecked(value) };
match value_string.parse() {
Ok(ipv4) => Ok(Host::IPv4Address(ipv4)),
Err(_) => Ok(Host::RegisteredName(RegisteredName {
normalized,
registered_name: Cow::from(value_string),
})),
}
} else {
Err(HostError::InvalidIPv4OrRegisteredNameCharacter)
}
}
}
}
}
impl<'host> TryFrom<&'host str> for Host<'host> {
type Error = HostError;
fn try_from(value: &'host str) -> Result<Self, Self::Error> {
Host::try_from(value.as_bytes())
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Password<'password> {
normalized: bool,
password: Cow<'password, str>,
}
impl Password<'_> {
pub fn as_borrowed(&self) -> Password {
use self::Cow::*;
let password = match &self.password {
Borrowed(borrowed) => *borrowed,
Owned(owned) => owned.as_str(),
};
Password {
normalized: self.normalized,
password: Cow::Borrowed(password),
}
}
pub fn as_str(&self) -> &str {
&self.password
}
pub fn into_owned(self) -> Password<'static> {
Password {
normalized: self.normalized,
password: Cow::from(self.password.into_owned()),
}
}
pub fn is_normalized(&self) -> bool {
self.normalized
}
pub fn normalize(&mut self) {
if !self.normalized {
unsafe { normalize_string(&mut self.password.to_mut(), true) };
self.normalized = true;
}
}
}
impl AsRef<[u8]> for Password<'_> {
fn as_ref(&self) -> &[u8] {
self.password.as_bytes()
}
}
impl AsRef<str> for Password<'_> {
fn as_ref(&self) -> &str {
&self.password
}
}
impl Deref for Password<'_> {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.password
}
}
impl Display for Password<'_> {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str(&self.password)
}
}
impl Eq for Password<'_> {}
impl<'password> From<Password<'password>> for String {
fn from(value: Password<'password>) -> String {
value.to_string()
}
}
impl Hash for Password<'_> {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
percent_encoded_hash(self.password.as_bytes(), state, true);
}
}
impl PartialEq for Password<'_> {
fn eq(&self, other: &Password) -> bool {
*self == *other.as_bytes()
}
}
impl PartialEq<[u8]> for Password<'_> {
fn eq(&self, other: &[u8]) -> bool {
percent_encoded_equality(self.password.as_bytes(), other, true)
}
}
impl<'password> PartialEq<Password<'password>> for [u8] {
fn eq(&self, other: &Password<'password>) -> bool {
other == self
}
}
impl<'a> PartialEq<&'a [u8]> for Password<'_> {
fn eq(&self, other: &&'a [u8]) -> bool {
self == *other
}
}
impl<'a, 'password> PartialEq<Password<'password>> for &'a [u8] {
fn eq(&self, other: &Password<'password>) -> bool {
other == *self
}
}
impl PartialEq<str> for Password<'_> {
fn eq(&self, other: &str) -> bool {
self == other.as_bytes()
}
}
impl<'password> PartialEq<Password<'password>> for str {
fn eq(&self, other: &Password<'password>) -> bool {
other == self.as_bytes()
}
}
impl<'a> PartialEq<&'a str> for Password<'_> {
fn eq(&self, other: &&'a str) -> bool {
self == other.as_bytes()
}
}
impl<'a, 'password> PartialEq<Password<'password>> for &'a str {
fn eq(&self, other: &Password<'password>) -> bool {
other == self.as_bytes()
}
}
impl<'password> TryFrom<&'password [u8]> for Password<'password> {
type Error = PasswordError;
fn try_from(value: &'password [u8]) -> Result<Self, Self::Error> {
let normalized = check_user_info(value, false)?;
Ok(Password {
normalized,
password: Cow::from(unsafe { str::from_utf8_unchecked(value) }),
})
}
}
impl<'password> TryFrom<&'password str> for Password<'password> {
type Error = PasswordError;
fn try_from(value: &'password str) -> Result<Self, Self::Error> {
Password::try_from(value.as_bytes())
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RegisteredName<'name> {
normalized: bool,
registered_name: Cow<'name, str>,
}
impl RegisteredName<'_> {
pub fn as_borrowed(&self) -> RegisteredName {
use self::Cow::*;
let name = match &self.registered_name {
Borrowed(borrowed) => *borrowed,
Owned(owned) => owned.as_str(),
};
RegisteredName {
normalized: self.normalized,
registered_name: Cow::Borrowed(name),
}
}
pub fn as_str(&self) -> &str {
&self.registered_name
}
pub fn into_owned(self) -> RegisteredName<'static> {
RegisteredName {
normalized: self.normalized,
registered_name: Cow::from(self.registered_name.into_owned()),
}
}
pub fn is_normalized(&self) -> bool {
self.normalized
}
pub fn normalize(&mut self) {
if !self.normalized {
unsafe { normalize_string(&mut self.registered_name.to_mut(), false) };
self.normalized = true;
}
}
}
impl AsRef<[u8]> for RegisteredName<'_> {
fn as_ref(&self) -> &[u8] {
self.registered_name.as_bytes()
}
}
impl AsRef<str> for RegisteredName<'_> {
fn as_ref(&self) -> &str {
&self.registered_name
}
}
impl Deref for RegisteredName<'_> {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.registered_name
}
}
impl Display for RegisteredName<'_> {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str(&self.registered_name)
}
}
impl Eq for RegisteredName<'_> {}
impl<'name> From<RegisteredName<'name>> for String {
fn from(value: RegisteredName<'name>) -> String {
value.to_string()
}
}
impl Hash for RegisteredName<'_> {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
percent_encoded_hash(self.registered_name.as_bytes(), state, false);
}
}
impl PartialEq for RegisteredName<'_> {
fn eq(&self, other: &RegisteredName) -> bool {
*self == *other.as_bytes()
}
}
impl PartialEq<[u8]> for RegisteredName<'_> {
fn eq(&self, other: &[u8]) -> bool {
percent_encoded_equality(self.registered_name.as_bytes(), other, false)
}
}
impl<'name> PartialEq<RegisteredName<'name>> for [u8] {
fn eq(&self, other: &RegisteredName<'name>) -> bool {
other == self
}
}
impl<'a> PartialEq<&'a [u8]> for RegisteredName<'_> {
fn eq(&self, other: &&'a [u8]) -> bool {
self == *other
}
}
impl<'a, 'name> PartialEq<RegisteredName<'name>> for &'a [u8] {
fn eq(&self, other: &RegisteredName<'name>) -> bool {
other == *self
}
}
impl PartialEq<str> for RegisteredName<'_> {
fn eq(&self, other: &str) -> bool {
self == other.as_bytes()
}
}
impl<'name> PartialEq<RegisteredName<'name>> for str {
fn eq(&self, other: &RegisteredName<'name>) -> bool {
other == self.as_bytes()
}
}
impl<'a> PartialEq<&'a str> for RegisteredName<'_> {
fn eq(&self, other: &&'a str) -> bool {
self == other.as_bytes()
}
}
impl<'a, 'name> PartialEq<RegisteredName<'name>> for &'a str {
fn eq(&self, other: &RegisteredName<'name>) -> bool {
other == self.as_bytes()
}
}
impl<'name> TryFrom<&'name [u8]> for RegisteredName<'name> {
type Error = RegisteredNameError;
fn try_from(value: &'name [u8]) -> Result<Self, Self::Error> {
match Host::try_from(value) {
Ok(Host::RegisteredName(name)) => Ok(name),
_ => Err(RegisteredNameError),
}
}
}
impl<'name> TryFrom<&'name str> for RegisteredName<'name> {
type Error = RegisteredNameError;
fn try_from(value: &'name str) -> Result<Self, Self::Error> {
RegisteredName::try_from(value.as_bytes())
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Username<'username> {
normalized: bool,
username: Cow<'username, str>,
}
impl Username<'_> {
pub fn as_borrowed(&self) -> Username {
use self::Cow::*;
let username = match &self.username {
Borrowed(borrowed) => *borrowed,
Owned(owned) => owned.as_str(),
};
Username {
normalized: self.normalized,
username: Cow::Borrowed(username),
}
}
pub fn as_str(&self) -> &str {
&self.username
}
pub fn into_owned(self) -> Username<'static> {
Username {
normalized: self.normalized,
username: Cow::from(self.username.into_owned()),
}
}
pub fn is_normalized(&self) -> bool {
self.normalized
}
pub fn normalize(&mut self) {
if !self.normalized {
unsafe { normalize_string(&mut self.username.to_mut(), true) };
self.normalized = true;
}
}
}
impl AsRef<[u8]> for Username<'_> {
fn as_ref(&self) -> &[u8] {
self.username.as_bytes()
}
}
impl AsRef<str> for Username<'_> {
fn as_ref(&self) -> &str {
&self.username
}
}
impl Deref for Username<'_> {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.username
}
}
impl Display for Username<'_> {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str(&self.username)
}
}
impl<'username> Eq for Username<'username> {}
impl<'username> From<Username<'username>> for String {
fn from(value: Username<'username>) -> String {
value.to_string()
}
}
impl Hash for Username<'_> {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
percent_encoded_hash(self.username.as_bytes(), state, true);
}
}
impl PartialEq for Username<'_> {
fn eq(&self, other: &Username) -> bool {
*self == *other.as_bytes()
}
}
impl PartialEq<[u8]> for Username<'_> {
fn eq(&self, other: &[u8]) -> bool {
percent_encoded_equality(self.username.as_bytes(), other, true)
}
}
impl<'username> PartialEq<Username<'username>> for [u8] {
fn eq(&self, other: &Username<'username>) -> bool {
other == self
}
}
impl<'a> PartialEq<&'a [u8]> for Username<'_> {
fn eq(&self, other: &&'a [u8]) -> bool {
self == *other
}
}
impl<'a, 'username> PartialEq<Username<'username>> for &'a [u8] {
fn eq(&self, other: &Username<'username>) -> bool {
other == *self
}
}
impl PartialEq<str> for Username<'_> {
fn eq(&self, other: &str) -> bool {
self == other.as_bytes()
}
}
impl<'username> PartialEq<Username<'username>> for str {
fn eq(&self, other: &Username<'username>) -> bool {
other == self.as_bytes()
}
}
impl<'a> PartialEq<&'a str> for Username<'_> {
fn eq(&self, other: &&'a str) -> bool {
self == other.as_bytes()
}
}
impl<'a, 'username> PartialEq<Username<'username>> for &'a str {
fn eq(&self, other: &Username<'username>) -> bool {
other == self.as_bytes()
}
}
impl<'username> TryFrom<&'username [u8]> for Username<'username> {
type Error = UsernameError;
fn try_from(value: &'username [u8]) -> Result<Self, Self::Error> {
let normalized = check_user_info(value, true)?;
Ok(Username {
normalized,
username: Cow::from(unsafe { str::from_utf8_unchecked(value) }),
})
}
}
impl<'username> TryFrom<&'username str> for Username<'username> {
type Error = UsernameError;
fn try_from(value: &'username str) -> Result<Self, Self::Error> {
Username::try_from(value.as_bytes())
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum AuthorityError {
Host(HostError),
Password(PasswordError),
Port(PortError),
Username(UsernameError),
}
impl Display for AuthorityError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
use self::AuthorityError::*;
match self {
Host(error) => error.fmt(formatter),
Password(error) => error.fmt(formatter),
Port(error) => error.fmt(formatter),
Username(error) => error.fmt(formatter),
}
}
}
impl Error for AuthorityError {}
impl From<Infallible> for AuthorityError {
fn from(_: Infallible) -> Self {
AuthorityError::Host(HostError::InvalidIPv4OrRegisteredNameCharacter)
}
}
impl From<HostError> for AuthorityError {
fn from(value: HostError) -> Self {
AuthorityError::Host(value)
}
}
impl From<PasswordError> for AuthorityError {
fn from(value: PasswordError) -> Self {
AuthorityError::Password(value)
}
}
impl From<PortError> for AuthorityError {
fn from(value: PortError) -> Self {
AuthorityError::Port(value)
}
}
impl From<UserInfoError> for AuthorityError {
fn from(value: UserInfoError) -> Self {
use self::AuthorityError::*;
match value {
UserInfoError::Password(error) => Password(error),
UserInfoError::Username(error) => Username(error),
}
}
}
impl From<UsernameError> for AuthorityError {
fn from(value: UsernameError) -> Self {
AuthorityError::Username(value)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum HostError {
AddressMechanismNotSupported,
InvalidIPv4OrRegisteredNameCharacter,
InvalidIPv6Character,
InvalidIPv6Format,
InvalidIPvFutureCharacter,
}
impl Display for HostError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
use self::HostError::*;
match self {
AddressMechanismNotSupported => {
write!(formatter, "host address mechanism not supported")
}
InvalidIPv4OrRegisteredNameCharacter => {
write!(formatter, "invalid host IPv4 or registered name character")
}
InvalidIPv6Character => write!(formatter, "invalid host IPv6 character"),
InvalidIPv6Format => write!(formatter, "invalid host IPv6 format"),
InvalidIPvFutureCharacter => write!(formatter, "invalid host IPvFuture character"),
}
}
}
impl Error for HostError {}
impl From<Infallible> for HostError {
fn from(_: Infallible) -> Self {
HostError::InvalidIPv4OrRegisteredNameCharacter
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum PasswordError {
InvalidCharacter,
InvalidPercentEncoding,
}
impl Display for PasswordError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
use self::PasswordError::*;
match self {
InvalidCharacter => write!(formatter, "invalid password character"),
InvalidPercentEncoding => write!(formatter, "invalid password percent encoding"),
}
}
}
impl Error for PasswordError {}
impl From<Infallible> for PasswordError {
fn from(_: Infallible) -> Self {
PasswordError::InvalidCharacter
}
}
impl From<UserInfoError> for PasswordError {
fn from(value: UserInfoError) -> Self {
match value {
UserInfoError::Password(error) => error,
_ => panic!("unexpected user info error"),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum PortError {
InvalidCharacter,
Overflow,
}
impl Display for PortError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
use self::PortError::*;
match self {
InvalidCharacter => write!(formatter, "invalid port character"),
Overflow => write!(formatter, "port overflow"),
}
}
}
impl Error for PortError {}
impl From<Infallible> for PortError {
fn from(_: Infallible) -> Self {
PortError::InvalidCharacter
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct RegisteredNameError;
impl Display for RegisteredNameError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "invalid registered name")
}
}
impl Error for RegisteredNameError {}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
enum UserInfoError {
Password(PasswordError),
Username(UsernameError),
}
impl Display for UserInfoError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
use self::UserInfoError::*;
match self {
Password(error) => error.fmt(formatter),
Username(error) => error.fmt(formatter),
}
}
}
impl Error for UserInfoError {}
impl From<Infallible> for UserInfoError {
fn from(_: Infallible) -> Self {
UserInfoError::Username(UsernameError::InvalidCharacter)
}
}
impl From<PasswordError> for UserInfoError {
fn from(value: PasswordError) -> Self {
UserInfoError::Password(value)
}
}
impl From<UsernameError> for UserInfoError {
fn from(value: UsernameError) -> Self {
UserInfoError::Username(value)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum UsernameError {
ContainsColon,
InvalidCharacter,
InvalidPercentEncoding,
}
impl Display for UsernameError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
use self::UsernameError::*;
match self {
ContainsColon => write!(formatter, "username contains a colon character"),
InvalidCharacter => write!(formatter, "invalid username character"),
InvalidPercentEncoding => write!(formatter, "invalid username percent encoding"),
}
}
}
impl Error for UsernameError {}
impl From<Infallible> for UsernameError {
fn from(_: Infallible) -> Self {
UsernameError::InvalidCharacter
}
}
impl From<UserInfoError> for UsernameError {
fn from(value: UserInfoError) -> Self {
match value {
UserInfoError::Username(error) => error,
_ => panic!("unexpected user info error"),
}
}
}
fn check_ipv4_or_registered_name(value: &[u8]) -> (bool, bool) {
let mut bytes = value.iter();
let mut normalized = true;
while let Some(&byte) = bytes.next() {
match IPV4_AND_REGISTERED_NAME_CHAR_MAP[byte as usize] {
0 => return (false, false),
b'%' => match get_percent_encoded_value(bytes.next().cloned(), bytes.next().cloned()) {
Ok((hex_value, uppercase)) => {
if !uppercase || UNRESERVED_CHAR_MAP[hex_value as usize] != 0 {
normalized = false;
}
}
_ => return (false, false),
},
b'A'..=b'Z' => normalized = false,
_ => (),
}
}
(true, normalized)
}
fn check_ipv6(value: &[u8]) -> bool {
for &byte in value {
if !byte.is_ascii_hexdigit() && byte != b':' && byte != b'.' {
return false;
}
}
true
}
fn check_ipvfuture(value: &[u8]) -> bool {
for &byte in value {
if let 0 = IPV_FUTURE_CHAR_MAP[byte as usize] {
return false;
}
}
true
}
fn check_user_info(value: &[u8], is_username: bool) -> Result<bool, UserInfoError> {
let mut bytes = value.iter();
let mut normalized = true;
while let Some(&byte) = bytes.next() {
match USER_INFO_CHAR_MAP[byte as usize] {
0 => {
return if is_username {
Err(UsernameError::InvalidCharacter.into())
} else {
Err(PasswordError::InvalidCharacter.into())
};
}
b'%' => match get_percent_encoded_value(bytes.next().cloned(), bytes.next().cloned()) {
Ok((hex_value, uppercase)) => {
if !uppercase || UNRESERVED_CHAR_MAP[hex_value as usize] != 0 {
normalized = false;
}
}
Err(_) => {
return if is_username {
Err(UsernameError::InvalidPercentEncoding.into())
} else {
Err(PasswordError::InvalidPercentEncoding.into())
};
}
},
b':' if is_username => return Err(UsernameError::ContainsColon.into()),
_ => (),
}
}
Ok(normalized)
}
pub(crate) fn parse_authority(value: &[u8]) -> Result<(Authority, &[u8]), AuthorityError> {
let mut at_index = None;
let mut last_colon_index = None;
let mut end_index = value.len();
for (index, &byte) in value.iter().enumerate() {
match byte {
b'@' => {
if at_index.is_none() {
at_index = Some(index);
last_colon_index = None;
}
}
b':' => last_colon_index = Some(index),
b']' => last_colon_index = None,
b'/' | b'?' | b'#' => {
end_index = index;
break;
}
_ => (),
}
}
let (value, rest) = value.split_at(end_index);
let (username, password, host_start_index) = match at_index {
Some(index) => {
let (username, password) = parse_user_info(&value[..index])?;
(Some(username), password, index + 1)
}
None => (None, None, 0),
};
let (host, port) = match last_colon_index {
Some(index) => (
Host::try_from(&value[host_start_index..index])?,
parse_port(&value[index + 1..])?,
),
None => (Host::try_from(&value[host_start_index..])?, None),
};
let authority = Authority {
host,
port,
password,
username,
};
Ok((authority, rest))
}
pub fn parse_port(value: &[u8]) -> Result<Option<u16>, PortError> {
if value.is_empty() {
Ok(None)
} else {
let mut port = 0u16;
for &byte in value {
if !byte.is_ascii_digit() {
return Err(PortError::InvalidCharacter);
}
port = port.checked_mul(10).ok_or(PortError::Overflow)?;
port = port
.checked_add((byte - b'0').into())
.ok_or(PortError::Overflow)?;
}
Ok(Some(port))
}
}
fn parse_user_info(value: &[u8]) -> Result<(Username, Option<Password>), UserInfoError> {
let mut bytes = value.iter().enumerate();
let mut first_colon_index = None;
let mut password_normalized = true;
let mut username_normalized = true;
while let Some((index, &byte)) = bytes.next() {
match USER_INFO_CHAR_MAP[byte as usize] {
0 => {
return if first_colon_index.is_some() {
Err(PasswordError::InvalidCharacter.into())
} else {
Err(UsernameError::InvalidCharacter.into())
}
}
b'%' => match get_percent_encoded_value(
bytes.next().map(|(_, &byte)| byte),
bytes.next().map(|(_, &byte)| byte),
) {
Ok((hex_value, uppercase)) => {
if !uppercase || UNRESERVED_CHAR_MAP[hex_value as usize] != 0 {
if first_colon_index.is_some() {
password_normalized = false;
} else {
username_normalized = false;
}
}
}
Err(_) => {
return if first_colon_index.is_some() {
Err(PasswordError::InvalidPercentEncoding.into())
} else {
Err(UsernameError::InvalidPercentEncoding.into())
}
}
},
b':' => {
if first_colon_index.is_none() {
first_colon_index = Some(index);
}
}
_ => (),
}
}
Ok(match first_colon_index {
Some(index) => {
let username = Username {
normalized: username_normalized,
username: Cow::from(unsafe { str::from_utf8_unchecked(&value[..index]) }),
};
let password = Password {
normalized: password_normalized,
password: Cow::from(unsafe { str::from_utf8_unchecked(&value[index + 1..]) }),
};
(username, Some(password))
}
_ => {
let username = Username {
normalized: username_normalized,
username: Cow::from(unsafe { str::from_utf8_unchecked(value) }),
};
(username, None)
}
})
}