Skip to main content

rustack_ses_http/
router.rs

1//! SES v1 request router.
2//!
3//! SES v1 uses the `awsQuery` protocol where requests are `POST /` with
4//! `Content-Type: application/x-www-form-urlencoded`. The operation is
5//! specified by the `Action=<OperationName>` form parameter.
6
7use rustack_ses_model::{error::SesError, operations::SesOperation};
8
9/// Resolve an SES v1 action string to an `SesOperation`.
10///
11/// # Errors
12///
13/// Returns `SesError` if the action is not recognized.
14pub fn resolve_action(action: &str) -> Result<SesOperation, SesError> {
15    SesOperation::from_name(action).ok_or_else(|| SesError::invalid_action(action))
16}
17
18/// Resolve an SES operation from parsed form parameters.
19///
20/// Looks for the `Action` parameter in the form body and maps it to
21/// the corresponding [`SesOperation`] variant.
22pub fn resolve_operation(params: &[(String, String)]) -> Result<SesOperation, SesError> {
23    let action = params
24        .iter()
25        .find(|(k, _)| k == "Action")
26        .map(|(_, v)| v.as_str())
27        .ok_or_else(SesError::missing_action)?;
28
29    resolve_action(action)
30}
31
32#[cfg(test)]
33mod tests {
34    use rustack_ses_model::error::SesErrorCode;
35
36    use super::*;
37
38    fn params_with_action(action: &str) -> Vec<(String, String)> {
39        vec![("Action".to_owned(), action.to_owned())]
40    }
41
42    #[test]
43    fn test_should_resolve_send_email() {
44        let params = params_with_action("SendEmail");
45        let op = resolve_operation(&params).unwrap();
46        assert_eq!(op, SesOperation::SendEmail);
47    }
48
49    #[test]
50    fn test_should_resolve_verify_email_identity() {
51        let params = params_with_action("VerifyEmailIdentity");
52        let op = resolve_operation(&params).unwrap();
53        assert_eq!(op, SesOperation::VerifyEmailIdentity);
54    }
55
56    #[test]
57    fn test_should_error_on_missing_action() {
58        let params: Vec<(String, String)> = vec![];
59        let err = resolve_operation(&params).unwrap_err();
60        assert_eq!(err.code, SesErrorCode::MissingAction);
61    }
62
63    #[test]
64    fn test_should_error_on_unknown_operation() {
65        let params = params_with_action("NonExistentOperation");
66        let err = resolve_operation(&params).unwrap_err();
67        assert_eq!(err.code, SesErrorCode::InvalidParameterValue);
68        assert!(err.message.contains("NonExistentOperation"));
69    }
70
71    #[test]
72    fn test_should_find_action_among_other_params() {
73        let params = vec![
74            ("Version".to_owned(), "2010-12-01".to_owned()),
75            ("Action".to_owned(), "ListIdentities".to_owned()),
76            ("IdentityType".to_owned(), "EmailAddress".to_owned()),
77        ];
78        let op = resolve_operation(&params).unwrap();
79        assert_eq!(op, SesOperation::ListIdentities);
80    }
81}