diff --git a/ext-hyper/src/hyper_http.rs b/ext-hyper/src/hyper_http.rs index 1e6678a..75c11dc 100644 --- a/ext-hyper/src/hyper_http.rs +++ b/ext-hyper/src/hyper_http.rs @@ -5,7 +5,7 @@ use http::Request; use http_body::Body; use httpsig::prelude::{ message_component::{ - build_http_message_component, DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, + DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, HttpMessageComponentParam, }, HttpSignatureBase, HttpSignatureParams, SigningKey, VerifyingKey, @@ -233,7 +233,7 @@ fn extract_http_field_from_request( ensure!(field_values.iter().all(|v| v.is_ok()), "Failed to extract field values"); let field_values = field_values.into_iter().map(|v| v.unwrap().to_owned()).collect::>(); - build_http_message_component(id, &field_values) + HttpMessageComponent::try_from((id, field_values.as_slice())) } /// Extract derived component from hyper http request @@ -284,7 +284,7 @@ fn extract_derived_component_from_request( .collect::>(), }; - build_http_message_component(id, &field_values) + HttpMessageComponent::try_from((id, field_values.as_slice())) } /* --------------------------------------- */ diff --git a/lib/src/lib.rs b/lib/src/lib.rs index fe599c8..2ffb44f 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -8,7 +8,7 @@ mod util; pub mod prelude { pub mod message_component { pub use crate::message_component::{ - build_http_message_component, DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, + DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, HttpMessageComponentParam, }; } diff --git a/lib/src/message_component/component.rs b/lib/src/message_component/component.rs index b090bce..65622fa 100644 --- a/lib/src/message_component/component.rs +++ b/lib/src/message_component/component.rs @@ -1,5 +1,6 @@ use anyhow::{bail, ensure}; use rustc_hash::FxHashSet as HashSet; +use super::parse::{build_derived_component, build_http_field_component}; /* ---------------------------------------------------------------- */ #[derive(Debug, Clone)] @@ -11,11 +12,12 @@ pub struct HttpMessageComponent { pub value: HttpMessageComponentValue, } -impl HttpMessageComponent { - /// Create HttpMessageComponent from serialized string, i.e., `"": ` in the signature input - pub fn from_serialized_str(serialized_str: &str) -> std::result::Result { - let Some((id, value)) = serialized_str.split_once(':') else { - bail!("Invalid http message component: {}", serialized_str); +impl TryFrom<&str> for HttpMessageComponent { + type Error = anyhow::Error; + /// Create HttpMessageComponent from serialized string, i.e., `"": ` of lines in the signature base of HTTP header. + fn try_from(val: &str) -> Result { + let Some((id, value)) = val.split_once(':') else { + bail!("Invalid http message component: {}", val); }; let id = id.trim(); ensure_component_id(id)?; @@ -25,29 +27,18 @@ impl HttpMessageComponent { value: HttpMessageComponentValue::from(value.trim()), }) } +} + +impl TryFrom<(&HttpMessageComponentId, &[String])> for HttpMessageComponent { + type Error = anyhow::Error; - //Create an iterator of HttpMessageComponent from for a given http component id - // pub(crate) fn from_name_and_values(name: &str, values: impl Iterator) -> Vec { - // let name = HttpMessageComponentName::from(name); - // let iter = values - // .map(move |v| { - // // let params = match name { - // // HttpMessageComponentName::HttpField(_) => HttpMessageComponentParams::from(""), - // // HttpMessageComponentName::Derived(DerivedComponentName::QueryParam) => { - // // HttpMessageComponentParams::from(format!("name=\"{}\"", v)) - // // } - // // _ => HttpMessageComponentParams::from(""), - // // }; - // let res = Self { - // name: name.clone(), - // params: HttpMessageComponentParams(HashSet::default()), - // value: HttpMessageComponentValue::from(v.as_ref()), - // }; - // res - // }) - // .collect::>(); - // iter - // } + /// Build http message component from given id and its associated field values + fn try_from((id, field_values): (&HttpMessageComponentId, &[String])) -> Result { + match &id.name { + HttpMessageComponentName::HttpField(_) => build_http_field_component(id, field_values), + HttpMessageComponentName::Derived(_) => build_derived_component(id, field_values), + } + } } fn ensure_component_id(id: &str) -> anyhow::Result<()> { @@ -411,7 +402,7 @@ mod tests { ("\"@status\"", "200", DerivedComponentName::Status), ]; for (id, value, name) in tuples { - let comp = HttpMessageComponent::from_serialized_str(format!("{}: {}", id, value).as_ref()).unwrap(); + let comp = HttpMessageComponent::try_from(format!("{}: {}", id, value).as_ref()).unwrap(); assert_eq!(comp.id.name, HttpMessageComponentName::Derived(name)); if !id.contains(';') { assert_eq!(comp.id.params.0, HashSet::default()); @@ -428,7 +419,7 @@ mod tests { #[test] fn test_from_serialized_string_derived_query_params() { let (id, value, name) = ("\"@query-param\";name=\"key\"", "\"value\"", DerivedComponentName::QueryParam); - let comp = HttpMessageComponent::from_serialized_str(format!("{}: {}", id, value).as_ref()).unwrap(); + let comp = HttpMessageComponent::try_from(format!("{}: {}", id, value).as_ref()).unwrap(); assert_eq!(comp.id.name, HttpMessageComponentName::Derived(name)); assert_eq!( comp.id.params.0.get(&HttpMessageComponentParam::Name("key".to_string())), @@ -449,7 +440,7 @@ mod tests { ("\"x-empty-header\"", "", "x-empty-header"), ]; for (id, value, inner_name) in tuples { - let comp = HttpMessageComponent::from_serialized_str(format!("{}: {}", id, value).as_ref()).unwrap(); + let comp = HttpMessageComponent::try_from(format!("{}: {}", id, value).as_ref()).unwrap(); assert_eq!(comp.id.name, HttpMessageComponentName::HttpField(inner_name.to_string())); if !id.contains(';') { assert_eq!(comp.id.params.0, HashSet::default()); @@ -463,7 +454,7 @@ mod tests { #[test] fn test_from_serialized_string_http_field_params() { - let comp = HttpMessageComponent::from_serialized_str("\"example-header\";bs;tr: example-value").unwrap(); + let comp = HttpMessageComponent::try_from("\"example-header\";bs;tr: example-value").unwrap(); assert_eq!( comp.id.name, HttpMessageComponentName::HttpField("example-header".to_string()) @@ -478,7 +469,7 @@ mod tests { #[test] fn test_from_serialized_string_http_field_params_key() { - let comp = HttpMessageComponent::from_serialized_str("\"example-header\";key=\"hoge\": example-value").unwrap(); + let comp = HttpMessageComponent::try_from("\"example-header\";key=\"hoge\": example-value").unwrap(); assert_eq!( comp.id.name, HttpMessageComponentName::HttpField("example-header".to_string()) @@ -495,11 +486,11 @@ mod tests { fn test_field_params_derived_component() { // params check // only req field param is allowed - let comp = HttpMessageComponent::from_serialized_str("\"@method\";req: POST"); + let comp = HttpMessageComponent::try_from("\"@method\";req: POST"); assert!(comp.is_ok()); - let comp = HttpMessageComponent::from_serialized_str("\"@method\";bs: POST"); + let comp = HttpMessageComponent::try_from("\"@method\";bs: POST"); assert!(comp.is_err()); - let comp = HttpMessageComponent::from_serialized_str("\"@method\";key=\"hoge\": POST"); + let comp = HttpMessageComponent::try_from("\"@method\";key=\"hoge\": POST"); assert!(comp.is_err()); } } diff --git a/lib/src/message_component/mod.rs b/lib/src/message_component/mod.rs index e74b554..d8e1069 100644 --- a/lib/src/message_component/mod.rs +++ b/lib/src/message_component/mod.rs @@ -5,4 +5,3 @@ pub use component::{ DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, HttpMessageComponentParam, HttpMessageComponentValue, }; -pub use parse::build_http_message_component; diff --git a/lib/src/message_component/parse.rs b/lib/src/message_component/parse.rs index bbfe2ae..637dae0 100644 --- a/lib/src/message_component/parse.rs +++ b/lib/src/message_component/parse.rs @@ -5,19 +5,9 @@ use crate::trace::*; use anyhow::{bail, ensure}; use sfv::{Parser, SerializeValue}; -/// Build http message component from given id and its associated field values -pub fn build_http_message_component( - id: &HttpMessageComponentId, - field_values: &[String], -) -> anyhow::Result { - match &id.name { - super::HttpMessageComponentName::HttpField(_) => build_http_field_component(id, field_values), - super::HttpMessageComponentName::Derived(_) => build_derived_component(id, field_values), - } -} /// Build derived component from given id and its associated field values -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"); }; @@ -70,7 +60,7 @@ fn build_derived_component(id: &HttpMessageComponentId, field_values: &[String]) /// Build http field component from given id and its associated field values /// NOTE: field_value must be ones of request for `req` param -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; diff --git a/lib/src/signature_base.rs b/lib/src/signature_base.rs index f7d8dce..00f74ea 100644 --- a/lib/src/signature_base.rs +++ b/lib/src/signature_base.rs @@ -67,10 +67,10 @@ mod test { let signature_params = HttpSignatureParams::try_from(format!("({}){}", values.0, values.1).as_str()).unwrap(); let component_lines = vec![ - HttpMessageComponent::from_serialized_str("\"@method\": GET").unwrap(), - HttpMessageComponent::from_serialized_str("\"@path\": /").unwrap(), - HttpMessageComponent::from_serialized_str("\"date\": Tue, 07 Jun 2014 20:51:35 GMT").unwrap(), - HttpMessageComponent::from_serialized_str("\"content-digest\": sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:") + HttpMessageComponent::try_from("\"@method\": GET").unwrap(), + HttpMessageComponent::try_from("\"@path\": /").unwrap(), + HttpMessageComponent::try_from("\"date\": Tue, 07 Jun 2014 20:51:35 GMT").unwrap(), + HttpMessageComponent::try_from("\"content-digest\": sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:") .unwrap(), ]; let signature_base = HttpSignatureBase::try_new(&component_lines, &signature_params).unwrap();