1use std::collections::HashMap;
4
5use http::StatusCode;
6
7use crate::service::{AwsRequest, AwsServiceError};
8
9pub fn query_response_xml(action: &str, namespace: &str, inner: &str, request_id: &str) -> String {
20 format!(
21 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
22 <{action}Response xmlns=\"{namespace}\">\
23 <{action}Result>{inner}</{action}Result>\
24 <ResponseMetadata><RequestId>{request_id}</RequestId></ResponseMetadata>\
25 </{action}Response>"
26 )
27}
28
29pub fn query_metadata_only_xml(action: &str, namespace: &str, request_id: &str) -> String {
31 format!(
32 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
33 <{action}Response xmlns=\"{namespace}\">\
34 <ResponseMetadata><RequestId>{request_id}</RequestId></ResponseMetadata>\
35 </{action}Response>"
36 )
37}
38
39pub fn optional_param(params: &HashMap<String, String>, name: &str) -> Option<String> {
43 params.get(name).cloned().filter(|value| !value.is_empty())
44}
45
46pub fn required_param(
50 params: &HashMap<String, String>,
51 name: &str,
52) -> Result<String, AwsServiceError> {
53 optional_param(params, name).ok_or_else(|| {
54 AwsServiceError::aws_error(
55 StatusCode::BAD_REQUEST,
56 "MissingParameter",
57 format!("The request must contain the parameter {name}."),
58 )
59 })
60}
61
62pub fn optional_query_param(req: &AwsRequest, name: &str) -> Option<String> {
64 optional_param(&req.query_params, name)
65}
66
67pub fn required_query_param(req: &AwsRequest, name: &str) -> Result<String, AwsServiceError> {
69 required_param(&req.query_params, name)
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use bytes::Bytes;
76 use http::HeaderMap;
77 use std::collections::HashMap;
78
79 fn make_req(params: &[(&str, &str)]) -> AwsRequest {
80 let mut query_params = HashMap::new();
81 for (k, v) in params {
82 query_params.insert((*k).to_string(), (*v).to_string());
83 }
84 AwsRequest {
85 service: "x".to_string(),
86 action: "A".to_string(),
87 region: "us-east-1".to_string(),
88 account_id: "123".to_string(),
89 request_id: "r".to_string(),
90 headers: HeaderMap::new(),
91 query_params,
92 body: Bytes::new(),
93 body_stream: parking_lot::Mutex::new(None),
94 path_segments: vec![],
95 raw_path: "/".to_string(),
96 raw_query: String::new(),
97 method: http::Method::POST,
98 is_query_protocol: true,
99 access_key_id: None,
100 principal: None,
101 }
102 }
103
104 #[test]
105 fn query_response_xml_format() {
106 let xml = query_response_xml("Foo", "http://example.com/", "<Bar/>", "req-1");
107 assert!(xml.contains("<FooResponse"));
108 assert!(xml.contains("<FooResult><Bar/></FooResult>"));
109 assert!(xml.contains("<RequestId>req-1</RequestId>"));
110 }
111
112 #[test]
113 fn query_metadata_only_xml_omits_result() {
114 let xml = query_metadata_only_xml("Foo", "http://example.com/", "req-1");
115 assert!(xml.contains("<FooResponse"));
116 assert!(!xml.contains("<FooResult"));
117 assert!(xml.contains("<RequestId>req-1</RequestId>"));
118 }
119
120 #[test]
121 fn optional_query_param_returns_value() {
122 let req = make_req(&[("key", "value")]);
123 assert_eq!(optional_query_param(&req, "key").as_deref(), Some("value"));
124 }
125
126 #[test]
127 fn optional_query_param_missing_returns_none() {
128 let req = make_req(&[]);
129 assert!(optional_query_param(&req, "key").is_none());
130 }
131
132 #[test]
133 fn optional_query_param_empty_returns_none() {
134 let req = make_req(&[("key", "")]);
135 assert!(optional_query_param(&req, "key").is_none());
136 }
137
138 #[test]
139 fn required_query_param_returns_value() {
140 let req = make_req(&[("k", "v")]);
141 assert_eq!(required_query_param(&req, "k").unwrap(), "v");
142 }
143
144 #[test]
145 fn required_query_param_missing_errors() {
146 let req = make_req(&[]);
147 assert!(required_query_param(&req, "k").is_err());
148 }
149}