1extern crate serde_regex;
2
3use crate::{
4 common::{
5 data::Error::{
6 HeaderDeserializationError, RequestConversionError, StaticMockConversionError,
7 },
8 util::HttpMockBytes,
9 },
10 server::matchers::generic::MatchingStrategy,
11};
12use bytes::Bytes;
13use serde::{Deserialize, Serialize};
14use serde_json::Value;
15use std::{
16 cmp::Ordering,
17 collections::HashMap,
18 convert::{TryFrom, TryInto},
19 fmt,
20 fmt::Debug,
21 str::FromStr,
22 sync::Arc,
23};
24use url::Url;
25
26use crate::server::RequestMetadata;
27#[cfg(feature = "cookies")]
28use headers::{Cookie, HeaderMapExt};
29
30#[derive(thiserror::Error, Debug)]
31pub enum Error {
32 #[error("Cannot deserialize header: {0}")]
33 HeaderDeserializationError(String),
34 #[error("Cookie parser error: {0}")]
35 CookieParserError(String),
36 #[error("cannot convert to/from static mock: {0}")]
37 StaticMockConversionError(String),
38 #[error("JSONConversionError: {0}")]
39 JSONConversionError(#[from] serde_json::Error),
40 #[error("Invalid request data: {0}")]
41 InvalidRequestData(String),
42 #[error("Cannot convert request to/from internal structure: {0}")]
43 RequestConversionError(String),
44}
45
46#[derive(Serialize, Deserialize, Debug, Clone)]
48pub struct HttpMockRequest {
49 scheme: String,
50 uri: String,
51 method: String,
52 headers: Vec<(String, String)>,
53 version: String,
54 body: HttpMockBytes,
55}
56
57impl HttpMockRequest {
58 pub(crate) fn new(
59 scheme: String,
60 uri: String,
61 method: String,
62 headers: Vec<(String, String)>,
63 version: String,
64 body: HttpMockBytes,
65 ) -> Self {
66 Self {
75 scheme,
76 uri,
77 method,
78 headers,
79 version,
80 body,
81 }
82 }
83
84 pub fn uri(&self) -> http::Uri {
98 self.uri.parse().unwrap()
99 }
100
101 pub fn scheme(&self) -> String {
111 let uri = self.uri();
112 if let Some(scheme) = uri.scheme() {
113 return scheme.to_string();
114 }
115
116 self.scheme.clone()
117 }
118
119 pub fn uri_str(&self) -> &str {
133 self.uri.as_ref()
134 }
135
136 pub fn host(&self) -> Option<String> {
151 if let Some((_, host)) = self
153 .headers
154 .iter()
155 .find(|&&(ref k, _)| k.eq_ignore_ascii_case("host"))
156 {
157 return Some(host.split(':').next().unwrap().to_string());
158 }
159
160 let uri = self.uri();
162 if let Some(authority) = uri.authority() {
163 return Some(authority.as_str().split(':').next().unwrap().to_string());
164 }
165
166 None
167 }
168
169 pub fn port(&self) -> u16 {
183 if let Some((_, host)) = self
185 .headers
186 .iter()
187 .find(|&&(ref k, _)| k.eq_ignore_ascii_case("host"))
188 {
189 if let Some(port_str) = host.split(':').nth(1) {
190 if let Ok(port) = port_str.parse::<u16>() {
191 return port;
192 }
193 }
194 }
195
196 let uri = self.uri();
198 if let Some(authority) = uri.authority() {
199 if let Some(port_str) = authority.as_str().split(':').nth(1) {
200 if let Ok(port) = port_str.parse::<u16>() {
201 return port;
202 }
203 }
204 }
205
206 if self.scheme().eq("https") {
207 return 443;
208 }
209
210 return 80;
211 }
212
213 pub fn method(&self) -> http::Method {
214 http::Method::from_bytes(self.method.as_bytes()).unwrap()
215 }
216
217 pub fn method_str(&self) -> &str {
218 self.method.as_ref()
219 }
220
221 pub fn headers(&self) -> http::HeaderMap<http::HeaderValue> {
222 let mut header_map: http::HeaderMap<http::HeaderValue> = http::HeaderMap::new();
223 for (key, value) in &self.headers {
224 let header_name = http::HeaderName::from_bytes(key.as_bytes()).unwrap();
225 let header_value = http::HeaderValue::from_str(&value).unwrap();
226
227 header_map.insert(header_name, header_value);
228 }
229
230 header_map
231 }
232
233 pub fn headers_vec(&self) -> &Vec<(String, String)> {
234 self.headers.as_ref()
235 }
236
237 pub fn query_params(&self) -> HashMap<String, String> {
238 self.query_params_vec().into_iter().collect()
239 }
240
241 pub fn query_params_vec(&self) -> Vec<(String, String)> {
242 let url = format!("http://dummy?{}", self.uri().query().unwrap_or(""));
245 let url = Url::parse(&url).unwrap();
246
247 url.query_pairs()
248 .map(|(k, v)| (k.into_owned(), v.into_owned()))
249 .collect()
250 }
251
252 pub fn body(&self) -> &HttpMockBytes {
253 &self.body
254 }
255
256 pub fn body_string(&self) -> String {
257 self.body.to_string()
258 }
259
260 pub fn body_ref<'a>(&'a self) -> &'a [u8] {
261 self.body.as_ref()
262 }
263
264 pub fn body_vec(&self) -> Vec<u8> {
266 self.body.to_vec()
267 }
268
269 pub fn body_bytes(&self) -> bytes::Bytes {
270 self.body.to_bytes()
271 }
272
273 pub fn version(&self) -> http::Version {
274 match self.version.as_ref() {
275 "HTTP/0.9" => http::Version::HTTP_09,
276 "HTTP/1.0" => http::Version::HTTP_10,
277 "HTTP/1.1" => http::Version::HTTP_11,
278 "HTTP/2.0" => http::Version::HTTP_2,
279 "HTTP/3.0" => http::Version::HTTP_3,
280 _ => panic!("unknown HTTP version: {:?}", self.version),
283 }
284 }
285
286 pub fn version_ref(&self) -> &str {
287 self.version.as_ref()
288 }
289
290 #[cfg(feature = "cookies")]
291 pub(crate) fn cookies(&self) -> Result<Vec<(String, String)>, Error> {
292 let mut result = Vec::new();
293
294 if let Some(cookie) = self.headers().typed_get::<Cookie>() {
295 for (key, value) in cookie.iter() {
296 result.push((key.to_string(), value.to_string()));
297 }
298 }
299
300 Ok(result)
301 }
302
303 pub fn to_http_request(&self) -> http::Request<Bytes> {
304 self.try_into().unwrap()
305 }
306}
307
308fn http_headers_to_vec<T>(req: &http::Request<T>) -> Result<Vec<(String, String)>, Error> {
309 req.headers()
310 .iter()
311 .map(|(name, value)| {
312 let value_str = value
314 .to_str()
315 .map_err(|e| RequestConversionError(e.to_string()))?;
316 Ok((name.as_str().to_string(), value_str.to_string()))
317 })
318 .collect()
319}
320
321impl TryInto<http::Request<Bytes>> for &HttpMockRequest {
322 type Error = Error;
323
324 fn try_into(self) -> Result<http::Request<Bytes>, Self::Error> {
325 let mut builder = http::Request::builder()
326 .method(self.method())
327 .uri(self.uri())
328 .version(self.version());
329
330 for (k, v) in self.headers() {
331 builder = builder.header(k.map_or(String::new(), |v| v.to_string()), v)
332 }
333
334 let req = builder
335 .body(self.body().to_bytes())
336 .map_err(|err| RequestConversionError(err.to_string()))?;
337
338 Ok(req)
339 }
340}
341
342impl TryFrom<&http::Request<Bytes>> for HttpMockRequest {
343 type Error = Error;
344
345 fn try_from(value: &http::Request<Bytes>) -> Result<Self, Self::Error> {
346 let metadata = value
347 .extensions()
348 .get::<RequestMetadata>()
349 .unwrap_or_else(|| panic!("request metadata was not added to the request"));
350
351 let headers = http_headers_to_vec(&value)?;
352
353 let body = HttpMockBytes::from(value.body().clone());
355
356 Ok(HttpMockRequest::new(
357 metadata.scheme.to_string(),
358 value.uri().to_string(),
359 value.method().to_string(),
360 headers,
361 format!("{:?}", value.version()),
362 body,
363 ))
364 }
365}
366
367#[derive(Serialize, Deserialize, Clone)]
369pub struct MockServerHttpResponse {
370 pub status: Option<u16>,
371 pub headers: Option<Vec<(String, String)>>,
372 #[serde(default, with = "opt_vector_serde_base64")]
373 pub body: Option<HttpMockBytes>,
374 pub delay: Option<u64>,
375}
376
377impl MockServerHttpResponse {
378 pub fn new() -> Self {
379 Self {
380 status: None,
381 headers: None,
382 body: None,
383 delay: None,
384 }
385 }
386}
387
388impl Default for MockServerHttpResponse {
389 fn default() -> Self {
390 Self::new()
391 }
392}
393
394impl TryFrom<&http::Response<Bytes>> for MockServerHttpResponse {
395 type Error = Error;
396
397 fn try_from(value: &http::Response<Bytes>) -> Result<Self, Self::Error> {
398 let mut headers = Vec::with_capacity(value.headers().len());
399
400 for (key, value) in value.headers() {
401 let value = value
402 .to_str()
403 .map_err(|err| HeaderDeserializationError(err.to_string()))?;
404
405 headers.push((key.as_str().to_string(), value.to_string()))
406 }
407
408 Ok(Self {
409 status: Some(value.status().as_u16()),
410 headers: if !headers.is_empty() {
411 Some(headers)
412 } else {
413 None
414 },
415 body: if !value.body().is_empty() {
416 Some(HttpMockBytes::from(value.body().clone()))
417 } else {
418 None
419 },
420 delay: None,
421 })
422 }
423}
424
425mod opt_vector_serde_base64 {
427 use crate::common::util::HttpMockBytes;
428 use bytes::Bytes;
429 use serde::{Deserialize, Deserializer, Serializer};
430
431 pub fn serialize<T, S>(bytes: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
435 where
436 T: AsRef<[u8]>,
437 S: Serializer,
438 {
439 match bytes {
440 Some(ref value) => serializer.serialize_bytes(base64::encode(value).as_bytes()),
441 None => serializer.serialize_none(),
442 }
443 }
444
445 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<HttpMockBytes>, D::Error>
448 where
449 D: Deserializer<'de>,
450 {
451 #[derive(Deserialize)]
452 struct Wrapper(#[serde(deserialize_with = "from_base64")] HttpMockBytes);
453
454 let v = Option::deserialize(deserializer)?;
455 Ok(v.map(|Wrapper(a)| a))
456 }
457
458 fn from_base64<'de, D>(deserializer: D) -> Result<HttpMockBytes, D::Error>
459 where
460 D: Deserializer<'de>,
461 {
462 let value = Vec::deserialize(deserializer)?;
463 let decoded = base64::decode(value).map_err(serde::de::Error::custom)?;
464 Ok(HttpMockBytes::from(Bytes::from(decoded)))
465 }
466}
467
468impl fmt::Debug for MockServerHttpResponse {
470 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
471 f.debug_struct("MockServerHttpResponse")
472 .field("status", &self.status)
473 .field("headers", &self.headers)
474 .field(
475 "body",
476 &self
477 .body
478 .as_ref()
479 .map(|x| String::from_utf8_lossy(x.as_ref()).to_string()),
480 )
481 .field("delay", &self.delay)
482 .finish()
483 }
484}
485
486#[derive(Serialize, Deserialize, Clone, Debug)]
488pub struct HttpMockRegex(#[serde(with = "serde_regex")] pub regex::Regex);
489
490impl Ord for HttpMockRegex {
491 fn cmp(&self, other: &Self) -> Ordering {
492 self.0.as_str().cmp(other.0.as_str())
493 }
494}
495
496impl PartialOrd for HttpMockRegex {
497 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
498 Some(self.cmp(other))
499 }
500}
501
502impl PartialEq for HttpMockRegex {
503 fn eq(&self, other: &Self) -> bool {
504 self.0.as_str() == other.0.as_str()
505 }
506}
507
508impl Eq for HttpMockRegex {}
509
510impl From<regex::Regex> for HttpMockRegex {
511 fn from(value: regex::Regex) -> Self {
512 HttpMockRegex(value)
513 }
514}
515
516impl From<&str> for HttpMockRegex {
517 fn from(value: &str) -> Self {
518 let re = regex::Regex::from_str(value).expect("cannot parse value as regex");
519 HttpMockRegex::from(re)
520 }
521}
522
523impl From<String> for HttpMockRegex {
524 fn from(value: String) -> Self {
525 HttpMockRegex::from(value.as_str())
526 }
527}
528
529impl fmt::Display for HttpMockRegex {
530 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
531 write!(f, "{}", self.0)
532 }
533}
534
535#[derive(Serialize, Deserialize, Clone)]
537pub struct RequestRequirements {
538 pub scheme: Option<String>,
539 pub scheme_not: Option<String>, pub host: Option<String>,
541 pub host_not: Option<Vec<String>>, pub host_contains: Option<Vec<String>>, pub host_excludes: Option<Vec<String>>, pub host_prefix: Option<Vec<String>>, pub host_suffix: Option<Vec<String>>, pub host_prefix_not: Option<Vec<String>>, pub host_suffix_not: Option<Vec<String>>, pub host_matches: Option<Vec<HttpMockRegex>>,
549 pub port: Option<u16>,
550 pub port_not: Option<Vec<u16>>, pub method: Option<String>,
552 pub method_not: Option<Vec<String>>, pub path: Option<String>,
554 pub path_not: Option<Vec<String>>, pub path_includes: Option<Vec<String>>, pub path_excludes: Option<Vec<String>>, pub path_prefix: Option<Vec<String>>, pub path_suffix: Option<Vec<String>>, pub path_prefix_not: Option<Vec<String>>, pub path_suffix_not: Option<Vec<String>>, pub path_matches: Option<Vec<HttpMockRegex>>,
562 pub query_param: Option<Vec<(String, String)>>,
563 pub query_param_not: Option<Vec<(String, String)>>, pub query_param_exists: Option<Vec<String>>,
565 pub query_param_missing: Option<Vec<String>>, pub query_param_includes: Option<Vec<(String, String)>>, pub query_param_excludes: Option<Vec<(String, String)>>, pub query_param_prefix: Option<Vec<(String, String)>>, pub query_param_suffix: Option<Vec<(String, String)>>, pub query_param_prefix_not: Option<Vec<(String, String)>>, pub query_param_suffix_not: Option<Vec<(String, String)>>, pub query_param_matches: Option<Vec<(HttpMockRegex, HttpMockRegex)>>, pub query_param_count: Option<Vec<(HttpMockRegex, HttpMockRegex, usize)>>, pub header: Option<Vec<(String, String)>>, pub header_not: Option<Vec<(String, String)>>, pub header_exists: Option<Vec<String>>,
577 pub header_missing: Option<Vec<String>>, pub header_includes: Option<Vec<(String, String)>>, pub header_excludes: Option<Vec<(String, String)>>, pub header_prefix: Option<Vec<(String, String)>>, pub header_suffix: Option<Vec<(String, String)>>, pub header_prefix_not: Option<Vec<(String, String)>>, pub header_suffix_not: Option<Vec<(String, String)>>, pub header_matches: Option<Vec<(HttpMockRegex, HttpMockRegex)>>, pub header_count: Option<Vec<(HttpMockRegex, HttpMockRegex, usize)>>, pub cookie: Option<Vec<(String, String)>>, pub cookie_not: Option<Vec<(String, String)>>, pub cookie_exists: Option<Vec<String>>,
589 pub cookie_missing: Option<Vec<String>>, pub cookie_includes: Option<Vec<(String, String)>>, pub cookie_excludes: Option<Vec<(String, String)>>, pub cookie_prefix: Option<Vec<(String, String)>>, pub cookie_suffix: Option<Vec<(String, String)>>, pub cookie_prefix_not: Option<Vec<(String, String)>>, pub cookie_suffix_not: Option<Vec<(String, String)>>, pub cookie_matches: Option<Vec<(HttpMockRegex, HttpMockRegex)>>, pub cookie_count: Option<Vec<(HttpMockRegex, HttpMockRegex, usize)>>, pub body: Option<HttpMockBytes>,
599 pub body_not: Option<Vec<HttpMockBytes>>, pub body_includes: Option<Vec<HttpMockBytes>>, pub body_excludes: Option<Vec<HttpMockBytes>>, pub body_prefix: Option<Vec<HttpMockBytes>>, pub body_suffix: Option<Vec<HttpMockBytes>>, pub body_prefix_not: Option<Vec<HttpMockBytes>>, pub body_suffix_not: Option<Vec<HttpMockBytes>>, pub body_matches: Option<Vec<HttpMockRegex>>, pub json_body: Option<Value>,
608 pub json_body_not: Option<Value>, pub json_body_includes: Option<Vec<Value>>,
610 pub json_body_excludes: Option<Vec<Value>>, pub form_urlencoded_tuple: Option<Vec<(String, String)>>,
612 pub form_urlencoded_tuple_not: Option<Vec<(String, String)>>, pub form_urlencoded_tuple_exists: Option<Vec<String>>,
614 pub form_urlencoded_tuple_missing: Option<Vec<String>>, pub form_urlencoded_tuple_includes: Option<Vec<(String, String)>>, pub form_urlencoded_tuple_excludes: Option<Vec<(String, String)>>, pub form_urlencoded_tuple_prefix: Option<Vec<(String, String)>>, pub form_urlencoded_tuple_suffix: Option<Vec<(String, String)>>, pub form_urlencoded_tuple_prefix_not: Option<Vec<(String, String)>>, pub form_urlencoded_tuple_suffix_not: Option<Vec<(String, String)>>, pub form_urlencoded_tuple_matches: Option<Vec<(HttpMockRegex, HttpMockRegex)>>, pub form_urlencoded_tuple_count: Option<Vec<(HttpMockRegex, HttpMockRegex, usize)>>, #[serde(skip)]
624 pub is_true: Option<Vec<Arc<dyn Fn(&HttpMockRequest) -> bool + Sync + Send>>>, #[serde(skip)]
626 pub is_false: Option<Vec<Arc<dyn Fn(&HttpMockRequest) -> bool + Sync + Send>>>, }
628
629impl Default for RequestRequirements {
630 fn default() -> Self {
631 Self::new()
632 }
633}
634
635impl RequestRequirements {
636 pub fn new() -> Self {
637 Self {
638 scheme: None,
639 scheme_not: None,
640 host: None,
641 host_not: None,
642 host_contains: None,
643 host_excludes: None,
644 host_prefix: None,
645 host_suffix: None,
646 host_prefix_not: None,
647 host_suffix_not: None,
648 host_matches: None,
649 port: None,
650 path: None,
651 path_not: None,
652 path_includes: None,
653 path_excludes: None,
654 path_prefix: None,
655 path_suffix: None,
656 path_prefix_not: None,
657 path_suffix_not: None,
658 path_matches: None,
659 method: None,
660 header: None,
661 header_not: None,
662 header_exists: None,
663 header_missing: None,
664 header_includes: None,
665 header_excludes: None,
666 header_prefix: None,
667 header_suffix: None,
668 header_prefix_not: None,
669 header_suffix_not: None,
670 header_matches: None,
671 header_count: None,
672 cookie: None,
673 cookie_not: None,
674 cookie_exists: None,
675 cookie_missing: None,
676 cookie_includes: None,
677 cookie_excludes: None,
678 cookie_prefix: None,
679 cookie_suffix: None,
680 cookie_prefix_not: None,
681 cookie_suffix_not: None,
682 cookie_matches: None,
683 cookie_count: None,
684 body: None,
685 json_body: None,
686 json_body_not: None,
687 json_body_includes: None,
688 body_includes: None,
689 body_excludes: None,
690 body_prefix: None,
691 body_suffix: None,
692 body_prefix_not: None,
693 body_suffix_not: None,
694 body_matches: None,
695 query_param_exists: None,
696 query_param_missing: None,
697 query_param_includes: None,
698 query_param_excludes: None,
699 query_param_prefix: None,
700 query_param_suffix: None,
701 query_param_prefix_not: None,
702 query_param_suffix_not: None,
703 query_param_matches: None,
704 query_param_count: None,
705 query_param: None,
706 form_urlencoded_tuple: None,
707 form_urlencoded_tuple_not: None,
708 form_urlencoded_tuple_exists: None,
709 form_urlencoded_tuple_missing: None,
710 form_urlencoded_tuple_includes: None,
711 form_urlencoded_tuple_excludes: None,
712 form_urlencoded_tuple_prefix: None,
713 form_urlencoded_tuple_suffix: None,
714 form_urlencoded_tuple_prefix_not: None,
715 form_urlencoded_tuple_suffix_not: None,
716 form_urlencoded_tuple_matches: None,
717 form_urlencoded_tuple_count: None,
718 is_true: None,
719 port_not: None,
720 method_not: None,
721 query_param_not: None,
722 body_not: None,
723 json_body_excludes: None,
724 is_false: None,
725 }
726 }
727}
728
729#[derive(Serialize, Deserialize, Clone)]
731pub struct MockDefinition {
732 pub request: RequestRequirements,
733 pub response: MockServerHttpResponse,
734}
735
736impl MockDefinition {
737 pub fn new(req: RequestRequirements, mock: MockServerHttpResponse) -> Self {
738 Self {
739 request: req,
740 response: mock,
741 }
742 }
743}
744
745#[derive(Serialize, Deserialize, Clone)]
746pub struct ActiveMock {
747 pub id: usize,
748 pub call_counter: usize,
749 pub definition: MockDefinition,
750 pub is_static: bool,
751}
752
753impl ActiveMock {
754 pub fn new(
755 id: usize,
756 definition: MockDefinition,
757 call_counter: usize,
758 is_static: bool,
759 ) -> Self {
760 ActiveMock {
761 id,
762 definition,
763 call_counter,
764 is_static,
765 }
766 }
767}
768
769#[derive(Serialize, Deserialize, Clone)]
770pub struct ActiveForwardingRule {
771 pub id: usize,
772 pub config: ForwardingRuleConfig,
773}
774
775impl ActiveForwardingRule {
776 pub fn new(id: usize, config: ForwardingRuleConfig) -> Self {
777 ActiveForwardingRule { id, config }
778 }
779}
780
781#[derive(Serialize, Deserialize, Clone)]
782pub struct ActiveProxyRule {
783 pub id: usize,
784 pub config: ProxyRuleConfig,
785}
786
787impl ActiveProxyRule {
788 pub fn new(id: usize, config: ProxyRuleConfig) -> Self {
789 ActiveProxyRule { id, config }
790 }
791}
792
793#[derive(Serialize, Deserialize, Clone)]
794pub struct ActiveRecording {
795 pub id: usize,
796 pub config: RecordingRuleConfig,
797 pub mocks: Vec<MockDefinition>,
798}
799
800impl ActiveRecording {
801 pub fn new(id: usize, config: RecordingRuleConfig) -> Self {
802 ActiveRecording {
803 id,
804 config,
805 mocks: vec![],
806 }
807 }
808}
809
810#[derive(Serialize, Deserialize)]
811pub struct ClosestMatch {
812 pub request: HttpMockRequest,
813 pub request_index: usize,
814 pub mismatches: Vec<Mismatch>,
815}
816
817#[derive(Serialize, Deserialize)]
818pub struct ErrorResponse {
819 pub message: String,
820}
821
822impl ErrorResponse {
823 pub fn new<T>(message: &T) -> ErrorResponse
824 where
825 T: ToString,
826 {
827 ErrorResponse {
828 message: message.to_string(),
829 }
830 }
831}
832
833#[derive(PartialEq, Debug, Serialize, Deserialize)]
838pub enum Diff {
839 Same(String),
840 Add(String),
841 Rem(String),
842}
843
844#[derive(Debug, Serialize, Deserialize)]
845pub struct DiffResult {
846 pub differences: Vec<Diff>,
847 pub distance: f32,
848 pub tokenizer: Tokenizer,
849}
850
851#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Copy)]
852pub enum Tokenizer {
853 Line,
854 Word,
855 Character,
856}
857
858#[derive(Debug, Serialize, Deserialize)]
859pub struct KeyValueComparisonKeyValuePair {
860 pub key: String,
861 pub value: Option<String>,
862}
863
864#[derive(Debug, Serialize, Deserialize)]
865pub struct KeyValueComparisonAttribute {
866 pub operator: String,
867 pub expected: String,
868 pub actual: Option<String>,
869}
870
871#[derive(Debug, Serialize, Deserialize)]
872pub struct KeyValueComparison {
873 pub key: Option<KeyValueComparisonAttribute>,
874 pub value: Option<KeyValueComparisonAttribute>,
875 pub expected_count: Option<usize>,
876 pub actual_count: Option<usize>,
877 pub all: Vec<KeyValueComparisonKeyValuePair>,
878}
879
880#[derive(Debug, Serialize, Deserialize)]
881pub struct FunctionComparison {
882 pub index: usize,
883}
884
885#[derive(Debug, Serialize, Deserialize)]
886pub struct SingleValueComparison {
887 pub operator: String,
888 pub expected: String,
889 pub actual: String,
890}
891
892#[derive(Debug, Serialize, Deserialize)]
893pub struct Mismatch {
894 pub entity: String,
895 pub matcher_method: String,
896 pub comparison: Option<SingleValueComparison>,
897 pub key_value_comparison: Option<KeyValueComparison>,
898 pub function_comparison: Option<FunctionComparison>,
899 pub matching_strategy: Option<MatchingStrategy>,
900 pub best_match: bool,
901 pub diff: Option<DiffResult>,
902}
903
904#[derive(Serialize, Deserialize, Clone, Default)]
909pub struct RecordingRuleConfig {
910 pub request_requirements: RequestRequirements,
911 pub record_headers: Vec<String>,
912 pub record_response_delays: bool,
913}
914
915#[derive(Serialize, Deserialize, Clone, Default)]
916pub struct ProxyRuleConfig {
917 pub request_requirements: RequestRequirements,
918 pub request_header: Vec<(String, String)>,
919}
920
921#[derive(Serialize, Deserialize, Clone, Default)]
922pub struct ForwardingRuleConfig {
923 pub target_base_url: String,
924 pub request_requirements: RequestRequirements,
925 pub request_header: Vec<(String, String)>,
926}
927
928#[derive(Debug, PartialEq, Serialize, Deserialize)]
929pub struct NameValueStringPair {
930 name: String,
931 value: String,
932}
933
934#[derive(Debug, PartialEq, Serialize, Deserialize)]
935pub struct NameValuePatternPair {
936 name: HttpMockRegex,
937 value: HttpMockRegex,
938}
939
940#[derive(Debug, PartialEq, Serialize, Deserialize)]
941pub struct KeyPatternCountPair {
942 key: HttpMockRegex,
943 count: usize,
944}
945
946#[derive(Debug, PartialEq, Serialize, Deserialize)]
947pub struct ValuePatternCountPair {
948 value: HttpMockRegex,
949 count: usize,
950}
951
952#[derive(Debug, PartialEq, Serialize, Deserialize)]
953pub struct KeyValuePatternCountTriple {
954 name: HttpMockRegex,
955 value: HttpMockRegex,
956 count: usize,
957}
958
959#[derive(Debug, Serialize, Deserialize)]
960pub struct StaticRequestRequirements {
961 #[serde(skip_serializing_if = "Option::is_none")]
963 pub scheme: Option<String>,
964 #[serde(skip_serializing_if = "Option::is_none")]
965 pub scheme_not: Option<String>,
966
967 #[serde(skip_serializing_if = "Option::is_none")]
969 pub host: Option<String>,
970 #[serde(skip_serializing_if = "Option::is_none")]
971 pub host_not: Option<Vec<String>>,
972 #[serde(skip_serializing_if = "Option::is_none")]
973 pub host_contains: Option<Vec<String>>,
974 #[serde(skip_serializing_if = "Option::is_none")]
975 pub host_excludes: Option<Vec<String>>,
976 #[serde(skip_serializing_if = "Option::is_none")]
977 pub host_prefix: Option<Vec<String>>,
978 #[serde(skip_serializing_if = "Option::is_none")]
979 pub host_suffix: Option<Vec<String>>,
980 #[serde(skip_serializing_if = "Option::is_none")]
981 pub host_prefix_not: Option<Vec<String>>,
982 #[serde(skip_serializing_if = "Option::is_none")]
983 pub host_suffix_not: Option<Vec<String>>,
984 #[serde(skip_serializing_if = "Option::is_none")]
985 pub host_matches: Option<Vec<HttpMockRegex>>,
986
987 #[serde(skip_serializing_if = "Option::is_none")]
989 pub port: Option<u16>,
990 #[serde(skip_serializing_if = "Option::is_none")]
991 pub port_not: Option<Vec<u16>>,
992
993 #[serde(skip_serializing_if = "Option::is_none")]
995 pub path: Option<String>,
996 #[serde(skip_serializing_if = "Option::is_none")]
997 pub path_not: Option<Vec<String>>,
998 #[serde(skip_serializing_if = "Option::is_none")]
999 pub path_contains: Option<Vec<String>>,
1000 #[serde(skip_serializing_if = "Option::is_none")]
1001 pub path_excludes: Option<Vec<String>>,
1002 #[serde(skip_serializing_if = "Option::is_none")]
1003 pub path_prefix: Option<Vec<String>>,
1004 #[serde(skip_serializing_if = "Option::is_none")]
1005 pub path_suffix: Option<Vec<String>>,
1006 #[serde(skip_serializing_if = "Option::is_none")]
1007 pub path_prefix_not: Option<Vec<String>>,
1008 #[serde(skip_serializing_if = "Option::is_none")]
1009 pub path_suffix_not: Option<Vec<String>>,
1010 #[serde(skip_serializing_if = "Option::is_none")]
1011 pub path_matches: Option<Vec<HttpMockRegex>>,
1012
1013 #[serde(skip_serializing_if = "Option::is_none")]
1015 pub method: Option<Method>,
1016 #[serde(skip_serializing_if = "Option::is_none")]
1017 pub method_not: Option<Vec<Method>>,
1018
1019 #[serde(skip_serializing_if = "Option::is_none")]
1021 pub query_param: Option<Vec<NameValueStringPair>>,
1022 #[serde(skip_serializing_if = "Option::is_none")]
1023 pub query_param_not: Option<Vec<NameValueStringPair>>,
1024 #[serde(skip_serializing_if = "Option::is_none")]
1025 pub query_param_exists: Option<Vec<String>>,
1026 #[serde(skip_serializing_if = "Option::is_none")]
1027 pub query_param_missing: Option<Vec<String>>,
1028 #[serde(skip_serializing_if = "Option::is_none")]
1029 pub query_param_contains: Option<Vec<NameValueStringPair>>,
1030 #[serde(skip_serializing_if = "Option::is_none")]
1031 pub query_param_excludes: Option<Vec<NameValueStringPair>>,
1032 #[serde(skip_serializing_if = "Option::is_none")]
1033 pub query_param_prefix: Option<Vec<NameValueStringPair>>,
1034 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub query_param_suffix: Option<Vec<NameValueStringPair>>,
1036 #[serde(skip_serializing_if = "Option::is_none")]
1037 pub query_param_prefix_not: Option<Vec<NameValueStringPair>>,
1038 #[serde(skip_serializing_if = "Option::is_none")]
1039 pub query_param_suffix_not: Option<Vec<NameValueStringPair>>,
1040 #[serde(skip_serializing_if = "Option::is_none")]
1041 pub query_param_matches: Option<Vec<NameValuePatternPair>>,
1042 #[serde(skip_serializing_if = "Option::is_none")]
1043 pub query_param_count: Option<Vec<KeyValuePatternCountTriple>>,
1044
1045 #[serde(skip_serializing_if = "Option::is_none")]
1047 pub header: Option<Vec<NameValueStringPair>>,
1048 #[serde(skip_serializing_if = "Option::is_none")]
1049 pub header_not: Option<Vec<NameValueStringPair>>,
1050 #[serde(skip_serializing_if = "Option::is_none")]
1051 pub header_exists: Option<Vec<String>>,
1052 #[serde(skip_serializing_if = "Option::is_none")]
1053 pub header_missing: Option<Vec<String>>,
1054 #[serde(skip_serializing_if = "Option::is_none")]
1055 pub header_contains: Option<Vec<NameValueStringPair>>,
1056 #[serde(skip_serializing_if = "Option::is_none")]
1057 pub header_excludes: Option<Vec<NameValueStringPair>>,
1058 #[serde(skip_serializing_if = "Option::is_none")]
1059 pub header_prefix: Option<Vec<NameValueStringPair>>,
1060 #[serde(skip_serializing_if = "Option::is_none")]
1061 pub header_suffix: Option<Vec<NameValueStringPair>>,
1062 #[serde(skip_serializing_if = "Option::is_none")]
1063 pub header_prefix_not: Option<Vec<NameValueStringPair>>,
1064 #[serde(skip_serializing_if = "Option::is_none")]
1065 pub header_suffix_not: Option<Vec<NameValueStringPair>>,
1066 #[serde(skip_serializing_if = "Option::is_none")]
1067 pub header_matches: Option<Vec<NameValuePatternPair>>,
1068 #[serde(skip_serializing_if = "Option::is_none")]
1069 pub header_count: Option<Vec<KeyValuePatternCountTriple>>,
1070
1071 #[serde(skip_serializing_if = "Option::is_none")]
1073 pub cookie: Option<Vec<NameValueStringPair>>,
1074 #[serde(skip_serializing_if = "Option::is_none")]
1075 pub cookie_not: Option<Vec<NameValueStringPair>>,
1076 #[serde(skip_serializing_if = "Option::is_none")]
1077 pub cookie_exists: Option<Vec<String>>,
1078 #[serde(skip_serializing_if = "Option::is_none")]
1079 pub cookie_missing: Option<Vec<String>>,
1080 #[serde(skip_serializing_if = "Option::is_none")]
1081 pub cookie_contains: Option<Vec<NameValueStringPair>>,
1082 #[serde(skip_serializing_if = "Option::is_none")]
1083 pub cookie_excludes: Option<Vec<NameValueStringPair>>,
1084 #[serde(skip_serializing_if = "Option::is_none")]
1085 pub cookie_prefix: Option<Vec<NameValueStringPair>>,
1086 #[serde(skip_serializing_if = "Option::is_none")]
1087 pub cookie_suffix: Option<Vec<NameValueStringPair>>,
1088 #[serde(skip_serializing_if = "Option::is_none")]
1089 pub cookie_prefix_not: Option<Vec<NameValueStringPair>>,
1090 #[serde(skip_serializing_if = "Option::is_none")]
1091 pub cookie_suffix_not: Option<Vec<NameValueStringPair>>,
1092 #[serde(skip_serializing_if = "Option::is_none")]
1093 pub cookie_matches: Option<Vec<NameValuePatternPair>>,
1094 #[serde(skip_serializing_if = "Option::is_none")]
1095 pub cookie_count: Option<Vec<KeyValuePatternCountTriple>>,
1096
1097 #[serde(skip_serializing_if = "Option::is_none")]
1099 pub body: Option<String>,
1100 #[serde(skip_serializing_if = "Option::is_none")]
1101 pub body_base64: Option<String>,
1102 #[serde(skip_serializing_if = "Option::is_none")]
1103 pub body_not: Option<Vec<String>>,
1104 #[serde(skip_serializing_if = "Option::is_none")]
1105 pub body_not_base64: Option<Vec<String>>,
1106 #[serde(skip_serializing_if = "Option::is_none")]
1107 pub body_contains: Option<Vec<String>>,
1108 #[serde(skip_serializing_if = "Option::is_none")]
1109 pub body_contains_base64: Option<Vec<String>>,
1110 #[serde(skip_serializing_if = "Option::is_none")]
1111 pub body_excludes: Option<Vec<String>>,
1112 #[serde(skip_serializing_if = "Option::is_none")]
1113 pub body_excludes_base64: Option<Vec<String>>,
1114 #[serde(skip_serializing_if = "Option::is_none")]
1115 pub body_prefix: Option<Vec<String>>,
1116 #[serde(skip_serializing_if = "Option::is_none")]
1117 pub body_prefix_base64: Option<Vec<String>>,
1118 #[serde(skip_serializing_if = "Option::is_none")]
1119 pub body_suffix: Option<Vec<String>>,
1120 #[serde(skip_serializing_if = "Option::is_none")]
1121 pub body_suffix_base64: Option<Vec<String>>,
1122 #[serde(skip_serializing_if = "Option::is_none")]
1123 pub body_prefix_not: Option<Vec<String>>,
1124 #[serde(skip_serializing_if = "Option::is_none")]
1125 pub body_prefix_not_base64: Option<Vec<String>>,
1126 #[serde(skip_serializing_if = "Option::is_none")]
1127 pub body_suffix_not: Option<Vec<String>>,
1128 #[serde(skip_serializing_if = "Option::is_none")]
1129 pub body_suffix_not_base64: Option<Vec<String>>,
1130 #[serde(skip_serializing_if = "Option::is_none")]
1131 pub body_matches: Option<Vec<HttpMockRegex>>,
1132
1133 #[serde(skip_serializing_if = "Option::is_none")]
1135 pub json_body: Option<Value>,
1136 #[serde(skip_serializing_if = "Option::is_none")]
1137 pub json_body_not: Option<Value>,
1138 #[serde(skip_serializing_if = "Option::is_none")]
1139 pub json_body_includes: Option<Vec<Value>>,
1140 #[serde(skip_serializing_if = "Option::is_none")]
1141 pub json_body_excludes: Option<Vec<Value>>,
1142
1143 #[serde(skip_serializing_if = "Option::is_none")]
1145 pub form_urlencoded_tuple: Option<Vec<NameValueStringPair>>,
1146 #[serde(skip_serializing_if = "Option::is_none")]
1147 pub form_urlencoded_tuple_not: Option<Vec<NameValueStringPair>>,
1148 #[serde(skip_serializing_if = "Option::is_none")]
1149 pub form_urlencoded_key_exists: Option<Vec<String>>,
1150 #[serde(skip_serializing_if = "Option::is_none")]
1151 pub form_urlencoded_key_missing: Option<Vec<String>>,
1152 #[serde(skip_serializing_if = "Option::is_none")]
1153 pub form_urlencoded_contains: Option<Vec<NameValueStringPair>>,
1154 #[serde(skip_serializing_if = "Option::is_none")]
1155 pub form_urlencoded_excludes: Option<Vec<NameValueStringPair>>,
1156 #[serde(skip_serializing_if = "Option::is_none")]
1157 pub form_urlencoded_prefix: Option<Vec<NameValueStringPair>>,
1158 #[serde(skip_serializing_if = "Option::is_none")]
1159 pub form_urlencoded_suffix: Option<Vec<NameValueStringPair>>,
1160 #[serde(skip_serializing_if = "Option::is_none")]
1161 pub form_urlencoded_prefix_not: Option<Vec<NameValueStringPair>>,
1162 #[serde(skip_serializing_if = "Option::is_none")]
1163 pub form_urlencoded_suffix_not: Option<Vec<NameValueStringPair>>,
1164 #[serde(skip_serializing_if = "Option::is_none")]
1165 pub form_urlencoded_matches: Option<Vec<NameValuePatternPair>>,
1166 #[serde(skip_serializing_if = "Option::is_none")]
1167 pub form_urlencoded_count: Option<Vec<KeyValuePatternCountTriple>>,
1168}
1169
1170#[derive(Debug, Serialize, Deserialize)]
1171pub struct StaticHTTPResponse {
1172 #[serde(skip_serializing_if = "Option::is_none")]
1173 pub status: Option<u16>,
1174 #[serde(skip_serializing_if = "Option::is_none")]
1175 pub header: Option<Vec<NameValueStringPair>>,
1176 #[serde(skip_serializing_if = "Option::is_none")]
1177 pub body: Option<String>,
1178 #[serde(skip_serializing_if = "Option::is_none")]
1179 pub body_base64: Option<String>,
1180 #[serde(skip_serializing_if = "Option::is_none")]
1181 pub delay: Option<u64>,
1182}
1183
1184#[derive(Debug, Serialize, Deserialize)]
1185pub struct StaticMockDefinition {
1186 when: StaticRequestRequirements,
1187 then: StaticHTTPResponse,
1188}
1189
1190impl TryInto<MockDefinition> for StaticMockDefinition {
1191 type Error = Error;
1192
1193 fn try_into(self) -> Result<MockDefinition, Self::Error> {
1194 Ok(MockDefinition {
1195 request: RequestRequirements {
1196 scheme: self.when.scheme,
1198 scheme_not: self.when.scheme_not,
1199
1200 host: self.when.host,
1202 host_not: self.when.host_not,
1203 host_contains: self.when.host_contains,
1204 host_excludes: self.when.host_excludes,
1205 host_prefix: self.when.host_prefix,
1206 host_suffix: self.when.host_suffix,
1207 host_prefix_not: self.when.host_prefix_not,
1208 host_suffix_not: self.when.host_suffix_not,
1209 host_matches: self.when.host_matches,
1210
1211 port: self.when.port,
1213 port_not: self.when.port_not,
1214
1215 path: self.when.path,
1217 path_not: self.when.path_not,
1218 path_includes: self.when.path_contains,
1219 path_excludes: self.when.path_excludes,
1220 path_prefix: self.when.path_prefix,
1221 path_suffix: self.when.path_suffix,
1222 path_prefix_not: self.when.path_prefix_not,
1223 path_suffix_not: self.when.path_suffix_not,
1224 path_matches: self.when.path_matches,
1225
1226 method: self.when.method.map(|m| m.to_string()),
1228 method_not: from_method_vec(self.when.method_not),
1229 query_param: from_name_value_string_pair_vec(self.when.query_param),
1231 query_param_not: from_name_value_string_pair_vec(self.when.query_param_not),
1232 query_param_exists: self.when.query_param_exists,
1233 query_param_missing: self.when.query_param_missing,
1234 query_param_includes: from_name_value_string_pair_vec(
1235 self.when.query_param_contains,
1236 ),
1237 query_param_excludes: from_name_value_string_pair_vec(
1238 self.when.query_param_excludes,
1239 ),
1240 query_param_prefix: from_name_value_string_pair_vec(self.when.query_param_prefix),
1241 query_param_suffix: from_name_value_string_pair_vec(self.when.query_param_suffix),
1242 query_param_prefix_not: from_name_value_string_pair_vec(
1243 self.when.query_param_prefix_not,
1244 ),
1245 query_param_suffix_not: from_name_value_string_pair_vec(
1246 self.when.query_param_suffix_not,
1247 ),
1248 query_param_matches: from_name_value_pattern_pair_vec(
1249 self.when.query_param_matches,
1250 ),
1251 query_param_count: from_key_value_pattern_count_triple_vec(
1252 self.when.query_param_count,
1253 ),
1254
1255 header: from_name_value_string_pair_vec(self.when.header),
1257 header_not: from_name_value_string_pair_vec(self.when.header_not),
1258 header_exists: self.when.header_exists,
1259 header_missing: self.when.header_missing,
1260 header_includes: from_name_value_string_pair_vec(self.when.header_contains),
1261 header_excludes: from_name_value_string_pair_vec(self.when.header_excludes),
1262 header_prefix: from_name_value_string_pair_vec(self.when.header_prefix),
1263 header_suffix: from_name_value_string_pair_vec(self.when.header_suffix),
1264 header_prefix_not: from_name_value_string_pair_vec(self.when.header_prefix_not),
1265 header_suffix_not: from_name_value_string_pair_vec(self.when.header_suffix_not),
1266 header_matches: from_name_value_pattern_pair_vec(self.when.header_matches),
1267 header_count: from_key_value_pattern_count_triple_vec(self.when.header_count),
1268 cookie: from_name_value_string_pair_vec(self.when.cookie),
1270 cookie_not: from_name_value_string_pair_vec(self.when.cookie_not),
1271 cookie_exists: self.when.cookie_exists,
1272 cookie_missing: self.when.cookie_missing,
1273 cookie_includes: from_name_value_string_pair_vec(self.when.cookie_contains),
1274 cookie_excludes: from_name_value_string_pair_vec(self.when.cookie_excludes),
1275 cookie_prefix: from_name_value_string_pair_vec(self.when.cookie_prefix),
1276 cookie_suffix: from_name_value_string_pair_vec(self.when.cookie_suffix),
1277 cookie_prefix_not: from_name_value_string_pair_vec(self.when.cookie_prefix_not),
1278 cookie_suffix_not: from_name_value_string_pair_vec(self.when.cookie_suffix_not),
1279 cookie_matches: from_name_value_pattern_pair_vec(self.when.cookie_matches),
1280 cookie_count: from_key_value_pattern_count_triple_vec(self.when.cookie_count),
1281
1282 body: from_string_to_bytes_choose(self.when.body, self.when.body_base64),
1284 body_not: to_bytes_vec(self.when.body_not, self.when.body_not_base64),
1285 body_includes: to_bytes_vec(
1286 self.when.body_contains,
1287 self.when.body_contains_base64,
1288 ),
1289 body_excludes: to_bytes_vec(
1290 self.when.body_excludes,
1291 self.when.body_excludes_base64,
1292 ),
1293 body_prefix: to_bytes_vec(self.when.body_prefix, self.when.body_prefix_base64),
1294 body_suffix: to_bytes_vec(self.when.body_suffix, self.when.body_suffix_base64),
1295 body_prefix_not: to_bytes_vec(
1296 self.when.body_prefix_not,
1297 self.when.body_prefix_not_base64,
1298 ),
1299 body_suffix_not: to_bytes_vec(
1300 self.when.body_suffix_not,
1301 self.when.body_suffix_not_base64,
1302 ),
1303 body_matches: from_pattern_vec(self.when.body_matches),
1304
1305 json_body: self.when.json_body,
1307 json_body_not: self.when.json_body_not,
1308 json_body_includes: self.when.json_body_includes,
1309 json_body_excludes: self.when.json_body_excludes,
1310
1311 form_urlencoded_tuple: from_name_value_string_pair_vec(
1313 self.when.form_urlencoded_tuple,
1314 ),
1315 form_urlencoded_tuple_not: from_name_value_string_pair_vec(
1316 self.when.form_urlencoded_tuple_not,
1317 ),
1318 form_urlencoded_tuple_exists: self.when.form_urlencoded_key_exists,
1319 form_urlencoded_tuple_missing: self.when.form_urlencoded_key_missing,
1320 form_urlencoded_tuple_includes: from_name_value_string_pair_vec(
1321 self.when.form_urlencoded_contains,
1322 ),
1323 form_urlencoded_tuple_excludes: from_name_value_string_pair_vec(
1324 self.when.form_urlencoded_excludes,
1325 ),
1326 form_urlencoded_tuple_prefix: from_name_value_string_pair_vec(
1327 self.when.form_urlencoded_prefix,
1328 ),
1329 form_urlencoded_tuple_suffix: from_name_value_string_pair_vec(
1330 self.when.form_urlencoded_suffix,
1331 ),
1332 form_urlencoded_tuple_prefix_not: from_name_value_string_pair_vec(
1333 self.when.form_urlencoded_prefix_not,
1334 ),
1335 form_urlencoded_tuple_suffix_not: from_name_value_string_pair_vec(
1336 self.when.form_urlencoded_suffix_not,
1337 ),
1338 form_urlencoded_tuple_matches: from_name_value_pattern_pair_vec(
1339 self.when.form_urlencoded_matches,
1340 ),
1341
1342 form_urlencoded_tuple_count: from_key_value_pattern_count_triple_vec(
1343 self.when.form_urlencoded_count,
1344 ),
1345
1346 is_true: None,
1348 is_false: None,
1349 },
1350 response: MockServerHttpResponse {
1351 status: self.then.status,
1352 headers: from_name_value_string_pair_vec(self.then.header),
1353 body: from_string_to_bytes_choose(self.then.body, self.then.body_base64),
1354 delay: self.then.delay,
1355 },
1356 })
1357 }
1358}
1359
1360fn to_method_vec(vec: Option<Vec<String>>) -> Option<Vec<Method>> {
1361 vec.map(|vec| vec.iter().map(|val| Method::from(val.as_str())).collect())
1362}
1363
1364fn from_method_vec(value: Option<Vec<Method>>) -> Option<Vec<String>> {
1365 value.map(|vec| vec.iter().map(|m| m.to_string()).collect())
1366}
1367
1368fn to_pattern_vec(vec: Option<Vec<String>>) -> Option<Vec<HttpMockRegex>> {
1369 vec.map(|vec| {
1370 vec.iter()
1371 .map(|val| HttpMockRegex(regex::Regex::from_str(val).expect("cannot parse regex")))
1372 .collect()
1373 })
1374}
1375
1376fn from_pattern_vec(patterns: Option<Vec<HttpMockRegex>>) -> Option<Vec<HttpMockRegex>> {
1377 patterns.map(|vec| vec.iter().cloned().collect())
1378}
1379
1380fn from_name_value_string_pair_vec(
1381 kvp: Option<Vec<NameValueStringPair>>,
1382) -> Option<Vec<(String, String)>> {
1383 kvp.map(|vec| vec.into_iter().map(|nvp| (nvp.name, nvp.value)).collect())
1384}
1385
1386fn from_name_value_pattern_pair_vec(
1387 kvp: Option<Vec<NameValuePatternPair>>,
1388) -> Option<Vec<(HttpMockRegex, HttpMockRegex)>> {
1389 kvp.map(|vec| {
1390 vec.into_iter()
1391 .map(|pair| (pair.name, pair.value))
1392 .collect()
1393 })
1394}
1395
1396fn from_string_pair_vec(vec: Option<Vec<(String, String)>>) -> Option<Vec<NameValueStringPair>> {
1397 vec.map(|vec| {
1398 vec.into_iter()
1399 .map(|(name, value)| NameValueStringPair { name, value })
1400 .collect()
1401 })
1402}
1403
1404fn from_key_pattern_count_pair_vec(
1405 input: Option<Vec<KeyPatternCountPair>>,
1406) -> Option<Vec<(HttpMockRegex, usize)>> {
1407 input.map(|vec| vec.into_iter().map(|pair| (pair.key, pair.count)).collect())
1408}
1409
1410fn from_value_pattern_count_pair_vec(
1411 input: Option<Vec<ValuePatternCountPair>>,
1412) -> Option<Vec<(HttpMockRegex, usize)>> {
1413 input.map(|vec| {
1414 vec.into_iter()
1415 .map(|pair| (pair.value, pair.count))
1416 .collect()
1417 })
1418}
1419
1420fn from_key_value_pattern_count_triple_vec(
1421 input: Option<Vec<KeyValuePatternCountTriple>>,
1422) -> Option<Vec<(HttpMockRegex, HttpMockRegex, usize)>> {
1423 input.map(|vec| {
1424 vec.into_iter()
1425 .map(|triple| (triple.name, triple.value, triple.count))
1426 .collect()
1427 })
1428}
1429
1430fn to_name_value_string_pair_vec(
1431 vec: Option<Vec<(String, String)>>,
1432) -> Option<Vec<NameValueStringPair>> {
1433 vec.map(|vec| {
1434 vec.into_iter()
1435 .map(|(name, value)| NameValueStringPair { name, value })
1436 .collect()
1437 })
1438}
1439
1440fn to_name_value_pattern_pair_vec(
1441 vec: Option<Vec<(HttpMockRegex, HttpMockRegex)>>,
1442) -> Option<Vec<NameValuePatternPair>> {
1443 vec.map(|vec| {
1444 vec.into_iter()
1445 .map(|(name, value)| NameValuePatternPair { name, value })
1446 .collect()
1447 })
1448}
1449
1450fn to_key_pattern_count_pair_vec(
1451 vec: Option<Vec<(HttpMockRegex, usize)>>,
1452) -> Option<Vec<KeyPatternCountPair>> {
1453 vec.map(|vec| {
1454 vec.into_iter()
1455 .map(|(key, count)| KeyPatternCountPair { key, count })
1456 .collect()
1457 })
1458}
1459
1460fn to_value_pattern_count_pair_vec(
1461 vec: Option<Vec<(HttpMockRegex, usize)>>,
1462) -> Option<Vec<ValuePatternCountPair>> {
1463 vec.map(|vec| {
1464 vec.into_iter()
1465 .map(|(value, count)| ValuePatternCountPair { value, count })
1466 .collect()
1467 })
1468}
1469
1470fn to_key_value_pattern_count_triple_vec(
1471 vec: Option<Vec<(HttpMockRegex, HttpMockRegex, usize)>>,
1472) -> Option<Vec<KeyValuePatternCountTriple>> {
1473 vec.map(|vec| {
1474 vec.into_iter()
1475 .map(|(name, value, count)| KeyValuePatternCountTriple { name, value, count })
1476 .collect()
1477 })
1478}
1479
1480fn from_bytes_to_string(data: Option<HttpMockBytes>) -> (Option<String>, Option<String>) {
1481 let mut text_representation = None;
1482 let mut base64_representation = None;
1483
1484 if let Some(bytes_container) = data {
1485 if let Ok(text_str) = std::str::from_utf8(&bytes_container.to_bytes()) {
1486 text_representation = Some(text_str.to_string());
1487 } else {
1488 base64_representation = Some(base64::encode(&bytes_container.to_bytes()));
1489 }
1490 }
1491
1492 (text_representation, base64_representation)
1493}
1494
1495fn bytes_to_string_vec(
1496 data: Option<Vec<HttpMockBytes>>,
1497) -> (Option<Vec<String>>, Option<Vec<String>>) {
1498 let mut text_representations = Vec::new();
1499 let mut base64_representations = Vec::new();
1500
1501 if let Some(bytes_vec) = data {
1502 for bytes_container in bytes_vec {
1503 let bytes = bytes_container.to_bytes();
1504 if let Ok(text) = std::str::from_utf8(&bytes) {
1505 text_representations.push(text.to_owned());
1506 } else {
1507 base64_representations.push(base64::encode(&bytes));
1508 }
1509 }
1510 }
1511
1512 let text_opt_vec = if !text_representations.is_empty() {
1513 Some(text_representations)
1514 } else {
1515 None
1516 };
1517
1518 let base64_opt_vec = if !base64_representations.is_empty() {
1519 Some(base64_representations)
1520 } else {
1521 None
1522 };
1523
1524 (text_opt_vec, base64_opt_vec)
1525}
1526
1527fn to_bytes_vec(
1528 option_string: Option<Vec<String>>,
1529 option_base64: Option<Vec<String>>,
1530) -> Option<Vec<HttpMockBytes>> {
1531 let mut result = Vec::new();
1532
1533 if let Some(strings) = option_string {
1534 result.extend(
1535 strings
1536 .into_iter()
1537 .map(|s| HttpMockBytes::from(Bytes::from(s))),
1538 );
1539 }
1540
1541 if let Some(base64_strings) = option_base64 {
1542 result.extend(base64_strings.into_iter().filter_map(|s| {
1543 base64::decode(&s)
1544 .ok()
1545 .map(|decoded_bytes| HttpMockBytes::from(Bytes::from(decoded_bytes)))
1546 }));
1547 }
1548
1549 if result.is_empty() {
1550 None
1551 } else {
1552 Some(result)
1553 }
1554}
1555
1556fn to_bytes(option_string: Option<String>, option_base64: Option<String>) -> Option<String> {
1557 if option_string.is_some() {
1558 return option_string;
1559 }
1560
1561 return option_base64;
1562}
1563
1564fn from_string_to_bytes_choose(
1565 option_string: Option<String>,
1566 option_base64: Option<String>,
1567) -> Option<HttpMockBytes> {
1568 let request_body = match (option_string, option_base64) {
1569 (Some(body), None) => Some(body.into_bytes()),
1570 (None, Some(base64_body)) => base64::decode(base64_body).ok(),
1571 _ => None, };
1573
1574 return request_body.map(|s| HttpMockBytes::from(Bytes::from(s)));
1575}
1576
1577impl TryFrom<&MockDefinition> for StaticMockDefinition {
1578 type Error = Error;
1579
1580 fn try_from(value: &MockDefinition) -> Result<Self, Self::Error> {
1581 let value = value.clone();
1582
1583 let (response_body, response_body_base64) = from_bytes_to_string(value.response.body);
1584
1585 let (request_body, request_body_base64) = from_bytes_to_string(value.request.body);
1586 let (request_body_not, request_body_not_base64) =
1587 bytes_to_string_vec(value.request.body_not);
1588 let (request_body_includes, request_body_includes_base64) =
1589 bytes_to_string_vec(value.request.body_includes);
1590 let (request_body_excludes, request_body_excludes_base64) =
1591 bytes_to_string_vec(value.request.body_excludes);
1592 let (request_body_prefix, request_body_prefix_base64) =
1593 bytes_to_string_vec(value.request.body_prefix);
1594 let (request_body_suffix, request_body_suffix_base64) =
1595 bytes_to_string_vec(value.request.body_suffix);
1596 let (request_body_prefix_not, request_body_prefix_not_base64) =
1597 bytes_to_string_vec(value.request.body_prefix_not);
1598 let (request_body_suffix_not, request_body_suffix_not_base64) =
1599 bytes_to_string_vec(value.request.body_suffix_not);
1600
1601 let mut method = None;
1602 if let Some(method_str) = value.request.method {
1603 method = Some(
1604 Method::from_str(&method_str)
1605 .map_err(|err| StaticMockConversionError(err.to_string()))?,
1606 );
1607 }
1608
1609 Ok(StaticMockDefinition {
1610 when: StaticRequestRequirements {
1611 scheme: value.request.scheme,
1613 scheme_not: value.request.scheme_not,
1614
1615 method,
1617 method_not: to_method_vec(value.request.method_not),
1618 host: value.request.host,
1620 host_not: value.request.host_not,
1621 host_contains: value.request.host_contains,
1622 host_excludes: value.request.host_excludes,
1623 host_prefix: value.request.host_prefix,
1624 host_suffix: value.request.host_suffix,
1625 host_prefix_not: value.request.host_prefix_not,
1626 host_suffix_not: value.request.host_suffix_not,
1627 host_matches: value.request.host_matches,
1628
1629 port: value.request.port,
1631 port_not: value.request.port_not,
1632
1633 path: value.request.path,
1635 path_not: value.request.path_not,
1636 path_contains: value.request.path_includes,
1637 path_excludes: value.request.path_excludes,
1638 path_prefix: value.request.path_prefix,
1639 path_suffix: value.request.path_suffix,
1640 path_prefix_not: value.request.path_prefix_not,
1641 path_suffix_not: value.request.path_suffix_not,
1642 path_matches: from_pattern_vec(value.request.path_matches),
1643
1644 header: from_string_pair_vec(value.request.header),
1646 header_not: from_string_pair_vec(value.request.header_not),
1647 header_exists: value.request.header_exists,
1648 header_missing: value.request.header_missing,
1649 header_contains: to_name_value_string_pair_vec(value.request.header_includes),
1650 header_excludes: to_name_value_string_pair_vec(value.request.header_excludes),
1651 header_prefix: to_name_value_string_pair_vec(value.request.header_prefix),
1652 header_suffix: to_name_value_string_pair_vec(value.request.header_suffix),
1653 header_prefix_not: to_name_value_string_pair_vec(value.request.header_prefix_not),
1654 header_suffix_not: to_name_value_string_pair_vec(value.request.header_suffix_not),
1655 header_matches: to_name_value_pattern_pair_vec(value.request.header_matches),
1656 header_count: to_key_value_pattern_count_triple_vec(value.request.header_count),
1657
1658 cookie: from_string_pair_vec(value.request.cookie),
1660 cookie_not: from_string_pair_vec(value.request.cookie_not),
1661 cookie_exists: value.request.cookie_exists,
1662 cookie_missing: value.request.cookie_missing,
1663 cookie_contains: to_name_value_string_pair_vec(value.request.cookie_includes),
1664 cookie_excludes: to_name_value_string_pair_vec(value.request.cookie_excludes),
1665 cookie_prefix: to_name_value_string_pair_vec(value.request.cookie_prefix),
1666 cookie_suffix: to_name_value_string_pair_vec(value.request.cookie_suffix),
1667 cookie_prefix_not: to_name_value_string_pair_vec(value.request.cookie_prefix_not),
1668 cookie_suffix_not: to_name_value_string_pair_vec(value.request.cookie_suffix_not),
1669 cookie_matches: to_name_value_pattern_pair_vec(value.request.cookie_matches),
1670
1671 cookie_count: to_key_value_pattern_count_triple_vec(value.request.cookie_count),
1672
1673 query_param: from_string_pair_vec(value.request.query_param),
1675 query_param_not: from_string_pair_vec(value.request.query_param_not),
1676 query_param_exists: value.request.query_param_exists,
1677 query_param_missing: value.request.query_param_missing,
1678 query_param_contains: to_name_value_string_pair_vec(
1679 value.request.query_param_includes,
1680 ),
1681 query_param_excludes: to_name_value_string_pair_vec(
1682 value.request.query_param_excludes,
1683 ),
1684 query_param_prefix: to_name_value_string_pair_vec(value.request.query_param_prefix),
1685 query_param_suffix: to_name_value_string_pair_vec(value.request.query_param_suffix),
1686 query_param_prefix_not: to_name_value_string_pair_vec(
1687 value.request.query_param_prefix_not,
1688 ),
1689 query_param_suffix_not: to_name_value_string_pair_vec(
1690 value.request.query_param_suffix_not,
1691 ),
1692 query_param_matches: to_name_value_pattern_pair_vec(
1693 value.request.query_param_matches,
1694 ),
1695 query_param_count: to_key_value_pattern_count_triple_vec(
1696 value.request.query_param_count,
1697 ),
1698
1699 body: request_body,
1701 body_base64: request_body_base64,
1702 body_not: request_body_not,
1703 body_not_base64: request_body_not_base64,
1704 body_contains: request_body_includes,
1705 body_contains_base64: request_body_includes_base64,
1706 body_excludes: request_body_excludes,
1707 body_excludes_base64: request_body_excludes_base64,
1708 body_prefix: request_body_prefix,
1709 body_prefix_base64: request_body_prefix_base64,
1710 body_suffix: request_body_suffix,
1711 body_suffix_base64: request_body_suffix_base64,
1712 body_prefix_not: request_body_prefix_not,
1713 body_prefix_not_base64: request_body_prefix_not_base64,
1714 body_suffix_not: request_body_suffix_not,
1715 body_suffix_not_base64: request_body_suffix_not_base64,
1716 body_matches: from_pattern_vec(value.request.body_matches),
1717
1718 json_body: value.request.json_body,
1720 json_body_not: value.request.json_body_not,
1721 json_body_includes: value.request.json_body_includes,
1722 json_body_excludes: value.request.json_body_excludes,
1723
1724 form_urlencoded_tuple: from_string_pair_vec(value.request.form_urlencoded_tuple),
1726 form_urlencoded_tuple_not: from_string_pair_vec(
1727 value.request.form_urlencoded_tuple_not,
1728 ),
1729 form_urlencoded_key_exists: value.request.form_urlencoded_tuple_exists,
1730 form_urlencoded_key_missing: value.request.form_urlencoded_tuple_missing,
1731 form_urlencoded_contains: to_name_value_string_pair_vec(
1732 value.request.form_urlencoded_tuple_includes,
1733 ),
1734 form_urlencoded_excludes: to_name_value_string_pair_vec(
1735 value.request.form_urlencoded_tuple_excludes,
1736 ),
1737 form_urlencoded_prefix: to_name_value_string_pair_vec(
1738 value.request.form_urlencoded_tuple_prefix,
1739 ),
1740 form_urlencoded_suffix: to_name_value_string_pair_vec(
1741 value.request.form_urlencoded_tuple_suffix,
1742 ),
1743 form_urlencoded_prefix_not: to_name_value_string_pair_vec(
1744 value.request.form_urlencoded_tuple_prefix_not,
1745 ),
1746 form_urlencoded_suffix_not: to_name_value_string_pair_vec(
1747 value.request.form_urlencoded_tuple_suffix_not,
1748 ),
1749 form_urlencoded_matches: to_name_value_pattern_pair_vec(
1750 value.request.form_urlencoded_tuple_matches,
1751 ),
1752
1753 form_urlencoded_count: to_key_value_pattern_count_triple_vec(
1754 value.request.form_urlencoded_tuple_count,
1755 ),
1756 },
1757 then: StaticHTTPResponse {
1758 status: value.response.status,
1759 header: from_string_pair_vec(value.response.headers),
1760 body: response_body,
1761 body_base64: response_body_base64,
1762 delay: value.response.delay,
1769 },
1770 })
1771 }
1772}
1773
1774#[derive(Serialize, Deserialize, Debug)]
1776pub enum Method {
1777 GET,
1778 HEAD,
1779 POST,
1780 PUT,
1781 DELETE,
1782 CONNECT,
1783 OPTIONS,
1784 TRACE,
1785 PATCH,
1786}
1787
1788impl PartialEq<Method> for http::method::Method {
1789 fn eq(&self, other: &Method) -> bool {
1790 self.to_string().to_uppercase() == other.to_string().to_uppercase()
1791 }
1792}
1793
1794impl FromStr for Method {
1795 type Err = String;
1796
1797 fn from_str(input: &str) -> Result<Self, Self::Err> {
1798 match input.to_uppercase().as_str() {
1799 "GET" => Ok(Method::GET),
1800 "HEAD" => Ok(Method::HEAD),
1801 "POST" => Ok(Method::POST),
1802 "PUT" => Ok(Method::PUT),
1803 "DELETE" => Ok(Method::DELETE),
1804 "CONNECT" => Ok(Method::CONNECT),
1805 "OPTIONS" => Ok(Method::OPTIONS),
1806 "TRACE" => Ok(Method::TRACE),
1807 "PATCH" => Ok(Method::PATCH),
1808 _ => Err(format!("Invalid HTTP method {}", input)),
1809 }
1810 }
1811}
1812
1813impl From<&str> for Method {
1814 fn from(value: &str) -> Self {
1815 value
1816 .parse()
1817 .expect(&format!("Cannot parse HTTP method from string {:?}", value))
1818 }
1819}
1820
1821impl std::fmt::Display for Method {
1822 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1823 std::fmt::Debug::fmt(self, f)
1824 }
1825}