1use crate::Request;
9use rama_core::{context::Extensions, matcher::IteratorMatcherExt, Context};
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
37pub struct HttpMatcher<State, Body> {
39 kind: HttpMatcherKind<State, Body>,
40 negate: bool,
41}
42
43impl<State, Body> Clone for HttpMatcher<State, Body> {
44 fn clone(&self) -> Self {
45 Self {
46 kind: self.kind.clone(),
47 negate: self.negate,
48 }
49 }
50}
51
52impl<State, Body> fmt::Debug for HttpMatcher<State, Body> {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 f.debug_struct("HttpMatcher")
55 .field("kind", &self.kind)
56 .field("negate", &self.negate)
57 .finish()
58 }
59}
60
61pub enum HttpMatcherKind<State, Body> {
63 All(Vec<HttpMatcher<State, Body>>),
65 Method(MethodMatcher),
67 Path(PathMatcher),
69 Domain(DomainMatcher),
71 Version(VersionMatcher),
73 Any(Vec<HttpMatcher<State, Body>>),
75 Uri(UriMatcher),
77 Header(HeaderMatcher),
79 Socket(SocketMatcher<State, Request<Body>>),
83 Custom(Arc<dyn rama_core::matcher::Matcher<State, Request<Body>>>),
85}
86
87impl<State, Body> Clone for HttpMatcherKind<State, Body> {
88 fn clone(&self) -> Self {
89 match self {
90 Self::All(inner) => Self::All(inner.clone()),
91 Self::Method(inner) => Self::Method(*inner),
92 Self::Path(inner) => Self::Path(inner.clone()),
93 Self::Domain(inner) => Self::Domain(inner.clone()),
94 Self::Version(inner) => Self::Version(*inner),
95 Self::Any(inner) => Self::Any(inner.clone()),
96 Self::Uri(inner) => Self::Uri(inner.clone()),
97 Self::Header(inner) => Self::Header(inner.clone()),
98 Self::Socket(inner) => Self::Socket(inner.clone()),
99 Self::Custom(inner) => Self::Custom(inner.clone()),
100 }
101 }
102}
103
104impl<State, Body> fmt::Debug for HttpMatcherKind<State, Body> {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 match self {
107 Self::All(inner) => f.debug_tuple("All").field(inner).finish(),
108 Self::Method(inner) => f.debug_tuple("Method").field(inner).finish(),
109 Self::Path(inner) => f.debug_tuple("Path").field(inner).finish(),
110 Self::Domain(inner) => f.debug_tuple("Domain").field(inner).finish(),
111 Self::Version(inner) => f.debug_tuple("Version").field(inner).finish(),
112 Self::Any(inner) => f.debug_tuple("Any").field(inner).finish(),
113 Self::Uri(inner) => f.debug_tuple("Uri").field(inner).finish(),
114 Self::Header(inner) => f.debug_tuple("Header").field(inner).finish(),
115 Self::Socket(inner) => f.debug_tuple("Socket").field(inner).finish(),
116 Self::Custom(_) => f.debug_tuple("Custom").finish(),
117 }
118 }
119}
120
121impl<State, Body> HttpMatcher<State, Body> {
122 pub fn method(method: MethodMatcher) -> Self {
126 Self {
127 kind: HttpMatcherKind::Method(method),
128 negate: false,
129 }
130 }
131
132 pub fn and_method(self, method: MethodMatcher) -> Self {
136 self.and(Self::method(method))
137 }
138
139 pub fn or_method(self, method: MethodMatcher) -> Self {
143 self.or(Self::method(method))
144 }
145
146 pub fn method_delete() -> Self {
150 Self {
151 kind: HttpMatcherKind::Method(MethodMatcher::DELETE),
152 negate: false,
153 }
154 }
155
156 pub fn and_method_delete(self) -> Self {
160 self.and(Self::method_delete())
161 }
162
163 pub fn or_method_delete(self) -> Self {
168 self.or(Self::method_delete())
169 }
170
171 pub fn method_get() -> Self {
175 Self {
176 kind: HttpMatcherKind::Method(MethodMatcher::GET),
177 negate: false,
178 }
179 }
180
181 pub fn and_method_get(self) -> Self {
185 self.and(Self::method_get())
186 }
187
188 pub fn or_method_get(self) -> Self {
193 self.or(Self::method_get())
194 }
195
196 pub fn method_head() -> Self {
200 Self {
201 kind: HttpMatcherKind::Method(MethodMatcher::HEAD),
202 negate: false,
203 }
204 }
205
206 pub fn and_method_head(self) -> Self {
210 self.and(Self::method_head())
211 }
212
213 pub fn or_method_head(self) -> Self {
218 self.or(Self::method_head())
219 }
220
221 pub fn method_options() -> Self {
225 Self {
226 kind: HttpMatcherKind::Method(MethodMatcher::OPTIONS),
227 negate: false,
228 }
229 }
230
231 pub fn and_method_options(self) -> Self {
235 self.and(Self::method_options())
236 }
237
238 pub fn or_method_options(self) -> Self {
243 self.or(Self::method_options())
244 }
245
246 pub fn method_patch() -> Self {
250 Self {
251 kind: HttpMatcherKind::Method(MethodMatcher::PATCH),
252 negate: false,
253 }
254 }
255
256 pub fn and_method_patch(self) -> Self {
260 self.and(Self::method_patch())
261 }
262
263 pub fn or_method_patch(self) -> Self {
268 self.or(Self::method_patch())
269 }
270
271 pub fn method_post() -> Self {
275 Self {
276 kind: HttpMatcherKind::Method(MethodMatcher::POST),
277 negate: false,
278 }
279 }
280
281 pub fn and_method_post(self) -> Self {
285 self.and(Self::method_post())
286 }
287
288 pub fn or_method_post(self) -> Self {
293 self.or(Self::method_post())
294 }
295
296 pub fn method_put() -> Self {
300 Self {
301 kind: HttpMatcherKind::Method(MethodMatcher::PUT),
302 negate: false,
303 }
304 }
305
306 pub fn and_method_put(self) -> Self {
310 self.and(Self::method_put())
311 }
312
313 pub fn or_method_put(self) -> Self {
318 self.or(Self::method_put())
319 }
320
321 pub fn method_trace() -> Self {
325 Self {
326 kind: HttpMatcherKind::Method(MethodMatcher::TRACE),
327 negate: false,
328 }
329 }
330
331 pub fn and_method_trace(self) -> Self {
335 self.and(Self::method_trace())
336 }
337
338 pub fn or_method_trace(self) -> Self {
343 self.or(Self::method_trace())
344 }
345
346 pub fn domain(domain: Domain) -> Self {
348 Self {
349 kind: HttpMatcherKind::Domain(DomainMatcher::exact(domain)),
350 negate: false,
351 }
352 }
353
354 pub fn subdomain(domain: Domain) -> Self {
357 Self {
358 kind: HttpMatcherKind::Domain(DomainMatcher::sub(domain)),
359 negate: false,
360 }
361 }
362
363 pub fn and_domain(self, domain: Domain) -> Self {
367 self.and(Self::domain(domain))
368 }
369
370 pub fn and_subdomain(self, domain: Domain) -> Self {
374 self.and(Self::subdomain(domain))
375 }
376
377 pub fn or_domain(self, domain: Domain) -> Self {
381 self.or(Self::domain(domain))
382 }
383
384 pub fn or_subdomain(self, domain: Domain) -> Self {
388 self.or(Self::subdomain(domain))
389 }
390
391 pub fn version(version: VersionMatcher) -> Self {
393 Self {
394 kind: HttpMatcherKind::Version(version),
395 negate: false,
396 }
397 }
398
399 pub fn and_version(self, version: VersionMatcher) -> Self {
403 self.and(Self::version(version))
404 }
405
406 pub fn or_version(self, version: VersionMatcher) -> Self {
410 self.or(Self::version(version))
411 }
412
413 pub fn uri(re: impl AsRef<str>) -> Self {
415 Self {
416 kind: HttpMatcherKind::Uri(UriMatcher::new(re)),
417 negate: false,
418 }
419 }
420
421 pub fn and_uri(self, re: impl AsRef<str>) -> Self {
425 self.and(Self::uri(re))
426 }
427
428 pub fn or_uri(self, re: impl AsRef<str>) -> Self {
432 self.or(Self::uri(re))
433 }
434
435 pub fn path(path: impl AsRef<str>) -> Self {
437 Self {
438 kind: HttpMatcherKind::Path(PathMatcher::new(path)),
439 negate: false,
440 }
441 }
442
443 pub fn and_path(self, path: impl AsRef<str>) -> Self {
447 self.and(Self::path(path))
448 }
449
450 pub fn or_path(self, path: impl AsRef<str>) -> Self {
454 self.or(Self::path(path))
455 }
456
457 pub fn header(name: http::header::HeaderName, value: http::header::HeaderValue) -> Self {
459 Self {
460 kind: HttpMatcherKind::Header(HeaderMatcher::is(name, value)),
461 negate: false,
462 }
463 }
464
465 pub fn and_header(
469 self,
470 name: http::header::HeaderName,
471 value: http::header::HeaderValue,
472 ) -> Self {
473 self.and(Self::header(name, value))
474 }
475
476 pub fn or_header(
480 self,
481 name: http::header::HeaderName,
482 value: http::header::HeaderValue,
483 ) -> Self {
484 self.or(Self::header(name, value))
485 }
486
487 pub fn header_exists(name: http::header::HeaderName) -> Self {
490 Self {
491 kind: HttpMatcherKind::Header(HeaderMatcher::exists(name)),
492 negate: false,
493 }
494 }
495
496 pub fn and_header_exists(self, name: http::header::HeaderName) -> Self {
501 self.and(Self::header_exists(name))
502 }
503
504 pub fn or_header_exists(self, name: http::header::HeaderName) -> Self {
509 self.or(Self::header_exists(name))
510 }
511
512 pub fn header_contains(
514 name: http::header::HeaderName,
515 value: http::header::HeaderValue,
516 ) -> Self {
517 Self {
518 kind: HttpMatcherKind::Header(HeaderMatcher::contains(name, value)),
519 negate: false,
520 }
521 }
522
523 pub fn and_header_contains(
528 self,
529 name: http::header::HeaderName,
530 value: http::header::HeaderValue,
531 ) -> Self {
532 self.and(Self::header_contains(name, value))
533 }
534
535 pub fn or_header_contains(
540 self,
541 name: http::header::HeaderName,
542 value: http::header::HeaderValue,
543 ) -> Self {
544 self.or(Self::header_contains(name, value))
545 }
546
547 pub fn socket(socket: SocketMatcher<State, Request<Body>>) -> Self {
549 Self {
550 kind: HttpMatcherKind::Socket(socket),
551 negate: false,
552 }
553 }
554
555 pub fn and_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
559 self.and(Self::socket(socket))
560 }
561
562 pub fn or_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
566 self.or(Self::socket(socket))
567 }
568
569 pub fn get(path: impl AsRef<str>) -> Self {
571 Self::method_get().and_path(path)
572 }
573
574 pub fn custom<M>(matcher: M) -> Self
578 where
579 M: rama_core::matcher::Matcher<State, Request<Body>>,
580 {
581 Self {
582 kind: HttpMatcherKind::Custom(Arc::new(matcher)),
583 negate: false,
584 }
585 }
586
587 pub fn and_custom<M>(self, matcher: M) -> Self
591 where
592 M: rama_core::matcher::Matcher<State, Request<Body>>,
593 {
594 self.and(Self::custom(matcher))
595 }
596
597 pub fn or_custom<M>(self, matcher: M) -> Self
601 where
602 M: rama_core::matcher::Matcher<State, Request<Body>>,
603 {
604 self.or(Self::custom(matcher))
605 }
606
607 pub fn post(path: impl AsRef<str>) -> Self {
609 Self::method_post().and_path(path)
610 }
611
612 pub fn put(path: impl AsRef<str>) -> Self {
614 Self::method_put().and_path(path)
615 }
616
617 pub fn delete(path: impl AsRef<str>) -> Self {
619 Self::method_delete().and_path(path)
620 }
621
622 pub fn patch(path: impl AsRef<str>) -> Self {
624 Self::method_patch().and_path(path)
625 }
626
627 pub fn head(path: impl AsRef<str>) -> Self {
629 Self::method_head().and_path(path)
630 }
631
632 pub fn options(path: impl AsRef<str>) -> Self {
634 Self::method_options().and_path(path)
635 }
636
637 pub fn trace(path: impl AsRef<str>) -> Self {
639 Self::method_trace().and_path(path)
640 }
641
642 pub fn and(mut self, matcher: HttpMatcher<State, Body>) -> Self {
644 match (self.negate, &mut self.kind) {
645 (false, HttpMatcherKind::All(v)) => {
646 v.push(matcher);
647 self
648 }
649 _ => HttpMatcher {
650 kind: HttpMatcherKind::All(vec![self, matcher]),
651 negate: false,
652 },
653 }
654 }
655
656 pub fn or(mut self, matcher: HttpMatcher<State, Body>) -> Self {
658 match (self.negate, &mut self.kind) {
659 (false, HttpMatcherKind::Any(v)) => {
660 v.push(matcher);
661 self
662 }
663 _ => HttpMatcher {
664 kind: HttpMatcherKind::Any(vec![self, matcher]),
665 negate: false,
666 },
667 }
668 }
669
670 pub fn negate(self) -> Self {
672 Self {
673 kind: self.kind,
674 negate: true,
675 }
676 }
677}
678
679impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for HttpMatcher<State, Body>
680where
681 State: Clone + Send + Sync + 'static,
682 Body: Send + 'static,
683{
684 fn matches(
685 &self,
686 ext: Option<&mut Extensions>,
687 ctx: &Context<State>,
688 req: &Request<Body>,
689 ) -> bool {
690 let matches = self.kind.matches(ext, ctx, req);
691 if self.negate {
692 !matches
693 } else {
694 matches
695 }
696 }
697}
698
699impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for HttpMatcherKind<State, Body>
700where
701 State: Clone + Send + Sync + 'static,
702 Body: Send + 'static,
703{
704 fn matches(
705 &self,
706 ext: Option<&mut Extensions>,
707 ctx: &Context<State>,
708 req: &Request<Body>,
709 ) -> bool {
710 match self {
711 HttpMatcherKind::All(all) => all.iter().matches_and(ext, ctx, req),
712 HttpMatcherKind::Method(method) => method.matches(ext, ctx, req),
713 HttpMatcherKind::Path(path) => path.matches(ext, ctx, req),
714 HttpMatcherKind::Domain(domain) => domain.matches(ext, ctx, req),
715 HttpMatcherKind::Version(version) => version.matches(ext, ctx, req),
716 HttpMatcherKind::Uri(uri) => uri.matches(ext, ctx, req),
717 HttpMatcherKind::Header(header) => header.matches(ext, ctx, req),
718 HttpMatcherKind::Socket(socket) => socket.matches(ext, ctx, req),
719 HttpMatcherKind::Any(all) => all.iter().matches_or(ext, ctx, req),
720 HttpMatcherKind::Custom(matcher) => matcher.matches(ext, ctx, req),
721 }
722 }
723}
724
725#[cfg(test)]
726mod test {
727 use itertools::Itertools;
728
729 use rama_core::matcher::Matcher;
730
731 use super::*;
732
733 struct BooleanMatcher(bool);
734
735 impl Matcher<(), Request<()>> for BooleanMatcher {
736 fn matches(
737 &self,
738 _ext: Option<&mut Extensions>,
739 _ctx: &Context<()>,
740 _req: &Request<()>,
741 ) -> bool {
742 self.0
743 }
744 }
745
746 #[test]
747 fn test_matcher_and_combination() {
748 for v in [true, false].into_iter().permutations(3) {
749 let expected = v[0] && v[1] && v[2];
750 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
751 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
752 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
753
754 let matcher = a.and(b).and(c);
755 let req = Request::builder().body(()).unwrap();
756 assert_eq!(
757 matcher.matches(None, &Context::default(), &req),
758 expected,
759 "({:#?}).matches({:#?})",
760 matcher,
761 req
762 );
763 }
764 }
765
766 #[test]
767 fn test_matcher_negation_with_and_combination() {
768 for v in [true, false].into_iter().permutations(3) {
769 let expected = !v[0] && v[1] && v[2];
770 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
771 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
772 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
773
774 let matcher = a.negate().and(b).and(c);
775 let req = Request::builder().body(()).unwrap();
776 assert_eq!(
777 matcher.matches(None, &Context::default(), &req),
778 expected,
779 "({:#?}).matches({:#?})",
780 matcher,
781 req
782 );
783 }
784 }
785
786 #[test]
787 fn test_matcher_and_combination_negated() {
788 for v in [true, false].into_iter().permutations(3) {
789 let expected = !(v[0] && v[1] && v[2]);
790 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
791 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
792 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
793
794 let matcher = a.and(b).and(c).negate();
795 let req = Request::builder().body(()).unwrap();
796 assert_eq!(
797 matcher.matches(None, &Context::default(), &req),
798 expected,
799 "({:#?}).matches({:#?})",
800 matcher,
801 req
802 );
803 }
804 }
805
806 #[test]
807 fn test_matcher_ors_combination() {
808 for v in [true, false].into_iter().permutations(3) {
809 let expected = v[0] || v[1] || v[2];
810 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
811 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
812 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
813
814 let matcher = a.or(b).or(c);
815 let req = Request::builder().body(()).unwrap();
816 assert_eq!(
817 matcher.matches(None, &Context::default(), &req),
818 expected,
819 "({:#?}).matches({:#?})",
820 matcher,
821 req
822 );
823 }
824 }
825
826 #[test]
827 fn test_matcher_negation_with_ors_combination() {
828 for v in [true, false].into_iter().permutations(3) {
829 let expected = !v[0] || v[1] || v[2];
830 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
831 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
832 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
833
834 let matcher = a.negate().or(b).or(c);
835 let req = Request::builder().body(()).unwrap();
836 assert_eq!(
837 matcher.matches(None, &Context::default(), &req),
838 expected,
839 "({:#?}).matches({:#?})",
840 matcher,
841 req
842 );
843 }
844 }
845
846 #[test]
847 fn test_matcher_ors_combination_negated() {
848 for v in [true, false].into_iter().permutations(3) {
849 let expected = !(v[0] || v[1] || v[2]);
850 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
851 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
852 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
853
854 let matcher = a.or(b).or(c).negate();
855 let req = Request::builder().body(()).unwrap();
856 assert_eq!(
857 matcher.matches(None, &Context::default(), &req),
858 expected,
859 "({:#?}).matches({:#?})",
860 matcher,
861 req
862 );
863 }
864 }
865
866 #[test]
867 fn test_matcher_or_and_or_and_negation() {
868 for v in [true, false].into_iter().permutations(5) {
869 let expected = (v[0] || v[1]) && (v[2] || v[3]) && !v[4];
870 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
871 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
872 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
873 let d = HttpMatcher::custom(BooleanMatcher(v[3]));
874 let e = HttpMatcher::custom(BooleanMatcher(v[4]));
875
876 let matcher = (a.or(b)).and(c.or(d)).and(e.negate());
877 let req = Request::builder().body(()).unwrap();
878 assert_eq!(
879 matcher.matches(None, &Context::default(), &req),
880 expected,
881 "({:#?}).matches({:#?})",
882 matcher,
883 req
884 );
885 }
886 }
887}