-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathcomponent_id.rs
More file actions
81 lines (73 loc) · 3.02 KB
/
Copy pathcomponent_id.rs
File metadata and controls
81 lines (73 loc) · 3.02 KB
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
use super::{
component_name::{DerivedComponentName, HttpMessageComponentName},
component_param::{HttpMessageComponentParam, HttpMessageComponentParams},
};
use crate::error::{HttpSigError, HttpSigResult};
use sfv::Parser;
/* ---------------------------------------------------------------- */
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
/// Http message component id
pub struct HttpMessageComponentId {
/// Http message component name
pub name: HttpMessageComponentName,
/// Http message component params
pub params: HttpMessageComponentParams,
}
impl HttpMessageComponentId {
/// Add `req` field param to the component, which is used to generate signature input for response from its corresponding request.
pub fn add_req_param(&mut self) {
self.params.0.insert(HttpMessageComponentParam::Req);
}
}
impl std::fmt::Display for HttpMessageComponentId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}{}", self.name, self.params)
}
}
impl TryFrom<&str> for HttpMessageComponentId {
type Error = HttpSigError;
/// Parse http message component id from string
/// Accept `"<name>";<params>` or `"<name>"` (with double quotations).
/// But accept string in the form of `<name>` (without double quotations) when no param is given
fn try_from(val: &str) -> HttpSigResult<Self> {
let val = val.trim();
let item: sfv::Item = if !val.starts_with('"') && !val.ends_with('"') && !val.is_empty() && !val.contains('"') {
// maybe insufficient, but it's enough for now
Parser::new(format!("\"{val}\"").as_str())
.parse()
.map_err(|e| HttpSigError::ParseSFVError(e.to_string()))?
// Parser::parse_item(format!("\"{val}\"").as_bytes()).map_err(|e| HttpSigError::ParseSFVError(e.to_string()))?
} else {
Parser::new(val)
.parse()
.map_err(|e| HttpSigError::ParseSFVError(e.to_string()))?
// Parser::parse_item(val.as_bytes()).map_err(|e| HttpSigError::ParseSFVError(e.to_string()))?
};
let res = Self {
name: HttpMessageComponentName::try_from(&item.bare_item)?,
params: HttpMessageComponentParams::try_from(&item.params)?,
};
// assert for query param
if res.params.0.iter().any(|v| matches!(v, &HttpMessageComponentParam::Name(_)))
&& !matches!(res.name, HttpMessageComponentName::Derived(DerivedComponentName::QueryParam))
{
return Err(HttpSigError::InvalidComponentId(format!(
"Invalid http message component id: {res}"
)));
}
// assert for http field components
// only req field param is allowed
if res.params.0.iter().any(|v| {
matches!(v, &HttpMessageComponentParam::Bs)
|| matches!(v, &HttpMessageComponentParam::Sf)
|| matches!(v, &HttpMessageComponentParam::Tr)
|| matches!(v, &HttpMessageComponentParam::Key(_))
}) && !matches!(res.name, HttpMessageComponentName::HttpField(_))
{
return Err(HttpSigError::InvalidComponentId(format!(
"Invalid http message component id: {res}"
)));
}
Ok(res)
}
}