use core::{marker, fmt};
use core::net::IpAddr;
const FORWARDED_SEP: char = ',';
const ENTRY_SEP: char = ';';
const PAIR_SEP: char = '=';
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ForwardedNode<'a> {
Ip(IpAddr),
Name(&'a str),
Unknown,
}
impl<'a> ForwardedNode<'a> {
#[inline(always)]
fn parse_name(name: &'a str) -> Self {
if let Ok(name) = name.parse() {
return Self::Ip(name);
} else {
return Self::Name(name)
}
}
#[inline(always)]
pub const fn ip(&self) -> Option<IpAddr> {
match self {
Self::Ip(ip) => Some(*ip),
_ => None
}
}
#[inline]
pub fn parse_x_node(mut node: &'a str) -> Self {
node = node.trim();
match node.parse() {
Ok(ip) => ForwardedNode::Ip(ip),
Err(_) => ForwardedNode::Name(node)
}
}
pub fn parse_node(mut node: &'a str) -> Self {
node = node.trim_matches('"');
if node.eq_ignore_ascii_case("unknown") {
return Self::Unknown;
}
if let Some(mut ipv6) = node.strip_prefix('[') {
if let Some(end_addr_idx) = ipv6.find(']') {
ipv6 = &ipv6[..end_addr_idx];
return Self::parse_name(ipv6);
} else {
return Self::Name(ipv6);
}
}
let mut node = node.rsplit(':');
let port_or_ip = node.next().unwrap();
let ip = if let Some(ip) = node.next() {
ip
} else {
port_or_ip
};
ForwardedNode::parse_name(ip)
}
}
impl fmt::Display for ForwardedNode<'_> {
#[inline(always)]
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Ip(ip) => fmt::Display::fmt(&ip, fmt),
Self::Name(ip) => fmt.write_str(&ip),
Self::Unknown => fmt.write_str("-"),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ForwardedValue<'a> {
By(ForwardedNode<'a>),
For(ForwardedNode<'a>),
Host(&'a str),
Protocol(&'a str)
}
pub struct ForwardedEntryIter<'a> {
components: core::str::Split<'a, char>,
}
impl<'a> ForwardedEntryIter<'a> {
pub fn parse_entry(value: &'a str) -> Self {
Self {
components: value.split(ENTRY_SEP)
}
}
}
impl<'a> Iterator for ForwardedEntryIter<'a> {
type Item = ForwardedValue<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(value) = self.components.next() {
let mut pairs = value.splitn(2, PAIR_SEP);
let key = pairs.next().unwrap();
if key.eq_ignore_ascii_case("for") {
if let Some(node) = pairs.next() {
return Some(ForwardedValue::For(ForwardedNode::parse_node(node)))
}
} else if key.eq_ignore_ascii_case("by") {
if let Some(node) = pairs.next() {
return Some(ForwardedValue::By(ForwardedNode::parse_node(node)))
}
} else if key.eq_ignore_ascii_case("proto") {
if let Some(proto) = pairs.next() {
return Some(ForwardedValue::Protocol(proto))
}
} else if key.eq_ignore_ascii_case("host") {
if let Some(host) = pairs.next() {
return Some(ForwardedValue::Host(host))
}
}
}
None
}
}
pub struct ForwardedIter<'a, I> {
components: I,
_lifetime: marker::PhantomData<&'a I>,
}
impl<'a, I: Iterator<Item = &'a str> + 'a> Iterator for ForwardedIter<'a, I> {
type Item = ForwardedEntryIter<'a>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.components.next().map(ForwardedEntryIter::parse_entry)
}
}
pub struct ForwardedForIter<'a, I> {
components: I,
_lifetime: marker::PhantomData<&'a I>,
}
impl<'a, I: Iterator<Item = &'a str> + 'a> Iterator for ForwardedForIter<'a, I> {
type Item = ForwardedNode<'a>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
while let Some(value) = self.components.next() {
let mut pairs = value.splitn(2, PAIR_SEP);
let key = pairs.next().unwrap();
if key.eq_ignore_ascii_case("for") {
if let Some(node) = pairs.next() {
return Some(ForwardedNode::parse_node(node))
}
}
}
None
}
}
pub struct XForwardedForIter<'a, I> {
components: I,
_lifetime: marker::PhantomData<&'a I>,
}
impl<'a, I: Iterator<Item = &'a str> + 'a> Iterator for XForwardedForIter<'a, I> {
type Item = ForwardedNode<'a>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.components.next().map(ForwardedNode::parse_x_node)
}
}
#[inline(always)]
pub fn parse_forwarded<'a>(value: &'a str) -> ForwardedIter<'a, impl Iterator<Item = &'a str>> {
ForwardedIter {
components: value.split(FORWARDED_SEP),
_lifetime: marker::PhantomData,
}
}
#[inline(always)]
pub fn parse_forwarded_rev<'a>(value: &'a str) -> ForwardedIter<'a, impl Iterator<Item = &'a str>> {
ForwardedIter {
components: value.rsplit(FORWARDED_SEP),
_lifetime: marker::PhantomData,
}
}
#[inline(always)]
pub fn parse_forwarded_for<'a>(value: &'a str) -> ForwardedForIter<'a, impl Iterator<Item = &'a str>> {
ForwardedForIter {
components: value.split([FORWARDED_SEP, ENTRY_SEP]),
_lifetime: marker::PhantomData,
}
}
#[inline(always)]
pub fn parse_forwarded_for_rev<'a>(value: &'a str) -> ForwardedForIter<'a, impl Iterator<Item = &'a str>> {
ForwardedForIter {
components: value.rsplit([FORWARDED_SEP, ENTRY_SEP]),
_lifetime: marker::PhantomData,
}
}
#[inline(always)]
pub fn parse_x_forwarded_for<'a>(value: &'a str) -> XForwardedForIter<'a, impl Iterator<Item = &'a str>> {
XForwardedForIter {
components: value.split(FORWARDED_SEP),
_lifetime: marker::PhantomData,
}
}
#[inline(always)]
pub fn parse_x_forwarded_for_rev<'a>(value: &'a str) -> XForwardedForIter<'a, impl Iterator<Item = &'a str>> {
XForwardedForIter {
components: value.rsplit(FORWARDED_SEP),
_lifetime: marker::PhantomData,
}
}