1use crate::Request;
9use rama_core::{extensions::Extensions, matcher::IteratorMatcherExt};
10use rama_net::{
11 address::{AsDomainRef, Domain},
12 stream::matcher::SocketMatcher,
13 uri::PathPattern,
14};
15use rama_utils::thirdparty::{regex::Regex, wildcard::Wildcard};
16use std::fmt;
17use std::sync::Arc;
18
19mod method;
20#[doc(inline)]
21pub use method::MethodMatcher;
22
23mod domain;
24#[doc(inline)]
25pub use domain::DomainMatcher;
26
27pub mod uri;
28pub use uri::UriMatcher;
29
30mod version;
31#[doc(inline)]
32pub use version::VersionMatcher;
33
34pub(crate) mod path;
35#[doc(inline)]
36pub use path::{UriParams, UriParamsDeserializeError};
37
38mod header;
39#[doc(inline)]
40pub use header::HeaderMatcher;
41
42mod subdomain_trie;
43#[doc(inline)]
44pub use subdomain_trie::SubdomainTrieMatcher;
45
46pub struct HttpMatcher<Body> {
48 kind: HttpMatcherKind<Body>,
49 negate: bool,
50}
51
52impl<Body> Clone for HttpMatcher<Body> {
53 fn clone(&self) -> Self {
54 Self {
55 kind: self.kind.clone(),
56 negate: self.negate,
57 }
58 }
59}
60
61impl<Body> fmt::Debug for HttpMatcher<Body> {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 f.debug_struct("HttpMatcher")
64 .field("kind", &self.kind)
65 .field("negate", &self.negate)
66 .finish()
67 }
68}
69
70pub enum HttpMatcherKind<Body> {
72 All(Vec<HttpMatcher<Body>>),
74 Method(MethodMatcher),
76 Path(PathPattern),
80 Domain(DomainMatcher),
82 Version(VersionMatcher),
84 Any(Vec<HttpMatcher<Body>>),
86 Uri(UriMatcher),
88 Header(HeaderMatcher),
90 Socket(SocketMatcher<Request<Body>>),
94 SubdomainTrie(SubdomainTrieMatcher),
96 Custom(Arc<dyn rama_core::matcher::Matcher<Request<Body>>>),
98}
99
100impl<Body> Clone for HttpMatcherKind<Body> {
101 fn clone(&self) -> Self {
102 match self {
103 Self::All(inner) => Self::All(inner.clone()),
104 Self::Method(inner) => Self::Method(*inner),
105 Self::Path(inner) => Self::Path(inner.clone()),
106 Self::Domain(inner) => Self::Domain(inner.clone()),
107 Self::Version(inner) => Self::Version(*inner),
108 Self::Any(inner) => Self::Any(inner.clone()),
109 Self::Uri(inner) => Self::Uri(inner.clone()),
110 Self::Header(inner) => Self::Header(inner.clone()),
111 Self::Socket(inner) => Self::Socket(inner.clone()),
112 Self::SubdomainTrie(inner) => Self::SubdomainTrie(inner.clone()),
113 Self::Custom(inner) => Self::Custom(inner.clone()),
114 }
115 }
116}
117
118impl<Body> fmt::Debug for HttpMatcherKind<Body> {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 match self {
121 Self::All(inner) => f.debug_tuple("All").field(inner).finish(),
122 Self::Method(inner) => f.debug_tuple("Method").field(inner).finish(),
123 Self::Path(inner) => f.debug_tuple("Path").field(inner).finish(),
124 Self::Domain(inner) => f.debug_tuple("Domain").field(inner).finish(),
125 Self::Version(inner) => f.debug_tuple("Version").field(inner).finish(),
126 Self::Any(inner) => f.debug_tuple("Any").field(inner).finish(),
127 Self::Uri(inner) => f.debug_tuple("Uri").field(inner).finish(),
128 Self::Header(inner) => f.debug_tuple("Header").field(inner).finish(),
129 Self::Socket(inner) => f.debug_tuple("Socket").field(inner).finish(),
130 Self::SubdomainTrie(inner) => f.debug_tuple("SubdomainTrie").field(inner).finish(),
131 Self::Custom(_) => f.debug_tuple("Custom").finish(),
132 }
133 }
134}
135
136impl<Body> HttpMatcher<Body> {
137 #[must_use]
141 pub fn method(method: MethodMatcher) -> Self {
142 Self {
143 kind: HttpMatcherKind::Method(method),
144 negate: false,
145 }
146 }
147
148 #[must_use]
152 pub fn and_method(self, method: MethodMatcher) -> Self {
153 self.and(Self::method(method))
154 }
155
156 #[must_use]
160 pub fn or_method(self, method: MethodMatcher) -> Self {
161 self.or(Self::method(method))
162 }
163
164 #[must_use]
168 pub fn method_delete() -> Self {
169 Self {
170 kind: HttpMatcherKind::Method(MethodMatcher::DELETE),
171 negate: false,
172 }
173 }
174
175 #[must_use]
179 pub fn and_method_delete(self) -> Self {
180 self.and(Self::method_delete())
181 }
182
183 #[must_use]
188 pub fn or_method_delete(self) -> Self {
189 self.or(Self::method_delete())
190 }
191
192 #[must_use]
196 pub fn method_get() -> Self {
197 Self {
198 kind: HttpMatcherKind::Method(MethodMatcher::GET),
199 negate: false,
200 }
201 }
202
203 #[must_use]
207 pub fn and_method_get(self) -> Self {
208 self.and(Self::method_get())
209 }
210
211 #[must_use]
216 pub fn or_method_get(self) -> Self {
217 self.or(Self::method_get())
218 }
219
220 #[must_use]
224 pub fn method_head() -> Self {
225 Self {
226 kind: HttpMatcherKind::Method(MethodMatcher::HEAD),
227 negate: false,
228 }
229 }
230
231 #[must_use]
235 pub fn and_method_head(self) -> Self {
236 self.and(Self::method_head())
237 }
238
239 #[must_use]
244 pub fn or_method_head(self) -> Self {
245 self.or(Self::method_head())
246 }
247
248 #[must_use]
252 pub fn method_options() -> Self {
253 Self {
254 kind: HttpMatcherKind::Method(MethodMatcher::OPTIONS),
255 negate: false,
256 }
257 }
258
259 #[must_use]
263 pub fn and_method_options(self) -> Self {
264 self.and(Self::method_options())
265 }
266
267 #[must_use]
272 pub fn or_method_options(self) -> Self {
273 self.or(Self::method_options())
274 }
275
276 #[must_use]
280 pub fn method_patch() -> Self {
281 Self {
282 kind: HttpMatcherKind::Method(MethodMatcher::PATCH),
283 negate: false,
284 }
285 }
286
287 #[must_use]
291 pub fn and_method_patch(self) -> Self {
292 self.and(Self::method_patch())
293 }
294
295 #[must_use]
300 pub fn or_method_patch(self) -> Self {
301 self.or(Self::method_patch())
302 }
303
304 #[must_use]
308 pub fn method_post() -> Self {
309 Self {
310 kind: HttpMatcherKind::Method(MethodMatcher::POST),
311 negate: false,
312 }
313 }
314
315 #[must_use]
319 pub fn and_method_post(self) -> Self {
320 self.and(Self::method_post())
321 }
322
323 #[must_use]
328 pub fn or_method_post(self) -> Self {
329 self.or(Self::method_post())
330 }
331
332 #[must_use]
336 pub fn method_put() -> Self {
337 Self {
338 kind: HttpMatcherKind::Method(MethodMatcher::PUT),
339 negate: false,
340 }
341 }
342
343 #[must_use]
347 pub fn and_method_put(self) -> Self {
348 self.and(Self::method_put())
349 }
350
351 #[must_use]
356 pub fn or_method_put(self) -> Self {
357 self.or(Self::method_put())
358 }
359
360 #[must_use]
364 pub fn method_query() -> Self {
365 Self {
366 kind: HttpMatcherKind::Method(MethodMatcher::QUERY),
367 negate: false,
368 }
369 }
370
371 #[must_use]
375 pub fn and_method_query(self) -> Self {
376 self.and(Self::method_query())
377 }
378
379 #[must_use]
384 pub fn or_method_query(self) -> Self {
385 self.or(Self::method_query())
386 }
387
388 #[must_use]
392 pub fn method_trace() -> Self {
393 Self {
394 kind: HttpMatcherKind::Method(MethodMatcher::TRACE),
395 negate: false,
396 }
397 }
398
399 #[must_use]
403 pub fn and_method_trace(self) -> Self {
404 self.and(Self::method_trace())
405 }
406
407 #[must_use]
412 pub fn or_method_trace(self) -> Self {
413 self.or(Self::method_trace())
414 }
415
416 #[must_use]
420 pub fn method_connect() -> Self {
421 Self {
422 kind: HttpMatcherKind::Method(MethodMatcher::CONNECT),
423 negate: false,
424 }
425 }
426
427 #[must_use]
431 pub fn and_method_connect(self) -> Self {
432 self.and(Self::method_connect())
433 }
434
435 #[must_use]
440 pub fn or_method_connect(self) -> Self {
441 self.or(Self::method_connect())
442 }
443
444 #[must_use]
446 pub fn domain(domain: Domain) -> Self {
447 Self {
448 kind: HttpMatcherKind::Domain(DomainMatcher::exact(domain)),
449 negate: false,
450 }
451 }
452
453 #[must_use]
456 pub fn subdomain(domain: Domain) -> Self {
457 Self {
458 kind: HttpMatcherKind::Domain(DomainMatcher::sub(domain)),
459 negate: false,
460 }
461 }
462
463 #[must_use]
467 pub fn and_domain(self, domain: Domain) -> Self {
468 self.and(Self::domain(domain))
469 }
470
471 #[must_use]
475 pub fn and_subdomain(self, domain: Domain) -> Self {
476 self.and(Self::subdomain(domain))
477 }
478
479 #[must_use]
483 pub fn or_domain(self, domain: Domain) -> Self {
484 self.or(Self::domain(domain))
485 }
486
487 #[must_use]
491 pub fn or_subdomain(self, domain: Domain) -> Self {
492 self.or(Self::subdomain(domain))
493 }
494
495 #[must_use]
497 pub fn version(version: VersionMatcher) -> Self {
498 Self {
499 kind: HttpMatcherKind::Version(version),
500 negate: false,
501 }
502 }
503
504 #[must_use]
508 pub fn and_version(self, version: VersionMatcher) -> Self {
509 self.and(Self::version(version))
510 }
511
512 #[must_use]
516 pub fn or_version(self, version: VersionMatcher) -> Self {
517 self.or(Self::version(version))
518 }
519
520 #[must_use]
522 pub fn uri_regex(re: Regex) -> Self {
523 Self {
524 kind: HttpMatcherKind::Uri(UriMatcher::regex(re)),
525 negate: false,
526 }
527 }
528
529 #[must_use]
531 pub fn uri_wildcard(wc: Wildcard<'static>) -> Self {
532 Self {
533 kind: HttpMatcherKind::Uri(UriMatcher::wildcard(wc)),
534 negate: false,
535 }
536 }
537
538 #[must_use]
542 pub fn and_uri_regex(self, re: Regex) -> Self {
543 self.and(Self::uri_regex(re))
544 }
545
546 #[must_use]
550 pub fn and_uri_wildcard(self, wc: Wildcard<'static>) -> Self {
551 self.and(Self::uri_wildcard(wc))
552 }
553
554 #[must_use]
558 pub fn or_uri_regex(self, re: Regex) -> Self {
559 self.or(Self::uri_regex(re))
560 }
561
562 #[must_use]
566 pub fn or_uri_wildcard(self, wc: Wildcard<'static>) -> Self {
567 self.or(Self::uri_wildcard(wc))
568 }
569
570 #[must_use]
573 pub fn path(path: impl AsRef<str>) -> Self {
574 Self {
575 kind: HttpMatcherKind::Path(path::compile_pattern(path.as_ref())),
576 negate: false,
577 }
578 }
579
580 #[must_use]
585 pub fn path_prefix(path: impl AsRef<str>) -> Self {
586 Self {
587 kind: HttpMatcherKind::Path(path::compile_prefix_pattern(path.as_ref())),
588 negate: false,
589 }
590 }
591
592 #[must_use]
594 pub fn and_path(self, path: impl AsRef<str>) -> Self {
595 self.and(Self::path(path))
596 }
597
598 #[must_use]
600 pub fn or_path(self, path: impl AsRef<str>) -> Self {
601 self.or(Self::path(path))
602 }
603
604 #[must_use]
606 pub fn header(
607 name: rama_http_types::header::HeaderName,
608 value: rama_http_types::header::HeaderValue,
609 ) -> Self {
610 Self {
611 kind: HttpMatcherKind::Header(HeaderMatcher::is(name, value)),
612 negate: false,
613 }
614 }
615
616 #[must_use]
620 pub fn and_header(
621 self,
622 name: rama_http_types::header::HeaderName,
623 value: rama_http_types::header::HeaderValue,
624 ) -> Self {
625 self.and(Self::header(name, value))
626 }
627
628 #[must_use]
632 pub fn or_header(
633 self,
634 name: rama_http_types::header::HeaderName,
635 value: rama_http_types::header::HeaderValue,
636 ) -> Self {
637 self.or(Self::header(name, value))
638 }
639
640 #[must_use]
643 pub fn header_exists(name: rama_http_types::header::HeaderName) -> Self {
644 Self {
645 kind: HttpMatcherKind::Header(HeaderMatcher::exists(name)),
646 negate: false,
647 }
648 }
649
650 #[must_use]
655 pub fn and_header_exists(self, name: rama_http_types::header::HeaderName) -> Self {
656 self.and(Self::header_exists(name))
657 }
658
659 #[must_use]
664 pub fn or_header_exists(self, name: rama_http_types::header::HeaderName) -> Self {
665 self.or(Self::header_exists(name))
666 }
667
668 #[must_use]
670 pub fn header_contains(
671 name: rama_http_types::header::HeaderName,
672 value: rama_http_types::header::HeaderValue,
673 ) -> Self {
674 Self {
675 kind: HttpMatcherKind::Header(HeaderMatcher::contains(name, value)),
676 negate: false,
677 }
678 }
679
680 #[must_use]
685 pub fn and_header_contains(
686 self,
687 name: rama_http_types::header::HeaderName,
688 value: rama_http_types::header::HeaderValue,
689 ) -> Self {
690 self.and(Self::header_contains(name, value))
691 }
692
693 #[must_use]
698 pub fn or_header_contains(
699 self,
700 name: rama_http_types::header::HeaderName,
701 value: rama_http_types::header::HeaderValue,
702 ) -> Self {
703 self.or(Self::header_contains(name, value))
704 }
705
706 #[must_use]
708 pub fn socket(socket: SocketMatcher<Request<Body>>) -> Self {
709 Self {
710 kind: HttpMatcherKind::Socket(socket),
711 negate: false,
712 }
713 }
714
715 #[must_use]
719 pub fn and_socket(self, socket: SocketMatcher<Request<Body>>) -> Self {
720 self.and(Self::socket(socket))
721 }
722
723 #[must_use]
727 pub fn or_socket(self, socket: SocketMatcher<Request<Body>>) -> Self {
728 self.or(Self::socket(socket))
729 }
730
731 #[must_use]
733 pub fn get(path: impl AsRef<str>) -> Self {
734 Self::method_get().and_path(path)
735 }
736
737 #[must_use]
741 pub fn custom<M>(matcher: M) -> Self
742 where
743 M: rama_core::matcher::Matcher<Request<Body>>,
744 {
745 Self {
746 kind: HttpMatcherKind::Custom(Arc::new(matcher)),
747 negate: false,
748 }
749 }
750
751 #[must_use]
755 pub fn and_custom<M>(self, matcher: M) -> Self
756 where
757 M: rama_core::matcher::Matcher<Request<Body>>,
758 {
759 self.and(Self::custom(matcher))
760 }
761
762 #[must_use]
766 pub fn or_custom<M>(self, matcher: M) -> Self
767 where
768 M: rama_core::matcher::Matcher<Request<Body>>,
769 {
770 self.or(Self::custom(matcher))
771 }
772
773 #[must_use]
777 pub fn any_subdomain<I, S>(domains: I) -> Self
778 where
779 I: IntoIterator<Item = S>,
780 S: AsDomainRef,
781 {
782 Self {
783 kind: HttpMatcherKind::SubdomainTrie(SubdomainTrieMatcher::new(domains)),
784 negate: false,
785 }
786 }
787
788 #[must_use]
792 pub fn and_any_subdomain<I, S>(self, domains: I) -> Self
793 where
794 I: IntoIterator<Item = S>,
795 S: AsDomainRef,
796 {
797 self.and(Self::any_subdomain(domains))
798 }
799
800 #[must_use]
804 pub fn or_any_subdomain<I, S>(self, domains: I) -> Self
805 where
806 I: IntoIterator<Item = S>,
807 S: AsDomainRef,
808 {
809 self.or(Self::any_subdomain(domains))
810 }
811
812 #[must_use]
814 pub fn post(path: impl AsRef<str>) -> Self {
815 Self::method_post().and_path(path)
816 }
817
818 #[must_use]
820 pub fn put(path: impl AsRef<str>) -> Self {
821 Self::method_put().and_path(path)
822 }
823
824 #[must_use]
826 pub fn delete(path: impl AsRef<str>) -> Self {
827 Self::method_delete().and_path(path)
828 }
829
830 #[must_use]
832 pub fn patch(path: impl AsRef<str>) -> Self {
833 Self::method_patch().and_path(path)
834 }
835
836 #[must_use]
838 pub fn head(path: impl AsRef<str>) -> Self {
839 Self::method_head().and_path(path)
840 }
841
842 #[must_use]
844 pub fn options(path: impl AsRef<str>) -> Self {
845 Self::method_options().and_path(path)
846 }
847
848 #[must_use]
850 pub fn trace(path: impl AsRef<str>) -> Self {
851 Self::method_trace().and_path(path)
852 }
853
854 #[must_use]
856 pub fn connect(path: impl AsRef<str>) -> Self {
857 Self::method_connect().and_path(path)
858 }
859
860 #[must_use]
862 pub fn query(path: impl AsRef<str>) -> Self {
863 Self::method_query().and_path(path)
864 }
865
866 #[must_use]
868 pub fn and(mut self, matcher: Self) -> Self {
869 match (self.negate, &mut self.kind) {
870 (false, HttpMatcherKind::All(v)) => {
871 v.push(matcher);
872 self
873 }
874 _ => Self {
875 kind: HttpMatcherKind::All(vec![self, matcher]),
876 negate: false,
877 },
878 }
879 }
880
881 #[must_use]
884 pub fn or(mut self, matcher: Self) -> Self {
885 match (self.negate, &mut self.kind) {
886 (false, HttpMatcherKind::Any(v)) => {
887 v.push(matcher);
888 self
889 }
890 _ => Self {
891 kind: HttpMatcherKind::Any(vec![self, matcher]),
892 negate: false,
893 },
894 }
895 }
896
897 #[must_use]
899 pub fn negate(self) -> Self {
900 Self {
901 kind: self.kind,
902 negate: true,
903 }
904 }
905
906 pub fn allowed_methods(&self) -> Option<MethodMatcher> {
914 let m = self.kind.allowed_methods();
915 if self.negate {
916 m.map(|m| m.complement())
917 } else {
918 m
919 }
920 }
921}
922
923impl<Body> HttpMatcherKind<Body> {
924 fn allowed_methods(&self) -> Option<MethodMatcher> {
925 match self {
926 Self::Method(m) => Some(*m),
927 Self::All(matchers) => {
928 matchers
931 .iter()
932 .filter_map(|m| m.allowed_methods())
933 .reduce(|acc, next| acc.and_method(next))
934 }
935 Self::Any(matchers) => {
936 matchers.iter().try_fold(MethodMatcher::NONE, |acc, m| {
939 Some(acc.or_method(m.allowed_methods()?))
940 })
941 }
942 _ => None,
944 }
945 }
946}
947
948impl<Body> rama_core::matcher::Matcher<Request<Body>> for HttpMatcher<Body>
949where
950 Body: Send + 'static,
951{
952 fn matches(&self, ext: Option<&Extensions>, req: &Request<Body>) -> bool {
953 let matches = self.kind.matches(ext, req);
954 if self.negate { !matches } else { matches }
955 }
956}
957
958impl<Body> rama_core::matcher::Matcher<Request<Body>> for HttpMatcherKind<Body>
959where
960 Body: Send + 'static,
961{
962 fn matches(&self, ext: Option<&Extensions>, req: &Request<Body>) -> bool {
963 match self {
964 Self::All(all) => all.iter().matches_and(ext, req),
965 Self::Method(method) => method.matches(ext, req),
966 Self::Path(pattern) => path::match_pattern(pattern, ext, req.uri().path_ref_or_root()),
967 Self::Domain(domain) => domain.matches(ext, req),
968 Self::Version(version) => version.matches(ext, req),
969 Self::Uri(uri) => uri.matches(ext, req),
970 Self::Header(header) => header.matches(ext, req),
971 Self::Socket(socket) => socket.matches(ext, req),
972 Self::Any(all) => all.iter().matches_or(ext, req),
973 Self::SubdomainTrie(subdomain_trie) => subdomain_trie.matches(ext, req),
974 Self::Custom(matcher) => matcher.matches(ext, req),
975 }
976 }
977}
978
979#[cfg(test)]
980mod test {
981 use itertools::Itertools;
982
983 use rama_core::matcher::Matcher;
984
985 use super::*;
986
987 struct BooleanMatcher(bool);
988
989 impl Matcher<Request<()>> for BooleanMatcher {
990 fn matches(&self, _ext: Option<&Extensions>, _req: &Request<()>) -> bool {
991 self.0
992 }
993 }
994
995 #[test]
996 fn test_matcher_and_combination() {
997 for v in [true, false].into_iter().permutations(3) {
998 let expected = v[0] && v[1] && v[2];
999 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
1000 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
1001 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
1002
1003 let matcher = a.and(b).and(c);
1004 let req = Request::builder().body(()).unwrap();
1005 assert_eq!(
1006 matcher.matches(None, &req),
1007 expected,
1008 "({matcher:#?}).matches({req:#?})",
1009 );
1010 }
1011 }
1012
1013 #[test]
1014 fn test_matcher_negation_with_and_combination() {
1015 for v in [true, false].into_iter().permutations(3) {
1016 let expected = !v[0] && v[1] && v[2];
1017 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
1018 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
1019 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
1020
1021 let matcher = a.negate().and(b).and(c);
1022 let req = Request::builder().body(()).unwrap();
1023 assert_eq!(
1024 matcher.matches(None, &req),
1025 expected,
1026 "({matcher:#?}).matches({req:#?})",
1027 );
1028 }
1029 }
1030
1031 #[test]
1032 fn test_matcher_and_combination_negated() {
1033 for v in [true, false].into_iter().permutations(3) {
1034 let expected = !(v[0] && v[1] && v[2]);
1035 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
1036 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
1037 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
1038
1039 let matcher = a.and(b).and(c).negate();
1040 let req = Request::builder().body(()).unwrap();
1041 assert_eq!(
1042 matcher.matches(None, &req),
1043 expected,
1044 "({matcher:#?}).matches({req:#?})",
1045 );
1046 }
1047 }
1048
1049 #[test]
1050 fn test_matcher_ors_combination() {
1051 for v in [true, false].into_iter().permutations(3) {
1052 let expected = v[0] || v[1] || v[2];
1053 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
1054 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
1055 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
1056
1057 let matcher = a.or(b).or(c);
1058 let req = Request::builder().body(()).unwrap();
1059 assert_eq!(
1060 matcher.matches(None, &req),
1061 expected,
1062 "({matcher:#?}).matches({req:#?})",
1063 );
1064 }
1065 }
1066
1067 #[test]
1068 fn test_matcher_negation_with_ors_combination() {
1069 for v in [true, false].into_iter().permutations(3) {
1070 let expected = !v[0] || v[1] || v[2];
1071 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
1072 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
1073 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
1074
1075 let matcher = a.negate().or(b).or(c);
1076 let req = Request::builder().body(()).unwrap();
1077 assert_eq!(
1078 matcher.matches(None, &req),
1079 expected,
1080 "({matcher:#?}).matches({req:#?})",
1081 );
1082 }
1083 }
1084
1085 #[test]
1086 fn test_matcher_ors_combination_negated() {
1087 for v in [true, false].into_iter().permutations(3) {
1088 let expected = !(v[0] || v[1] || v[2]);
1089 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
1090 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
1091 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
1092
1093 let matcher = a.or(b).or(c).negate();
1094 let req = Request::builder().body(()).unwrap();
1095 assert_eq!(
1096 matcher.matches(None, &req),
1097 expected,
1098 "({matcher:#?}).matches({req:#?})",
1099 );
1100 }
1101 }
1102
1103 #[test]
1104 fn test_matcher_or_and_or_and_negation() {
1105 for v in [true, false].into_iter().permutations(5) {
1106 let expected = (v[0] || v[1]) && (v[2] || v[3]) && !v[4];
1107 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
1108 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
1109 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
1110 let d = HttpMatcher::custom(BooleanMatcher(v[3]));
1111 let e = HttpMatcher::custom(BooleanMatcher(v[4]));
1112
1113 let matcher = (a.or(b)).and(c.or(d)).and(e.negate());
1114 let req = Request::builder().body(()).unwrap();
1115 assert_eq!(
1116 matcher.matches(None, &req),
1117 expected,
1118 "({matcher:#?}).matches({req:#?})",
1119 );
1120 }
1121 }
1122}