diff --git a/lib/src/message_component/component.rs b/lib/src/message_component/component.rs index a581e53..4268414 100644 --- a/lib/src/message_component/component.rs +++ b/lib/src/message_component/component.rs @@ -1,6 +1,8 @@ use super::parse::{build_derived_component, build_http_field_component}; +use super::{ + component_id::HttpMessageComponentId, component_name::HttpMessageComponentName, component_value::HttpMessageComponentValue, +}; use anyhow::{bail, ensure}; -use rustc_hash::FxHashSet as HashSet; /* ---------------------------------------------------------------- */ #[derive(Debug, Clone)] @@ -56,338 +58,13 @@ impl std::fmt::Display for HttpMessageComponent { } } -/* ---------------------------------------------------------------- */ -#[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 = anyhow::Error; - fn try_from(val: &str) -> std::result::Result { - let (name, params) = if val.contains(';') { - val.split_once(';').unwrap() - } else { - (val, "") - }; - Self::try_from((name, params)) - } -} - -impl TryFrom<(&str, &str)> for HttpMessageComponentId { - type Error = anyhow::Error; - fn try_from((name, params): (&str, &str)) -> std::result::Result { - let name = name.trim(); - let inner_name = if name.starts_with('"') && name.ends_with('"') { - name[1..name.len() - 1].to_string() - } else if !name.starts_with('"') && !name.ends_with('"') { - name.to_string() - } else { - bail!("Invalid http message component name: {}", name); - }; - - let res = Self { - name: HttpMessageComponentName::from(inner_name.as_ref()), - params: HttpMessageComponentParams::from(params), - }; - - // assert for query param - if res.params.0.iter().any(|v| matches!(v, &HttpMessageComponentParam::Name(_))) { - ensure!( - matches!(res.name, HttpMessageComponentName::Derived(DerivedComponentName::QueryParam)), - "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(_)) - }) { - ensure!( - matches!(res.name, HttpMessageComponentName::HttpField(_)), - "Invalid http message component id: {}", - res - ); - } - - Ok(res) - } -} - -/* ---------------------------------------------------------------- */ -#[derive(Debug, Clone, PartialEq, Eq)] -/// Http message component value -pub struct HttpMessageComponentValue { - /// inner value originally from http message header or derived from http message - inner: HttpMessageComponentValueInner, -} - -impl From<&str> for HttpMessageComponentValue { - fn from(val: &str) -> Self { - Self { - inner: HttpMessageComponentValueInner::String(val.to_string()), - } - } -} - -impl From<(&str, &str)> for HttpMessageComponentValue { - fn from((key, val): (&str, &str)) -> Self { - Self { - inner: HttpMessageComponentValueInner::KeyValue((key.to_string(), val.to_string())), - } - } -} - -impl std::fmt::Display for HttpMessageComponentValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.inner) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -/// Http message component value inner, simple string or key-value pair -enum HttpMessageComponentValueInner { - String(String), - KeyValue((String, String)), -} - -impl std::fmt::Display for HttpMessageComponentValueInner { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::String(val) => write!(f, "{}", val), - Self::KeyValue((_, val)) => write!(f, "{}", val), - } - } -} - -impl HttpMessageComponentValue { - /// Get key if pair, otherwise None - pub fn key(&self) -> Option<&str> { - match &self.inner { - HttpMessageComponentValueInner::String(_) => None, - HttpMessageComponentValueInner::KeyValue((key, _)) => Some(key.as_ref()), - } - } - /// Get key value connected with `=`, or just value - pub fn as_field_value(&self) -> String { - match &self.inner { - HttpMessageComponentValueInner::String(val) => val.to_owned(), - HttpMessageComponentValueInner::KeyValue((key, val)) => format!("{}={}", key, val), - } - } - /// Get value only - pub fn as_component_value(&self) -> &str { - match &self.inner { - HttpMessageComponentValueInner::String(val) => val.as_ref(), - HttpMessageComponentValueInner::KeyValue((_, val)) => val.as_ref(), - } - } -} - -/* ---------------------------------------------------------------- */ -#[derive(PartialEq, Eq, Hash, Debug, Clone)] -/// Http message component identifier -pub enum HttpMessageComponentName { - /// Http field component, which is in the form of `` without being wrapped by double quotations - HttpField(String), - /// Derived component - Derived(DerivedComponentName), -} - -impl From<&str> for HttpMessageComponentName { - fn from(val: &str) -> Self { - if val.starts_with('@') { - Self::Derived(DerivedComponentName::from(val)) - } else { - Self::HttpField(val.to_string()) - } - } -} - -impl std::fmt::Display for HttpMessageComponentName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::HttpField(val) => write!(f, "\"{}\"", val), - Self::Derived(val) => write!(f, "\"{}\"", val), - } - } -} - -/* ---------------------------------------------------------------- */ -#[derive(PartialEq, Eq, Hash, Debug, Clone)] -/// Http message component parameters that appends with `;` in the signature input -/// https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#secion-2.1 -pub enum HttpMessageComponentParam { - /// sf: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.1.1 - Sf, - /// key: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.1.2 - /// This will be encoded to `;key="..."` in the signature input - Key(String), - /// bs: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.1.3 - Bs, - // tr: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.1.4 - Tr, - // req: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.4 - Req, - // name: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#name-query-parameters - /// This will be encoded to `;name="..."` in the signature input - Name(String), -} - -impl From for String { - fn from(val: HttpMessageComponentParam) -> Self { - match val { - HttpMessageComponentParam::Sf => "sf".to_string(), - HttpMessageComponentParam::Key(val) => format!("key=\"{val}\""), - HttpMessageComponentParam::Bs => "bs".to_string(), - HttpMessageComponentParam::Tr => "tr".to_string(), - HttpMessageComponentParam::Req => "req".to_string(), - HttpMessageComponentParam::Name(v) => format!("name=\"{v}\""), - } - } -} -impl From<&str> for HttpMessageComponentParam { - fn from(val: &str) -> Self { - match val { - "sf" => Self::Sf, - "bs" => Self::Bs, - "tr" => Self::Tr, - "req" => Self::Req, - _ => { - if val.starts_with("key=\"") && val.ends_with('"') { - Self::Key(val[5..val.len() - 1].to_string()) - } else if val.starts_with("name=\"") && val.ends_with('"') { - Self::Name(val[6..val.len() - 1].to_string()) - } else { - panic!("Invalid http field param: {}", val) - } - } - } - } -} - -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct HttpMessageComponentParams(pub HashSet); -impl std::hash::Hash for HttpMessageComponentParams { - fn hash(&self, state: &mut H) { - let mut params = self.0.iter().map(|v| v.clone().into()).collect::>(); - params.sort(); - params.hash(state); - } -} -impl From<&str> for HttpMessageComponentParams { - fn from(val: &str) -> Self { - let mut hs = HashSet::default(); - val.split(';').for_each(|v| { - if !v.is_empty() { - let param = HttpMessageComponentParam::from(v); - hs.insert(param); - } - }); - Self(hs) - } -} -impl std::fmt::Display for HttpMessageComponentParams { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if !self.0.is_empty() { - write!( - f, - ";{}", - self.0.iter().map(|v| v.clone().into()).collect::>().join(";") - ) - } else { - Ok(()) - } - } -} - -/* ---------------------------------------------------------------- */ -#[derive(PartialEq, Eq, Clone, Hash, Debug)] -/// Derive components from http message, which is expressed as @method, @path, @authority, etc. in @signature-params -/// https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#name-derived-components -pub enum DerivedComponentName { - Method, - TargetUri, - Authority, - Scheme, - RequestTarget, - Path, - Query, - QueryParam, - Status, - SignatureParams, -} -impl AsRef for DerivedComponentName { - fn as_ref(&self) -> &str { - match self { - Self::Method => "@method", - Self::TargetUri => "@target-uri", - Self::Authority => "@authority", - Self::Scheme => "@scheme", - Self::RequestTarget => "@request-target", - Self::Path => "@path", - Self::Query => "@query", - Self::QueryParam => "@query-param", - Self::Status => "@status", - Self::SignatureParams => "@signature-params", - } - } -} -impl From for String { - fn from(val: DerivedComponentName) -> Self { - val.as_ref().to_string() - } -} -impl From<&str> for DerivedComponentName { - fn from(val: &str) -> Self { - match val { - "@method" => Self::Method, - "@target-uri" => Self::TargetUri, - "@authority" => Self::Authority, - "@scheme" => Self::Scheme, - "@request-target" => Self::RequestTarget, - "@path" => Self::Path, - "@query" => Self::Query, - "@query-param" => Self::QueryParam, - "@status" => Self::Status, - "@signature-params" => Self::SignatureParams, - _ => panic!("Invalid derived component: {}", val), - } - } -} - -impl std::fmt::Display for DerivedComponentName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", AsRef::::as_ref(self)) - } -} - /* ---------------------------------------------------------------- */ #[cfg(test)] mod tests { + use super::super::*; use super::*; + + use rustc_hash::FxHashSet as HashSet; #[test] fn test_from_serialized_string_derived() { let tuples = vec![ @@ -409,7 +86,6 @@ mod tests { } else { assert!(!comp.id.params.0.is_empty()); } - assert_eq!(comp.value.inner.to_string(), value); assert_eq!(comp.value.as_field_value(), value); assert_eq!(comp.value.key(), None); assert_eq!(comp.to_string(), format!("{}: {}", id, value)); @@ -425,7 +101,6 @@ mod tests { comp.id.params.0.get(&HttpMessageComponentParam::Name("key".to_string())), Some(&HttpMessageComponentParam::Name("key".to_string())) ); - assert_eq!(comp.value.inner.to_string(), value); assert_eq!(comp.value.as_field_value(), value); assert_eq!(comp.value.key(), None); assert_eq!(comp.to_string(), format!("{}: {}", id, value)); @@ -447,7 +122,7 @@ mod tests { } else { assert!(!comp.id.params.0.is_empty()); } - assert_eq!(comp.value.inner.to_string(), value); + assert_eq!(comp.value.as_field_value(), value); assert_eq!(comp.to_string(), format!("{}: {}", id, value)); } } diff --git a/lib/src/message_component/component_id.rs b/lib/src/message_component/component_id.rs new file mode 100644 index 0000000..6aea86d --- /dev/null +++ b/lib/src/message_component/component_id.rs @@ -0,0 +1,86 @@ +use anyhow::{bail, ensure}; + +use super::{ + component_name::{DerivedComponentName, HttpMessageComponentName}, + component_param::{HttpMessageComponentParam, HttpMessageComponentParams}, +}; + +/* ---------------------------------------------------------------- */ +#[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 = anyhow::Error; + fn try_from(val: &str) -> std::result::Result { + let (name, params) = if val.contains(';') { + val.split_once(';').unwrap() + } else { + (val, "") + }; + Self::try_from((name, params)) + } +} + +impl TryFrom<(&str, &str)> for HttpMessageComponentId { + type Error = anyhow::Error; + fn try_from((name, params): (&str, &str)) -> std::result::Result { + let name = name.trim(); + let inner_name = if name.starts_with('"') && name.ends_with('"') { + name[1..name.len() - 1].to_string() + } else if !name.starts_with('"') && !name.ends_with('"') { + name.to_string() + } else { + bail!("Invalid http message component name: {}", name); + }; + + let res = Self { + name: HttpMessageComponentName::from(inner_name.as_ref()), + params: HttpMessageComponentParams::from(params), + }; + + // assert for query param + if res.params.0.iter().any(|v| matches!(v, &HttpMessageComponentParam::Name(_))) { + ensure!( + matches!(res.name, HttpMessageComponentName::Derived(DerivedComponentName::QueryParam)), + "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(_)) + }) { + ensure!( + matches!(res.name, HttpMessageComponentName::HttpField(_)), + "Invalid http message component id: {}", + res + ); + } + + Ok(res) + } +} diff --git a/lib/src/message_component/component_name.rs b/lib/src/message_component/component_name.rs new file mode 100644 index 0000000..e9cc750 --- /dev/null +++ b/lib/src/message_component/component_name.rs @@ -0,0 +1,89 @@ +/* ---------------------------------------------------------------- */ +#[derive(PartialEq, Eq, Hash, Debug, Clone)] +/// Http message component identifier +pub enum HttpMessageComponentName { + /// Http field component, which is in the form of `` without being wrapped by double quotations + HttpField(String), + /// Derived component + Derived(DerivedComponentName), +} + +impl From<&str> for HttpMessageComponentName { + fn from(val: &str) -> Self { + if val.starts_with('@') { + Self::Derived(DerivedComponentName::from(val)) + } else { + Self::HttpField(val.to_string()) + } + } +} + +impl std::fmt::Display for HttpMessageComponentName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::HttpField(val) => write!(f, "\"{}\"", val), + Self::Derived(val) => write!(f, "\"{}\"", val), + } + } +} + +/* ---------------------------------------------------------------- */ +#[derive(PartialEq, Eq, Clone, Hash, Debug)] +/// Derive components from http message, which is expressed as @method, @path, @authority, etc. in @signature-params +/// https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#name-derived-components +pub enum DerivedComponentName { + Method, + TargetUri, + Authority, + Scheme, + RequestTarget, + Path, + Query, + QueryParam, + Status, + SignatureParams, +} +impl AsRef for DerivedComponentName { + fn as_ref(&self) -> &str { + match self { + Self::Method => "@method", + Self::TargetUri => "@target-uri", + Self::Authority => "@authority", + Self::Scheme => "@scheme", + Self::RequestTarget => "@request-target", + Self::Path => "@path", + Self::Query => "@query", + Self::QueryParam => "@query-param", + Self::Status => "@status", + Self::SignatureParams => "@signature-params", + } + } +} +impl From for String { + fn from(val: DerivedComponentName) -> Self { + val.as_ref().to_string() + } +} +impl From<&str> for DerivedComponentName { + fn from(val: &str) -> Self { + match val { + "@method" => Self::Method, + "@target-uri" => Self::TargetUri, + "@authority" => Self::Authority, + "@scheme" => Self::Scheme, + "@request-target" => Self::RequestTarget, + "@path" => Self::Path, + "@query" => Self::Query, + "@query-param" => Self::QueryParam, + "@status" => Self::Status, + "@signature-params" => Self::SignatureParams, + _ => panic!("Invalid derived component: {}", val), + } + } +} + +impl std::fmt::Display for DerivedComponentName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", AsRef::::as_ref(self)) + } +} diff --git a/lib/src/message_component/component_param.rs b/lib/src/message_component/component_param.rs new file mode 100644 index 0000000..4bbd077 --- /dev/null +++ b/lib/src/message_component/component_param.rs @@ -0,0 +1,91 @@ +use rustc_hash::FxHashSet as HashSet; + +/* ---------------------------------------------------------------- */ +#[derive(PartialEq, Eq, Hash, Debug, Clone)] +/// Http message component parameters that appends with `;` in the signature input +/// https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#secion-2.1 +pub enum HttpMessageComponentParam { + /// sf: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.1.1 + Sf, + /// key: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.1.2 + /// This will be encoded to `;key="..."` in the signature input + Key(String), + /// bs: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.1.3 + Bs, + // tr: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.1.4 + Tr, + // req: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#section-2.4 + Req, + // name: https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-19.html#name-query-parameters + /// This will be encoded to `;name="..."` in the signature input + Name(String), +} + +impl From for String { + fn from(val: HttpMessageComponentParam) -> Self { + match val { + HttpMessageComponentParam::Sf => "sf".to_string(), + HttpMessageComponentParam::Key(val) => format!("key=\"{val}\""), + HttpMessageComponentParam::Bs => "bs".to_string(), + HttpMessageComponentParam::Tr => "tr".to_string(), + HttpMessageComponentParam::Req => "req".to_string(), + HttpMessageComponentParam::Name(v) => format!("name=\"{v}\""), + } + } +} +impl From<&str> for HttpMessageComponentParam { + fn from(val: &str) -> Self { + match val { + "sf" => Self::Sf, + "bs" => Self::Bs, + "tr" => Self::Tr, + "req" => Self::Req, + _ => { + if val.starts_with("key=\"") && val.ends_with('"') { + Self::Key(val[5..val.len() - 1].to_string()) + } else if val.starts_with("name=\"") && val.ends_with('"') { + Self::Name(val[6..val.len() - 1].to_string()) + } else { + panic!("Invalid http field param: {}", val) + } + } + } + } +} + +#[derive(PartialEq, Eq, Debug, Clone)] +/// Http message component parameters +pub struct HttpMessageComponentParams(pub HashSet); + +impl std::hash::Hash for HttpMessageComponentParams { + fn hash(&self, state: &mut H) { + let mut params = self.0.iter().map(|v| v.clone().into()).collect::>(); + params.sort(); + params.hash(state); + } +} +impl From<&str> for HttpMessageComponentParams { + fn from(val: &str) -> Self { + let mut hs = HashSet::default(); + val.split(';').for_each(|v| { + if !v.is_empty() { + let param = HttpMessageComponentParam::from(v); + hs.insert(param); + } + }); + Self(hs) + } +} +impl std::fmt::Display for HttpMessageComponentParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if !self.0.is_empty() { + write!( + f, + ";{}", + self.0.iter().map(|v| v.clone().into()).collect::>().join(";") + ) + } else { + Ok(()) + } + } +} diff --git a/lib/src/message_component/component_value.rs b/lib/src/message_component/component_value.rs new file mode 100644 index 0000000..752ce6e --- /dev/null +++ b/lib/src/message_component/component_value.rs @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------- */ +#[derive(Debug, Clone, PartialEq, Eq)] +/// Http message component value +pub struct HttpMessageComponentValue { + /// inner value originally from http message header or derived from http message + inner: HttpMessageComponentValueInner, +} + +impl From<&str> for HttpMessageComponentValue { + fn from(val: &str) -> Self { + Self { + inner: HttpMessageComponentValueInner::String(val.to_string()), + } + } +} + +impl From<(&str, &str)> for HttpMessageComponentValue { + fn from((key, val): (&str, &str)) -> Self { + Self { + inner: HttpMessageComponentValueInner::KeyValue((key.to_string(), val.to_string())), + } + } +} + +impl std::fmt::Display for HttpMessageComponentValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.inner) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +/// Http message component value inner, simple string or key-value pair +enum HttpMessageComponentValueInner { + String(String), + KeyValue((String, String)), +} + +impl std::fmt::Display for HttpMessageComponentValueInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::String(val) => write!(f, "{}", val), + Self::KeyValue((_, val)) => write!(f, "{}", val), + } + } +} + +impl HttpMessageComponentValue { + /// Get key if pair, otherwise None + pub fn key(&self) -> Option<&str> { + match &self.inner { + HttpMessageComponentValueInner::String(_) => None, + HttpMessageComponentValueInner::KeyValue((key, _)) => Some(key.as_ref()), + } + } + /// Get key value connected with `=`, or just value + pub fn as_field_value(&self) -> String { + match &self.inner { + HttpMessageComponentValueInner::String(val) => val.to_owned(), + HttpMessageComponentValueInner::KeyValue((key, val)) => format!("{}={}", key, val), + } + } + /// Get value only + pub fn as_component_value(&self) -> &str { + match &self.inner { + HttpMessageComponentValueInner::String(val) => val.as_ref(), + HttpMessageComponentValueInner::KeyValue((_, val)) => val.as_ref(), + } + } +} diff --git a/lib/src/message_component/mod.rs b/lib/src/message_component/mod.rs index d8e1069..784f0b2 100644 --- a/lib/src/message_component/mod.rs +++ b/lib/src/message_component/mod.rs @@ -1,7 +1,12 @@ mod component; +mod component_id; +mod component_name; +mod component_param; +mod component_value; mod parse; -pub use component::{ - DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, HttpMessageComponentParam, - HttpMessageComponentValue, -}; +pub use component::HttpMessageComponent; +pub use component_id::HttpMessageComponentId; +pub use component_name::{DerivedComponentName, HttpMessageComponentName}; +pub use component_param::HttpMessageComponentParam; +pub use component_value::HttpMessageComponentValue; diff --git a/lib/src/message_component/parse.rs b/lib/src/message_component/parse.rs index 637dae0..a1fa5a3 100644 --- a/lib/src/message_component/parse.rs +++ b/lib/src/message_component/parse.rs @@ -1,13 +1,16 @@ use super::{ - HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, HttpMessageComponentParam, HttpMessageComponentValue, + component_name::DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, + HttpMessageComponentParam, HttpMessageComponentValue, }; use crate::trace::*; use anyhow::{bail, ensure}; use sfv::{Parser, SerializeValue}; - /// Build derived component from given id and its associated field values -pub(super) fn build_derived_component(id: &HttpMessageComponentId, field_values: &[String]) -> anyhow::Result { +pub(super) fn build_derived_component( + id: &HttpMessageComponentId, + field_values: &[String], +) -> anyhow::Result { let HttpMessageComponentName::Derived(derived_id) = &id.name else { bail!("invalid http message component name as derived component"); }; @@ -22,15 +25,15 @@ pub(super) fn build_derived_component(id: &HttpMessageComponentId, field_values: ); let value = match derived_id { - super::DerivedComponentName::Method => HttpMessageComponentValue::from(field_values[0].to_ascii_uppercase().as_ref()), - super::DerivedComponentName::TargetUri => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), - super::DerivedComponentName::Authority => HttpMessageComponentValue::from(field_values[0].to_ascii_lowercase().as_ref()), - super::DerivedComponentName::Scheme => HttpMessageComponentValue::from(field_values[0].to_ascii_lowercase().as_ref()), - super::DerivedComponentName::RequestTarget => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), - super::DerivedComponentName::Path => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), - super::DerivedComponentName::Query => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), - super::DerivedComponentName::Status => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), - super::DerivedComponentName::QueryParam => { + DerivedComponentName::Method => HttpMessageComponentValue::from(field_values[0].to_ascii_uppercase().as_ref()), + DerivedComponentName::TargetUri => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), + DerivedComponentName::Authority => HttpMessageComponentValue::from(field_values[0].to_ascii_lowercase().as_ref()), + DerivedComponentName::Scheme => HttpMessageComponentValue::from(field_values[0].to_ascii_lowercase().as_ref()), + DerivedComponentName::RequestTarget => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), + DerivedComponentName::Path => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), + DerivedComponentName::Query => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), + DerivedComponentName::Status => HttpMessageComponentValue::from(field_values[0].to_string().as_ref()), + DerivedComponentName::QueryParam => { let name = id.params.0.iter().find_map(|p| match p { HttpMessageComponentParam::Name(name) => Some(name), _ => None, @@ -46,7 +49,7 @@ pub(super) fn build_derived_component(id: &HttpMessageComponentId, field_values: .collect::>(); HttpMessageComponentValue::from(kvs.join(", ").as_ref()) } - super::DerivedComponentName::SignatureParams => { + DerivedComponentName::SignatureParams => { let value = field_values[0].to_string(); let opt_pair = value.trim().split_once('='); ensure!(opt_pair.is_some(), "invalid signature-params derived component"); @@ -60,7 +63,10 @@ pub(super) fn build_derived_component(id: &HttpMessageComponentId, field_values: /// Build http field component from given id and its associated field values /// NOTE: field_value must be ones of request for `req` param -pub(super) fn build_http_field_component(id: &HttpMessageComponentId, field_values: &[String]) -> anyhow::Result { +pub(super) fn build_http_field_component( + id: &HttpMessageComponentId, + field_values: &[String], +) -> anyhow::Result { let mut field_values = field_values.to_vec(); let params = &id.params;