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
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(
459 name: rama_http_types::header::HeaderName,
460 value: rama_http_types::header::HeaderValue,
461 ) -> Self {
462 Self {
463 kind: HttpMatcherKind::Header(HeaderMatcher::is(name, value)),
464 negate: false,
465 }
466 }
467
468 pub fn and_header(
472 self,
473 name: rama_http_types::header::HeaderName,
474 value: rama_http_types::header::HeaderValue,
475 ) -> Self {
476 self.and(Self::header(name, value))
477 }
478
479 pub fn or_header(
483 self,
484 name: rama_http_types::header::HeaderName,
485 value: rama_http_types::header::HeaderValue,
486 ) -> Self {
487 self.or(Self::header(name, value))
488 }
489
490 pub fn header_exists(name: rama_http_types::header::HeaderName) -> Self {
493 Self {
494 kind: HttpMatcherKind::Header(HeaderMatcher::exists(name)),
495 negate: false,
496 }
497 }
498
499 pub fn and_header_exists(self, name: rama_http_types::header::HeaderName) -> Self {
504 self.and(Self::header_exists(name))
505 }
506
507 pub fn or_header_exists(self, name: rama_http_types::header::HeaderName) -> Self {
512 self.or(Self::header_exists(name))
513 }
514
515 pub fn header_contains(
517 name: rama_http_types::header::HeaderName,
518 value: rama_http_types::header::HeaderValue,
519 ) -> Self {
520 Self {
521 kind: HttpMatcherKind::Header(HeaderMatcher::contains(name, value)),
522 negate: false,
523 }
524 }
525
526 pub fn and_header_contains(
531 self,
532 name: rama_http_types::header::HeaderName,
533 value: rama_http_types::header::HeaderValue,
534 ) -> Self {
535 self.and(Self::header_contains(name, value))
536 }
537
538 pub fn or_header_contains(
543 self,
544 name: rama_http_types::header::HeaderName,
545 value: rama_http_types::header::HeaderValue,
546 ) -> Self {
547 self.or(Self::header_contains(name, value))
548 }
549
550 pub fn socket(socket: SocketMatcher<State, Request<Body>>) -> Self {
552 Self {
553 kind: HttpMatcherKind::Socket(socket),
554 negate: false,
555 }
556 }
557
558 pub fn and_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
562 self.and(Self::socket(socket))
563 }
564
565 pub fn or_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
569 self.or(Self::socket(socket))
570 }
571
572 pub fn get(path: impl AsRef<str>) -> Self {
574 Self::method_get().and_path(path)
575 }
576
577 pub fn custom<M>(matcher: M) -> Self
581 where
582 M: rama_core::matcher::Matcher<State, Request<Body>>,
583 {
584 Self {
585 kind: HttpMatcherKind::Custom(Arc::new(matcher)),
586 negate: false,
587 }
588 }
589
590 pub fn and_custom<M>(self, matcher: M) -> Self
594 where
595 M: rama_core::matcher::Matcher<State, Request<Body>>,
596 {
597 self.and(Self::custom(matcher))
598 }
599
600 pub fn or_custom<M>(self, matcher: M) -> Self
604 where
605 M: rama_core::matcher::Matcher<State, Request<Body>>,
606 {
607 self.or(Self::custom(matcher))
608 }
609
610 pub fn post(path: impl AsRef<str>) -> Self {
612 Self::method_post().and_path(path)
613 }
614
615 pub fn put(path: impl AsRef<str>) -> Self {
617 Self::method_put().and_path(path)
618 }
619
620 pub fn delete(path: impl AsRef<str>) -> Self {
622 Self::method_delete().and_path(path)
623 }
624
625 pub fn patch(path: impl AsRef<str>) -> Self {
627 Self::method_patch().and_path(path)
628 }
629
630 pub fn head(path: impl AsRef<str>) -> Self {
632 Self::method_head().and_path(path)
633 }
634
635 pub fn options(path: impl AsRef<str>) -> Self {
637 Self::method_options().and_path(path)
638 }
639
640 pub fn trace(path: impl AsRef<str>) -> Self {
642 Self::method_trace().and_path(path)
643 }
644
645 pub fn and(mut self, matcher: HttpMatcher<State, Body>) -> Self {
647 match (self.negate, &mut self.kind) {
648 (false, HttpMatcherKind::All(v)) => {
649 v.push(matcher);
650 self
651 }
652 _ => HttpMatcher {
653 kind: HttpMatcherKind::All(vec![self, matcher]),
654 negate: false,
655 },
656 }
657 }
658
659 pub fn or(mut self, matcher: HttpMatcher<State, Body>) -> Self {
661 match (self.negate, &mut self.kind) {
662 (false, HttpMatcherKind::Any(v)) => {
663 v.push(matcher);
664 self
665 }
666 _ => HttpMatcher {
667 kind: HttpMatcherKind::Any(vec![self, matcher]),
668 negate: false,
669 },
670 }
671 }
672
673 pub fn negate(self) -> Self {
675 Self {
676 kind: self.kind,
677 negate: true,
678 }
679 }
680}
681
682impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for HttpMatcher<State, Body>
683where
684 State: Clone + Send + Sync + 'static,
685 Body: Send + 'static,
686{
687 fn matches(
688 &self,
689 ext: Option<&mut Extensions>,
690 ctx: &Context<State>,
691 req: &Request<Body>,
692 ) -> bool {
693 let matches = self.kind.matches(ext, ctx, req);
694 if self.negate { !matches } else { matches }
695 }
696}
697
698impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for HttpMatcherKind<State, Body>
699where
700 State: Clone + Send + Sync + 'static,
701 Body: Send + 'static,
702{
703 fn matches(
704 &self,
705 ext: Option<&mut Extensions>,
706 ctx: &Context<State>,
707 req: &Request<Body>,
708 ) -> bool {
709 match self {
710 HttpMatcherKind::All(all) => all.iter().matches_and(ext, ctx, req),
711 HttpMatcherKind::Method(method) => method.matches(ext, ctx, req),
712 HttpMatcherKind::Path(path) => path.matches(ext, ctx, req),
713 HttpMatcherKind::Domain(domain) => domain.matches(ext, ctx, req),
714 HttpMatcherKind::Version(version) => version.matches(ext, ctx, req),
715 HttpMatcherKind::Uri(uri) => uri.matches(ext, ctx, req),
716 HttpMatcherKind::Header(header) => header.matches(ext, ctx, req),
717 HttpMatcherKind::Socket(socket) => socket.matches(ext, ctx, req),
718 HttpMatcherKind::Any(all) => all.iter().matches_or(ext, ctx, req),
719 HttpMatcherKind::Custom(matcher) => matcher.matches(ext, ctx, req),
720 }
721 }
722}
723
724#[cfg(test)]
725mod test {
726 use itertools::Itertools;
727
728 use rama_core::matcher::Matcher;
729
730 use super::*;
731
732 struct BooleanMatcher(bool);
733
734 impl Matcher<(), Request<()>> for BooleanMatcher {
735 fn matches(
736 &self,
737 _ext: Option<&mut Extensions>,
738 _ctx: &Context<()>,
739 _req: &Request<()>,
740 ) -> bool {
741 self.0
742 }
743 }
744
745 #[test]
746 fn test_matcher_and_combination() {
747 for v in [true, false].into_iter().permutations(3) {
748 let expected = v[0] && v[1] && v[2];
749 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
750 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
751 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
752
753 let matcher = a.and(b).and(c);
754 let req = Request::builder().body(()).unwrap();
755 assert_eq!(
756 matcher.matches(None, &Context::default(), &req),
757 expected,
758 "({:#?}).matches({:#?})",
759 matcher,
760 req
761 );
762 }
763 }
764
765 #[test]
766 fn test_matcher_negation_with_and_combination() {
767 for v in [true, false].into_iter().permutations(3) {
768 let expected = !v[0] && v[1] && v[2];
769 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
770 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
771 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
772
773 let matcher = a.negate().and(b).and(c);
774 let req = Request::builder().body(()).unwrap();
775 assert_eq!(
776 matcher.matches(None, &Context::default(), &req),
777 expected,
778 "({:#?}).matches({:#?})",
779 matcher,
780 req
781 );
782 }
783 }
784
785 #[test]
786 fn test_matcher_and_combination_negated() {
787 for v in [true, false].into_iter().permutations(3) {
788 let expected = !(v[0] && v[1] && v[2]);
789 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
790 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
791 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
792
793 let matcher = a.and(b).and(c).negate();
794 let req = Request::builder().body(()).unwrap();
795 assert_eq!(
796 matcher.matches(None, &Context::default(), &req),
797 expected,
798 "({:#?}).matches({:#?})",
799 matcher,
800 req
801 );
802 }
803 }
804
805 #[test]
806 fn test_matcher_ors_combination() {
807 for v in [true, false].into_iter().permutations(3) {
808 let expected = v[0] || v[1] || v[2];
809 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
810 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
811 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
812
813 let matcher = a.or(b).or(c);
814 let req = Request::builder().body(()).unwrap();
815 assert_eq!(
816 matcher.matches(None, &Context::default(), &req),
817 expected,
818 "({:#?}).matches({:#?})",
819 matcher,
820 req
821 );
822 }
823 }
824
825 #[test]
826 fn test_matcher_negation_with_ors_combination() {
827 for v in [true, false].into_iter().permutations(3) {
828 let expected = !v[0] || v[1] || v[2];
829 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
830 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
831 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
832
833 let matcher = a.negate().or(b).or(c);
834 let req = Request::builder().body(()).unwrap();
835 assert_eq!(
836 matcher.matches(None, &Context::default(), &req),
837 expected,
838 "({:#?}).matches({:#?})",
839 matcher,
840 req
841 );
842 }
843 }
844
845 #[test]
846 fn test_matcher_ors_combination_negated() {
847 for v in [true, false].into_iter().permutations(3) {
848 let expected = !(v[0] || v[1] || v[2]);
849 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
850 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
851 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
852
853 let matcher = a.or(b).or(c).negate();
854 let req = Request::builder().body(()).unwrap();
855 assert_eq!(
856 matcher.matches(None, &Context::default(), &req),
857 expected,
858 "({:#?}).matches({:#?})",
859 matcher,
860 req
861 );
862 }
863 }
864
865 #[test]
866 fn test_matcher_or_and_or_and_negation() {
867 for v in [true, false].into_iter().permutations(5) {
868 let expected = (v[0] || v[1]) && (v[2] || v[3]) && !v[4];
869 let a = HttpMatcher::custom(BooleanMatcher(v[0]));
870 let b = HttpMatcher::custom(BooleanMatcher(v[1]));
871 let c = HttpMatcher::custom(BooleanMatcher(v[2]));
872 let d = HttpMatcher::custom(BooleanMatcher(v[3]));
873 let e = HttpMatcher::custom(BooleanMatcher(v[4]));
874
875 let matcher = (a.or(b)).and(c.or(d)).and(e.negate());
876 let req = Request::builder().body(()).unwrap();
877 assert_eq!(
878 matcher.matches(None, &Context::default(), &req),
879 expected,
880 "({:#?}).matches({:#?})",
881 matcher,
882 req
883 );
884 }
885 }
886}