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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
use super::{headermap::HeaderMap, method::Method, uri::Uri};
use anyhow::{anyhow, bail, Result};
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!("Content-Type", struct ContentType(String));
header!("Call-ID", struct CallID(String));
header!("Via", struct Via(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.trim().to_string(), v.trim().to_string()))
})
.try_collect::<HeaderMap>()?;
Ok(WWWAuthenticate {
realm: unquote(
&kvs.get_raw("realm")
.ok_or(anyhow!("realm missing"))?
.to_string(),
)?,
nonce: unquote(
&kvs.get_raw("nonce")
.ok_or(anyhow!("nonce missing"))?
.to_string(),
)?,
})
}
}
#[derive(Debug, Clone)]
pub struct Authorization {
pub username: String,
pub realm: String,
pub uri: String,
pub nonce: String,
pub response: String,
}
impl Header for Authorization {
const NAME: &'static str = "Authorization";
}
impl Display for Authorization {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self {
username,
realm,
nonce,
uri,
response,
} = self;
write!(
f,
"Digest username={username:?},\r\n realm={realm:?},\r\n nonce={nonce:?},\r\n uri={uri:?},\r\n response={response:?},\r\n algorithm=MD5"
)
}
}
impl FromStr for Authorization {
type Err = anyhow::Error;
fn from_str(_s: &str) -> Result<Self, Self::Err> {
todo!()
}
}
pub fn unquote(v: &str) -> Result<String> {
Ok(v.strip_prefix("\"")
.ok_or(anyhow!("start quote missing"))?
.strip_suffix("\"")
.ok_or(anyhow!("end quote missing"))?
.to_string())
}
#[derive(Debug)]
pub struct Contact {
pub display_name: Option<String>,
pub uri: Uri,
pub params: String,
}
impl Header for Contact {
const NAME: &'static str = "Contact";
}
impl Display for Contact {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self {
display_name,
uri,
params,
} = self;
if let Some(display_name) = display_name {
write!(f, "{display_name} <{uri}>{params}")
} else {
write!(f, "<{uri}>{params}")
}
}
}
impl FromStr for Contact {
type Err = anyhow::Error;
fn from_str(_s: &str) -> Result<Self, Self::Err> {
todo!()
}
}
|