1use crate::Request;
9use rama_core::{Context, context::Extensions, matcher::IteratorMatcherExt};
10use rama_net::{address::Domain, stream::matcher::SocketMatcher};
11use std::fmt;
12use std::sync::Arc;
13
14mod method;
15#[doc(inline)]
16pub use method::MethodMatcher;
17
18mod domain;
19#[doc(inline)]
20pub use domain::DomainMatcher;
21
22pub mod uri;
23pub use uri::UriMatcher;
24
25mod version;
26#[doc(inline)]
27pub use version::VersionMatcher;
28
29mod path;
30#[doc(inline)]
31pub use path::{PathMatcher, UriParams, UriParamsDeserializeError};
32
33mod header;
34#[doc(inline)]
35pub use header::HeaderMatcher;
36
37mod subdomain_trie;
38#[doc(inline)]
39pub use subdomain_trie::SubdomainTrieMatcher;
40
41pub struct HttpMatcher<State, Body> {
43 kind: HttpMatcherKind<State, Body>,
44 negate: bool,
45}
46
47impl<State, Body> Clone for HttpMatcher<State, Body> {
48 fn clone(&self) -> Self {
49 Self {
50 kind: self.kind.clone(),
51 negate: self.negate,
52 }
53 }
54}
55
56impl<State, Body> fmt::Debug for HttpMatcher<State, Body> {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 f.debug_struct("HttpMatcher")
59 .field("kind", &self.kind)
60 .field("negate", &self.negate)
61 .finish()
62 }
63}
64
65pub enum HttpMatcherKind<State, Body> {
67 All(Vec<HttpMatcher<State, Body>>),
69 Method(MethodMatcher),
71 Path(PathMatcher),
73 Domain(DomainMatcher),
75 Version(VersionMatcher),
77 Any(Vec<HttpMatcher<State, Body>>),
79 Uri(UriMatcher),
81 Header(HeaderMatcher),
83 Socket(SocketMatcher<State, Request<Body>>),
87 SubdomainTrie(SubdomainTrieMatcher),
89 Custom(Arc<dyn rama_core::matcher::Matcher<State, Request<Body>>>),
91}
92
93impl<State, Body> Clone for HttpMatcherKind<State, Body> {
94 fn clone(&self) -> Self {
95 match self {
96 Self::All(inner) => Self::All(inner.clone()),
97 Self::Method(inner) => Self::Method(*inner),
98 Self::Path(inner) => Self::Path(inner.clone()),
99 Self::Domain(inner) => Self::Domain(inner.clone()),
100 Self::Version(inner) => Self::Version(*inner),
101 Self::Any(inner) => Self::Any(inner.clone()),
102 Self::Uri(inner) => Self::Uri(inner.clone()),
103 Self::Header(inner) => Self::Header(inner.clone()),
104 Self::Socket(inner) => Self::Socket(inner.clone()),
105 Self::SubdomainTrie(inner) => Self::SubdomainTrie(inner.clone()),
106 Self::Custom(inner) => Self::Custom(inner.clone()),
107 }
108 }
109}
110
111impl<State, Body> fmt::Debug for HttpMatcherKind<State, Body> {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 match self {
114 Self::All(inner) => f.debug_tuple("All").field(inner).finish(),
115 Self::Method(inner) => f.debug_tuple("Method").field(inner).finish(),
116 Self::Path(inner) => f.debug_tuple("Path").field(inner).finish(),
117 Self::Domain(inner) => f.debug_tuple("Domain").field(inner).finish(),
118 Self::Version(inner) => f.debug_tuple("Version").field(inner).finish(),
119 Self::Any(inner) => f.debug_tuple("Any").field(inner).finish(),
120 Self::Uri(inner) => f.debug_tuple("Uri").field(inner).finish(),
121 Self::Header(inner) => f.debug_tuple("Header").field(inner).finish(),
122 Self::Socket(inner) => f.debug_tuple("Socket").field(inner).finish(),
123 Self::SubdomainTrie(inner) => f.debug_tuple("SubdomainTrie").field(inner).finish(),
124 Self::Custom(_) => f.debug_tuple("Custom").finish(),
125 }
126 }
127}
128
129impl<State, Body> HttpMatcher<State, Body> {
130 pub fn method(method: MethodMatcher) -> Self {
134 Self {
135 kind: HttpMatcherKind::Method(method),
136 negate: false,
137 }
138 }
139
140 pub fn and_method(self, method: MethodMatcher) -> Self {
144 self.and(Self::method(method))
145 }
146
147 pub fn or_method(self, method: MethodMatcher) -> Self {
151 self.or(Self::method(method))
152 }
153
154 pub fn method_delete() -> Self {
158 Self {
159 kind: HttpMatcherKind::Method(MethodMatcher::DELETE),
160 negate: false,
161 }
162 }
163
164 pub fn and_method_delete(self) -> Self {
168 self.and(Self::method_delete())
169 }
170
171 pub fn or_method_delete(self) -> Self {
176 self.or(Self::method_delete())
177 }
178
179 pub fn method_get() -> Self {
183 Self {
184 kind: HttpMatcherKind::Method(MethodMatcher::GET),
185 negate: false,
186 }
187 }
188
189 pub fn and_method_get(self) -> Self {
193 self.and(Self::method_get())
194 }
195
196 pub fn or_method_get(self) -> Self {
201 self.or(Self::method_get())
202 }
203
204 pub fn method_head() -> Self {
208 Self {
209 kind: HttpMatcherKind::Method(MethodMatcher::HEAD),
210 negate: false,
211 }
212 }
213
214 pub fn and_method_head(self) -> Self {
218 self.and(Self::method_head())
219 }
220
221 pub fn or_method_head(self) -> Self {
226 self.or(Self::method_head())
227 }
228
229 pub fn method_options() -> Self {
233 Self {
234 kind: HttpMatcherKind::Method(MethodMatcher::OPTIONS),
235 negate: false,
236 }
237 }
238
239 pub fn and_method_options(self) -> Self {
243 self.and(Self::method_options())
244 }
245
246 pub fn or_method_options(self) -> Self {
251 self.or(Self::method_options())
252 }
253
254 pub fn method_patch() -> Self {
258 Self {
259 kind: HttpMatcherKind::Method(MethodMatcher::PATCH),
260 negate: false,
261 }
262 }
263
264 pub fn and_method_patch(self) -> Self {
268 self.and(Self::method_patch())
269 }
270
271 pub fn or_method_patch(self) -> Self {
276 self.or(Self::method_patch())
277 }
278
279 pub fn method_post() -> Self {
283 Self {
284 kind: HttpMatcherKind::Method(MethodMatcher::POST),
285 negate: false,
286 }
287 }
288
289 pub fn and_method_post(self) -> Self {
293 self.and(Self::method_post())
294 }
295
296 pub fn or_method_post(self) -> Self {
301 self.or(Self::method_post())
302 }
303
304 pub fn method_put() -> Self {
308 Self {
309 kind: HttpMatcherKind::Method(MethodMatcher::PUT),
310 negate: false,
311 }
312 }
313
314 pub fn and_method_put(self) -> Self {
318 self.and(Self::method_put())
319 }
320
321 pub fn or_method_put(self) -> Self {
326 self.or(Self::method_put())
327 }
328
329 pub fn method_trace() -> Self {
333 Self {
334 kind: HttpMatcherKind::Method(MethodMatcher::TRACE),
335 negate: false,
336 }
337 }
338
339 pub fn and_method_trace(self) -> Self {
343 self.and(Self::method_trace())
344 }
345
346 pub fn or_method_trace(self) -> Self {
351 self.or(Self::method_trace())
352 }
353
354 pub fn domain(domain: Domain) -> Self {
356 Self {
357 kind: HttpMatcherKind::Domain(DomainMatcher::exact(domain)),
358 negate: false,
359 }
360 }
361
362 pub fn subdomain(domain: Domain) -> Self {
365 Self {
366 kind: HttpMatcherKind::Domain(DomainMatcher::sub(domain)),
367 negate: false,
368 }
369 }
370
371 pub fn and_domain(self, domain: Domain) -> Self {
375 self.and(Self::domain(domain))
376 }
377
378 pub fn and_subdomain(self, domain: Domain) -> Self {
382 self.and(Self::subdomain(domain))
383 }
384
385 pub fn or_domain(self, domain: Domain) -> Self {
389 self.or(Self::domain(domain))
390 }
391
392 pub fn or_subdomain(self, domain: Domain) -> Self {
396 self.or(Self::subdomain(domain))
397 }
398
399 pub fn version(version: VersionMatcher) -> Self {
401 Self {
402 kind: HttpMatcherKind::Version(version),
403 negate: false,
404 }
405 }
406
407 pub fn and_version(self, version: VersionMatcher) -> Self {
411 self.and(Self::version(version))
412 }
413
414 pub fn or_version(self, version: VersionMatcher) -> Self {
418 self.or(Self::version(version))
419 }
420
421 pub fn uri(re: impl AsRef<str>) -> Self {
423 Self {
424 kind: HttpMatcherKind::Uri(UriMatcher::new(re)),
425 negate: false,
426 }
427 }
428
429 pub fn and_uri(self, re: impl AsRef<str>) -> Self {
433 self.and(Self::uri(re))
434 }
435
436 pub fn or_uri(self, re: impl AsRef<str>) -> Self {
440 self.or(Self::uri(re))
441 }
442
443 pub fn path(path: impl AsRef<str>) -> Self {
445 Self {
446 kind: HttpMatcherKind::Path(PathMatcher::new(path)),
447 negate: false,
448 }
449 }
450
451 pub fn and_path(self, path: impl AsRef<str>) -> Self {
455 self.and(Self::path(path))
456 }
457
458 pub fn or_path(self, path: impl AsRef<str>) -> Self {
462 self.or(Self::path(path))
463 }
464
465 pub fn header(
467 name: rama_http_types::header::HeaderName,
468 value: rama_http_types::header::HeaderValue,
469 ) -> Self {
470 Self {
471 kind: HttpMatcherKind::Header(HeaderMatcher::is(name, value)),
472 negate: false,
473 }
474 }
475
476 pub fn and_header(
480 self,
481 name: rama_http_types::header::HeaderName,
482 value: rama_http_types::header::HeaderValue,
483 ) -> Self {
484 self.and(Self::header(name, value))
485 }
486
487 pub fn or_header(
491 self,
492 name: rama_http_types::header::HeaderName,
493 value: rama_http_types::header::HeaderValue,
494 ) -> Self {
495 self.or(Self::header(name, value))
496 }
497
498 pub fn header_exists(name: rama_http_types::header::HeaderName) -> Self {
501 Self {
502 kind: HttpMatcherKind::Header(HeaderMatcher::exists(name)),
503 negate: false,
504 }
505 }
506
507 pub fn and_header_exists(self, name: rama_http_types::header::HeaderName) -> Self {
512 self.and(Self::header_exists(name))
513 }
514
515 pub fn or_header_exists(self, name: rama_http_types::header::HeaderName) -> Self {
520 self.or(Self::header_exists(name))
521 }
522
523 pub fn header_contains(
525 name: rama_http_types::header::HeaderName,
526 value: rama_http_types::header::HeaderValue,
527 ) -> Self {
528 Self {
529 kind: HttpMatcherKind::Header(HeaderMatcher::contains(name, value)),
530 negate: false,
531 }
532 }
533
534 pub fn and_header_contains(
539 self,
540 name: rama_http_types::header::HeaderName,
541 value: rama_http_types::header::HeaderValue,
542 ) -> Self {
543 self.and(Self::header_contains(name, value))
544 }
545
546 pub fn or_header_contains(
551 self,
552 name: rama_http_types::header::HeaderName,
553 value: rama_http_types::header::HeaderValue,
554 ) -> Self {
555 self.or(Self::header_contains(name, value))
556 }
557
558 pub fn socket(socket: SocketMatcher<State, Request<Body>>) -> Self {
560 Self {
561 kind: HttpMatcherKind::Socket(socket),
562 negate: false,
563 }
564 }
565
566 pub fn and_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
570 self.and(Self::socket(socket))
571 }
572
573 pub fn or_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
577 self.or(Self::socket(socket))
578 }
579
580 pub fn get(path: impl AsRef<str>) -> Self {
582 Self::method_get().and_path(path)
583 }
584
585 pub fn custom<M>(matcher: M) -> Self
589 where
590 M: rama_core::matcher::Matcher<State, Request<Body>>,
591 {
592 Self {
593 kind: HttpMatcherKind::Custom(Arc::new(matcher)),
594 negate: false,
595 }
596 }
597
598 pub fn and_custom<M>(self, matcher: M) -> Self
602 where
603 M: rama_core::matcher::Matcher<State, Request<Body>>,
604 {
605 self.and(Self::custom(matcher))
606 }
607
608 pub fn or_custom<M>(self, matcher: M) -> Self
612 where
613 M: rama_core::matcher::Matcher<State, Request<Body>>,
614 {
615 self.or(Self::custom(matcher))
616 }
617
618 pub fn any_subdomain<I, S>(domains: I) -> Self
622 where
623 I: IntoIterator<Item = S>,
624 S: AsRef<str>,
625 {
626 HttpMatcher {
627 kind: HttpMatcherKind::SubdomainTrie(SubdomainTrieMatcher::new(domains)),
628 negate: false,
629 }
630 }
631
632 pub fn and_any_subdomain<I, S>(self, domains: I) -> Self
636 where
637 I: IntoIterator<Item = S>,
638 S: AsRef<str>,
639 {
640 self.and(Self::any_subdomain(domains))
641 }
642
643 pub fn or_any_subdomain<I, S>(self, domains: I) -> Self
647 where
648 I: IntoIterator<Item = S>,
649 S: AsRef<str>,
650 {
651 self.or(Self::any_subdomain(domains))
652 }
653
654 pub fn post(path: impl AsRef<str>) -> Self {
656 Self::method_post().and_path(path)
657 }
658
659 pub fn put(path: impl AsRef<str>) -> Self {
661 Self::method_put().and_path(path)
662 }
663
664 pub fn delete(path: impl AsRef<str>) -> Self {
666 Self::method_delete().and_path(path)
667 }
668
669 pub fn patch(path: impl AsRef<str>) -> Self {
671 Self::method_patch().and_path(path)
672 }
673
674 pub fn head(path: impl AsRef<str>) -> Self {
676 Self::method_head().and_path(path)
677 }
678
679 pub fn options(path: impl AsRef<str>) -> Self {
681 Self::method_options().and_path(path)
682 }
683
684 pub fn trace(path: impl AsRef<str>) -> Self {
686 Self::method_trace().and_path(path)
687 }
688
689 pub fn and(mut self, matcher: HttpMatcher<State, Body>) -> Self {
691 match (self.negate, &mut self.kind) {
692 (false, HttpMatcherKind::All(v)) => {
693 v.push(matcher);
694 self
695 }
696 _ => HttpMatcher {
697 kind: HttpMatcherKind::All(vec![self, matcher]),
698 negate: false,
699 },
700 }
701 }
702
703 pub fn or(mut self, matcher: HttpMatcher<State, Body>) -> Self {
705 match (self.negate, &mut self.kind) {
706 (false, HttpMatcherKind::Any(v)) => {
707 v.push(matcher);
708 self
709 }
710 _ => HttpMatcher {
711 kind: HttpMatcherKind::Any(vec![self, matcher]),
712 negate: false,
713 },
714 }
715 }
716
717 pub fn negate(self) -> Self {
719 Self {
720 kind: self.kind,
721 negate: true,
722 }
723 }
724}
725
726impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for HttpMatcher<State, Body>
727where
728 State: Clone + Send + Sync + 'static,
729 Body: Send + 'static,
730{
731 fn matches(
732 &self,
733 ext: Option<&mut Extensions>,
734 ctx: &Context<State>,
735 req: &Request<Body>,
736 ) -> bool {
737 let matches = self.kind.matches(ext, ctx, req);
738 if self.negate { !matches } else { matches }
739 }
740}
741
742impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for HttpMatcherKind<State, Body>
743where
744 State: Clone + Send + Sync + 'static,
745 Body: Send + 'static,
746{
747 fn matches(
748 &self,
749 ext: Option<&mut Extensions>,
750 ctx: &Context<State>,
751 req: &Request<Body>,
752 ) -> bool {
753 match self {
754 HttpMatcherKind::All(all) => all.iter().matches_and(ext, ctx, req),
755 HttpMatcherKind::Method(method) => method.matches(ext, ctx, req),
756 HttpMatcherKind::Path(path) => path.matches(ext, ctx, req),
757 HttpMatcherKind::Domain(domain) => domain.matches(ext, ctx, req),
758 HttpMatcherKind::Version(version) => version.matches(ext, ctx, req),
759 HttpMatcherKind::Uri(uri) => uri.matches(ext, ctx, req),
760 HttpMatcherKind::Header(header) => header.matches(ext, ctx, req),
761 HttpMatcherKind::Socket(socket) => socket.matches(ext, ctx, req),
762 HttpMatcherKind::Any(all) => all.iter().matches_or(ext, ctx, req),
763 HttpMatcherKind::SubdomainTrie(subdomain_trie) => subdomain_trie.matches(ext, ctx, req),
764 HttpMatcherKind::Custom(matcher) => matcher.matches(ext, ctx, req),
765 }
766 }
767}
768
769#[cfg(test)]
770mod test {
771 use itertools::Itertools;
772
773 use rama_core::matcher::Matcher;
774
775 use super::*;
776
777 struct BooleanMatcher(bool);
778
779 impl Matcher<(), Request<()>> for BooleanMatcher {
780 fn matches(
781 &self,
782 _ext: Option<&mut Extensions>,
783 _ctx: &Context<()>,
784 _req: &Request<()>,
785 ) -> bool {
786 self.0
787 }
788 }
789
790 #[test]
791 fn test_matcher_and_combination() {
792 for v in [true, false].into_iter().permutations(3) {
793 let expected = v[0] && v[1] && v[2];
794 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
795 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
796 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
797
798 let matcher = a.and(b).and(c);
799 let req = Request::builder().body(()).unwrap();
800 assert_eq!(
801 matcher.matches(None, &Context::default(), &req),
802 expected,
803 "({:#?}).matches({:#?})",
804 matcher,
805 req
806 );
807 }
808 }
809
810 #[test]
811 fn test_matcher_negation_with_and_combination() {
812 for v in [true, false].into_iter().permutations(3) {
813 let expected = !v[0] && v[1] && v[2];
814 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
815 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
816 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
817
818 let matcher = a.negate().and(b).and(c);
819 let req = Request::builder().body(()).unwrap();
820 assert_eq!(
821 matcher.matches(None, &Context::default(), &req),
822 expected,
823 "({:#?}).matches({:#?})",
824 matcher,
825 req
826 );
827 }
828 }
829
830 #[test]
831 fn test_matcher_and_combination_negated() {
832 for v in [true, false].into_iter().permutations(3) {
833 let expected = !(v[0] && v[1] && v[2]);
834 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
835 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
836 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
837
838 let matcher = a.and(b).and(c).negate();
839 let req = Request::builder().body(()).unwrap();
840 assert_eq!(
841 matcher.matches(None, &Context::default(), &req),
842 expected,
843 "({:#?}).matches({:#?})",
844 matcher,
845 req
846 );
847 }
848 }
849
850 #[test]
851 fn test_matcher_ors_combination() {
852 for v in [true, false].into_iter().permutations(3) {
853 let expected = v[0] || v[1] || v[2];
854 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
855 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
856 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
857
858 let matcher = a.or(b).or(c);
859 let req = Request::builder().body(()).unwrap();
860 assert_eq!(
861 matcher.matches(None, &Context::default(), &req),
862 expected,
863 "({:#?}).matches({:#?})",
864 matcher,
865 req
866 );
867 }
868 }
869
870 #[test]
871 fn test_matcher_negation_with_ors_combination() {
872 for v in [true, false].into_iter().permutations(3) {
873 let expected = !v[0] || v[1] || v[2];
874 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
875 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
876 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
877
878 let matcher = a.negate().or(b).or(c);
879 let req = Request::builder().body(()).unwrap();
880 assert_eq!(
881 matcher.matches(None, &Context::default(), &req),
882 expected,
883 "({:#?}).matches({:#?})",
884 matcher,
885 req
886 );
887 }
888 }
889
890 #[test]
891 fn test_matcher_ors_combination_negated() {
892 for v in [true, false].into_iter().permutations(3) {
893 let expected = !(v[0] || v[1] || v[2]);
894 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
895 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
896 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
897
898 let matcher = a.or(b).or(c).negate();
899 let req = Request::builder().body(()).unwrap();
900 assert_eq!(
901 matcher.matches(None, &Context::default(), &req),
902 expected,
903 "({:#?}).matches({:#?})",
904 matcher,
905 req
906 );
907 }
908 }
909
910 #[test]
911 fn test_matcher_or_and_or_and_negation() {
912 for v in [true, false].into_iter().permutations(5) {
913 let expected = (v[0] || v[1]) && (v[2] || v[3]) && !v[4];
914 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
915 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
916 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
917 let d = HttpMatcher::custom(BooleanMatcher(v[3]));
918 let e = HttpMatcher::custom(BooleanMatcher(v[4]));
919
920 let matcher = (a.or(b)).and(c.or(d)).and(e.negate());
921 let req = Request::builder().body(()).unwrap();
922 assert_eq!(
923 matcher.matches(None, &Context::default(), &req),
924 expected,
925 "({:#?}).matches({:#?})",
926 matcher,
927 req
928 );
929 }
930 }
931}