Skip to main content

http_msgsign_draft/sign/
params.rs

1use std::time::Duration;
2
3use http::{Request, Response};
4use indexmap::IndexSet;
5
6use crate::errors::{HttpPayloadSeekError, SignatureParamsError};
7use crate::sign::SignatureBase;
8use crate::sign::field::{TargetField, TimeOrDuration};
9
10#[derive(Debug, Clone)]
11pub struct SignatureParams {
12    targets: IndexSet<TargetField>,
13}
14
15pub struct SignatureParamsBuilder {
16    builder: Result<SignatureParams, SignatureParamsError>,
17}
18
19impl SignatureParams {
20    pub fn builder() -> SignatureParamsBuilder {
21        SignatureParamsBuilder {
22            builder: Ok(SignatureParams {
23                targets: Default::default(),
24            }),
25        }
26    }
27
28    pub(crate) fn seek_request<B>(
29        &self,
30        request: &Request<B>,
31    ) -> Result<SignatureBase, HttpPayloadSeekError> {
32        let seeked = self
33            .targets
34            .iter()
35            .map(|target| target.seek_request(request))
36            .collect::<Result<IndexSet<_>, _>>()?;
37
38        Ok(SignatureBase::from_components(seeked))
39    }
40
41    pub(crate) fn seek_response<B>(
42        &self,
43        response: &Response<B>,
44    ) -> Result<SignatureBase, HttpPayloadSeekError> {
45        let seeked = self
46            .targets
47            .iter()
48            .map(|target| target.seek_response(response))
49            .collect::<Result<IndexSet<_>, _>>()?;
50
51        Ok(SignatureBase::from_components(seeked))
52    }
53}
54
55impl SignatureParamsBuilder {
56    pub fn add_header<H>(self, header: H) -> Self
57    where
58        H: TryInto<http::HeaderName>,
59        H::Error: Into<http::Error>,
60    {
61        self.and_then(|mut params| {
62            let header = header.try_into().map_err(Into::into)?;
63            params.targets.insert(TargetField::HeaderField(header));
64            Ok(params)
65        })
66    }
67
68    pub fn add_request_target(self) -> Self {
69        self.and_then(|mut params| {
70            params.targets.insert(TargetField::RequestTarget);
71            Ok(params)
72        })
73    }
74
75    pub fn set_created(self) -> Self {
76        self.and_then(|mut params| {
77            params.targets.insert(TargetField::Created(None));
78            Ok(params)
79        })
80    }
81
82    pub fn set_expires(self, expires: impl Into<Duration>) -> Self {
83        self.and_then(|mut params| {
84            params
85                .targets
86                .insert(TargetField::Expires(TimeOrDuration::Duration(
87                    expires.into(),
88                )));
89            Ok(params)
90        })
91    }
92
93    pub fn build(self) -> Result<SignatureParams, SignatureParamsError> {
94        // If not specified, implementations MUST operate as if the field were specified
95        // with a single value, `(created)`, in the list of HTTP headers.
96        self.builder.map(|mut params| {
97            if params.targets.is_empty() {
98                params.targets.insert(TargetField::Created(None));
99            }
100            Ok(params)
101        })?
102    }
103
104    fn and_then<F>(self, f: F) -> Self
105    where
106        F: FnOnce(SignatureParams) -> Result<SignatureParams, SignatureParamsError>,
107    {
108        Self {
109            builder: self.builder.and_then(f),
110        }
111    }
112}