1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
use super::{headermap::HeaderMap, method::Method};
use anyhow::{anyhow, bail};
use std::{fmt::Display, str::FromStr};
macro_rules! header {
($hname:literal, struct $name:ident($type:ty)) => {
#[derive(Debug)]
pub struct $name(pub $type);
impl Header for $name {
const NAME: &'static str = $hname;
}
impl Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl FromStr for $name {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok($name(<$type>::from_str(s)?))
}
}
};
}
pub trait Header: FromStr<Err = anyhow::Error> + Display {
const NAME: &'static str;
}
header!("Content-Length", struct ContentLength(usize));
header!("Call-ID", struct CallID(String));
header!("Via", struct Via(String));
header!("Contact", struct Contact(String));
header!("Max-Forwards", struct MaxForwards(usize));
header!("From", struct From(String));
header!("To", struct To(String));
header!("User-Agent", struct UserAgent(String));
header!("Allow", struct Allow(String));
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct CSeq(pub u32, pub Method);
impl Header for CSeq {
const NAME: &'static str = "CSeq";
}
impl Display for CSeq {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.0, self.1)
}
}
impl FromStr for CSeq {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (seq, method) = s.split_once(" ").ok_or(anyhow!("method missing"))?;
Ok(CSeq(seq.parse()?, method.parse()?))
}
}
#[derive(Debug)]
pub struct WWWAuthenticate {
pub realm: String,
pub nonce: String,
}
impl Header for WWWAuthenticate {
const NAME: &'static str = "WWW-Authenticate";
}
impl Display for WWWAuthenticate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Digest realm={:?}, nonce={:?}", self.realm, self.nonce)
}
}
impl FromStr for WWWAuthenticate {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
// TODO this is totally wrong
let kvs = s
.strip_prefix("Digest ")
.ok_or(anyhow!("type not digest"))?
.split(", ")
.map(|e| {
let Some((k, v)) = e.split_once("=") else {
bail!("not a KV-pair")
};
Ok((
k.to_string(),
v.strip_prefix("\"")
.ok_or(anyhow!("start quote missing"))?
.strip_suffix("\"")
.ok_or(anyhow!("end quote missing"))?
.to_string(),
))
})
.try_collect::<HeaderMap>()?;
Ok(WWWAuthenticate {
realm: kvs
.get_raw("realm")
.ok_or(anyhow!("realm missing"))?
.to_string(),
nonce: kvs
.get_raw("nonce")
.ok_or(anyhow!("nonce missing"))?
.to_string(),
})
}
}
|