rama_http/matcher/
mod.rs

1//! [`service::Matcher`]s implementations to match on [`http::Request`]s.
2//!
3//! See [`service::matcher` module] for more information.
4//!
5//! [`service::Matcher`]: rama_core::matcher::Matcher
6//! [`http::Request`]: crate::Request
7//! [`service::matcher` module]: rama_core
8use 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
37/// A matcher that is used to match an http [`Request`]
38pub 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
61/// A matcher that is used to match an http [`Request`]
62pub enum HttpMatcherKind<State, Body> {
63    /// zero or more [`HttpMatcher`]s that all need to match in order for the matcher to return `true`.
64    All(Vec<HttpMatcher<State, Body>>),
65    /// [`MethodMatcher`], a matcher that matches one or more HTTP methods.
66    Method(MethodMatcher),
67    /// [`PathMatcher`], a matcher based on the URI path.
68    Path(PathMatcher),
69    /// [`DomainMatcher`], a matcher based on the (sub)domain of the request's URI.
70    Domain(DomainMatcher),
71    /// [`VersionMatcher`], a matcher based on the HTTP version of the request.
72    Version(VersionMatcher),
73    /// zero or more [`HttpMatcher`]s that at least one needs to match in order for the matcher to return `true`.
74    Any(Vec<HttpMatcher<State, Body>>),
75    /// [`UriMatcher`], a matcher the request's URI, using a substring or regex pattern.
76    Uri(UriMatcher),
77    /// [`HeaderMatcher`], a matcher based on the [`Request`]'s headers.
78    Header(HeaderMatcher),
79    /// [`SocketMatcher`], a matcher that matches on the [`SocketAddr`] of the peer.
80    ///
81    /// [`SocketAddr`]: std::net::SocketAddr
82    Socket(SocketMatcher<State, Request<Body>>),
83    /// A custom matcher that implements [`rama_core::matcher::Matcher`].
84    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    /// Create a new matcher that matches one or more HTTP methods.
123    ///
124    /// See [`MethodMatcher`] for more information.
125    pub fn method(method: MethodMatcher) -> Self {
126        Self {
127            kind: HttpMatcherKind::Method(method),
128            negate: false,
129        }
130    }
131
132    /// Create a matcher that also matches one or more HTTP methods on top of the existing [`HttpMatcher`] matchers.
133    ///
134    /// See [`MethodMatcher`] for more information.
135    pub fn and_method(self, method: MethodMatcher) -> Self {
136        self.and(Self::method(method))
137    }
138
139    /// Create a matcher that can also match one or more HTTP methods as an alternative to the existing [`HttpMatcher`] matchers.
140    ///
141    /// See [`MethodMatcher`] for more information.
142    pub fn or_method(self, method: MethodMatcher) -> Self {
143        self.or(Self::method(method))
144    }
145
146    /// Create a new matcher that matches [`MethodMatcher::DELETE`] requests.
147    ///
148    /// See [`MethodMatcher`] for more information.
149    pub fn method_delete() -> Self {
150        Self {
151            kind: HttpMatcherKind::Method(MethodMatcher::DELETE),
152            negate: false,
153        }
154    }
155
156    /// Add a new matcher that also matches [`MethodMatcher::DELETE`] on top of the existing [`HttpMatcher`] matchers.
157    ///
158    /// See [`MethodMatcher`] for more information.
159    pub fn and_method_delete(self) -> Self {
160        self.and(Self::method_delete())
161    }
162
163    /// Add a new matcher that can also match [`MethodMatcher::DELETE`]
164    /// as an alternative tothe existing [`HttpMatcher`] matchers.
165    ///
166    /// See [`MethodMatcher`] for more information.
167    pub fn or_method_delete(self) -> Self {
168        self.or(Self::method_delete())
169    }
170
171    /// Create a new matcher that matches [`MethodMatcher::GET`] requests.
172    ///
173    /// See [`MethodMatcher`] for more information.
174    pub fn method_get() -> Self {
175        Self {
176            kind: HttpMatcherKind::Method(MethodMatcher::GET),
177            negate: false,
178        }
179    }
180
181    /// Add a new matcher that also matches [`MethodMatcher::GET`] on top of the existing [`HttpMatcher`] matchers.
182    ///
183    /// See [`MethodMatcher`] for more information.
184    pub fn and_method_get(self) -> Self {
185        self.and(Self::method_get())
186    }
187
188    /// Add a new matcher that can also match [`MethodMatcher::GET`]
189    /// as an alternative tothe existing [`HttpMatcher`] matchers.
190    ///
191    /// See [`MethodMatcher`] for more information.
192    pub fn or_method_get(self) -> Self {
193        self.or(Self::method_get())
194    }
195
196    /// Create a new matcher that matches [`MethodMatcher::HEAD`] requests.
197    ///
198    /// See [`MethodMatcher`] for more information.
199    pub fn method_head() -> Self {
200        Self {
201            kind: HttpMatcherKind::Method(MethodMatcher::HEAD),
202            negate: false,
203        }
204    }
205
206    /// Add a new matcher that also matches [`MethodMatcher::HEAD`] on top of the existing [`HttpMatcher`] matchers.
207    ///
208    /// See [`MethodMatcher`] for more information.
209    pub fn and_method_head(self) -> Self {
210        self.and(Self::method_head())
211    }
212
213    /// Add a new matcher that can also match [`MethodMatcher::HEAD`]
214    /// as an alternative tothe existing [`HttpMatcher`] matchers.
215    ///
216    /// See [`MethodMatcher`] for more information.
217    pub fn or_method_head(self) -> Self {
218        self.or(Self::method_head())
219    }
220
221    /// Create a new matcher that matches [`MethodMatcher::OPTIONS`] requests.
222    ///
223    /// See [`MethodMatcher`] for more information.
224    pub fn method_options() -> Self {
225        Self {
226            kind: HttpMatcherKind::Method(MethodMatcher::OPTIONS),
227            negate: false,
228        }
229    }
230
231    /// Add a new matcher that also matches [`MethodMatcher::OPTIONS`] on top of the existing [`HttpMatcher`] matchers.
232    ///
233    /// See [`MethodMatcher`] for more information.
234    pub fn and_method_options(self) -> Self {
235        self.and(Self::method_options())
236    }
237
238    /// Add a new matcher that can also match [`MethodMatcher::OPTIONS`]
239    /// as an alternative tothe existing [`HttpMatcher`] matchers.
240    ///
241    /// See [`MethodMatcher`] for more information.
242    pub fn or_method_options(self) -> Self {
243        self.or(Self::method_options())
244    }
245
246    /// Create a new matcher that matches [`MethodMatcher::PATCH`] requests.
247    ///
248    /// See [`MethodMatcher`] for more information.
249    pub fn method_patch() -> Self {
250        Self {
251            kind: HttpMatcherKind::Method(MethodMatcher::PATCH),
252            negate: false,
253        }
254    }
255
256    /// Add a new matcher that also matches [`MethodMatcher::PATCH`] on top of the existing [`HttpMatcher`] matchers.
257    ///
258    /// See [`MethodMatcher`] for more information.
259    pub fn and_method_patch(self) -> Self {
260        self.and(Self::method_patch())
261    }
262
263    /// Add a new matcher that can also match [`MethodMatcher::PATCH`]
264    /// as an alternative tothe existing [`HttpMatcher`] matchers.
265    ///
266    /// See [`MethodMatcher`] for more information.
267    pub fn or_method_patch(self) -> Self {
268        self.or(Self::method_patch())
269    }
270
271    /// Create a new matcher that matches [`MethodMatcher::POST`] requests.
272    ///
273    /// See [`MethodMatcher`] for more information.
274    pub fn method_post() -> Self {
275        Self {
276            kind: HttpMatcherKind::Method(MethodMatcher::POST),
277            negate: false,
278        }
279    }
280
281    /// Add a new matcher that also matches [`MethodMatcher::POST`] on top of the existing [`HttpMatcher`] matchers.
282    ///
283    /// See [`MethodMatcher`] for more information.
284    pub fn and_method_post(self) -> Self {
285        self.and(Self::method_post())
286    }
287
288    /// Add a new matcher that can also match [`MethodMatcher::POST`]
289    /// as an alternative tothe existing [`HttpMatcher`] matchers.
290    ///
291    /// See [`MethodMatcher`] for more information.
292    pub fn or_method_post(self) -> Self {
293        self.or(Self::method_post())
294    }
295
296    /// Create a new matcher that matches [`MethodMatcher::PUT`] requests.
297    ///
298    /// See [`MethodMatcher`] for more information.
299    pub fn method_put() -> Self {
300        Self {
301            kind: HttpMatcherKind::Method(MethodMatcher::PUT),
302            negate: false,
303        }
304    }
305
306    /// Add a new matcher that also matches [`MethodMatcher::PUT`] on top of the existing [`HttpMatcher`] matchers.
307    ///
308    /// See [`MethodMatcher`] for more information.
309    pub fn and_method_put(self) -> Self {
310        self.and(Self::method_put())
311    }
312
313    /// Add a new matcher that can also match [`MethodMatcher::PUT`]
314    /// as an alternative tothe existing [`HttpMatcher`] matchers.
315    ///
316    /// See [`MethodMatcher`] for more information.
317    pub fn or_method_put(self) -> Self {
318        self.or(Self::method_put())
319    }
320
321    /// Create a new matcher that matches [`MethodMatcher::TRACE`] requests.
322    ///
323    /// See [`MethodMatcher`] for more information.
324    pub fn method_trace() -> Self {
325        Self {
326            kind: HttpMatcherKind::Method(MethodMatcher::TRACE),
327            negate: false,
328        }
329    }
330
331    /// Add a new matcher that also matches [`MethodMatcher::TRACE`] on top of the existing [`HttpMatcher`] matchers.
332    ///
333    /// See [`MethodMatcher`] for more information.
334    pub fn and_method_trace(self) -> Self {
335        self.and(Self::method_trace())
336    }
337
338    /// Add a new matcher that can also match [`MethodMatcher::TRACE`]
339    /// as an alternative tothe existing [`HttpMatcher`] matchers.
340    ///
341    /// See [`MethodMatcher`] for more information.
342    pub fn or_method_trace(self) -> Self {
343        self.or(Self::method_trace())
344    }
345
346    /// Create a [`DomainMatcher`] matcher, matching on the exact given [`Domain`].
347    pub fn domain(domain: Domain) -> Self {
348        Self {
349            kind: HttpMatcherKind::Domain(DomainMatcher::exact(domain)),
350            negate: false,
351        }
352    }
353
354    /// Create a [`DomainMatcher`] matcher, matching on the exact given [`Domain`]
355    /// or a subdomain of it.
356    pub fn subdomain(domain: Domain) -> Self {
357        Self {
358            kind: HttpMatcherKind::Domain(DomainMatcher::sub(domain)),
359            negate: false,
360        }
361    }
362
363    /// Create a [`DomainMatcher`] matcher to also match on top of the existing set of [`HttpMatcher`] matchers.
364    ///
365    /// See [`Self::domain`] for more information.
366    pub fn and_domain(self, domain: Domain) -> Self {
367        self.and(Self::domain(domain))
368    }
369
370    /// Create a sub [`DomainMatcher`] matcher to also match on top of the existing set of [`HttpMatcher`] matchers.
371    ///
372    /// See [`Self::subdomain`] for more information.
373    pub fn and_subdomain(self, domain: Domain) -> Self {
374        self.and(Self::subdomain(domain))
375    }
376
377    /// Create a [`DomainMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
378    ///
379    /// See [`Self::domain`] for more information.
380    pub fn or_domain(self, domain: Domain) -> Self {
381        self.or(Self::domain(domain))
382    }
383
384    /// Create a sub [`DomainMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
385    ///
386    /// See [`Self::subdomain`] for more information.
387    pub fn or_subdomain(self, domain: Domain) -> Self {
388        self.or(Self::subdomain(domain))
389    }
390
391    /// Create a [`VersionMatcher`] matcher.
392    pub fn version(version: VersionMatcher) -> Self {
393        Self {
394            kind: HttpMatcherKind::Version(version),
395            negate: false,
396        }
397    }
398
399    /// Add a [`VersionMatcher`] matcher to matcher on top of the existing set of [`HttpMatcher`] matchers.
400    ///
401    /// See [`VersionMatcher`] for more information.
402    pub fn and_version(self, version: VersionMatcher) -> Self {
403        self.and(Self::version(version))
404    }
405
406    /// Create a [`VersionMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
407    ///
408    /// See [`VersionMatcher`] for more information.
409    pub fn or_version(self, version: VersionMatcher) -> Self {
410        self.or(Self::version(version))
411    }
412
413    /// Create a [`UriMatcher`] matcher.
414    pub fn uri(re: impl AsRef<str>) -> Self {
415        Self {
416            kind: HttpMatcherKind::Uri(UriMatcher::new(re)),
417            negate: false,
418        }
419    }
420
421    /// Create a [`UriMatcher`] matcher to match on top of the existing set of [`HttpMatcher`] matchers.
422    ///
423    /// See [`UriMatcher`] for more information.
424    pub fn and_uri(self, re: impl AsRef<str>) -> Self {
425        self.and(Self::uri(re))
426    }
427
428    /// Create a [`UriMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
429    ///
430    /// See [`UriMatcher`] for more information.
431    pub fn or_uri(self, re: impl AsRef<str>) -> Self {
432        self.or(Self::uri(re))
433    }
434
435    /// Create a [`PathMatcher`] matcher.
436    pub fn path(path: impl AsRef<str>) -> Self {
437        Self {
438            kind: HttpMatcherKind::Path(PathMatcher::new(path)),
439            negate: false,
440        }
441    }
442
443    /// Add a [`PathMatcher`] to match on top of the existing set of [`HttpMatcher`] matchers.
444    ///
445    /// See [`PathMatcher`] for more information.
446    pub fn and_path(self, path: impl AsRef<str>) -> Self {
447        self.and(Self::path(path))
448    }
449
450    /// Create a [`PathMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
451    ///
452    /// See [`PathMatcher`] for more information.
453    pub fn or_path(self, path: impl AsRef<str>) -> Self {
454        self.or(Self::path(path))
455    }
456
457    /// Create a [`HeaderMatcher`] matcher.
458    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    /// Add a [`HeaderMatcher`] to match on top of the existing set of [`HttpMatcher`] matchers.
466    ///
467    /// See [`HeaderMatcher`] for more information.
468    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    /// Create a [`HeaderMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
477    ///
478    /// See [`HeaderMatcher`] for more information.
479    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    /// Create a [`HeaderMatcher`] matcher when the given header exists
488    /// to match on the existence of a header.
489    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    /// Add a [`HeaderMatcher`] to match when the given header exists
497    /// on top of the existing set of [`HttpMatcher`] matchers.
498    ///
499    /// See [`HeaderMatcher`] for more information.
500    pub fn and_header_exists(self, name: http::header::HeaderName) -> Self {
501        self.and(Self::header_exists(name))
502    }
503
504    /// Create a [`HeaderMatcher`] matcher to match when the given header exists
505    /// as an alternative to the existing set of [`HttpMatcher`] matchers.
506    ///
507    /// See [`HeaderMatcher`] for more information.
508    pub fn or_header_exists(self, name: http::header::HeaderName) -> Self {
509        self.or(Self::header_exists(name))
510    }
511
512    /// Create a [`HeaderMatcher`] matcher to match on it containing the given value.
513    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    /// Add a [`HeaderMatcher`] to match when it contains the given value
524    /// on top of the existing set of [`HttpMatcher`] matchers.
525    ///
526    /// See [`HeaderMatcher`] for more information.
527    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    /// Create a [`HeaderMatcher`] matcher to match if it contains the given value
536    /// as an alternative to the existing set of [`HttpMatcher`] matchers.
537    ///
538    /// See [`HeaderMatcher`] for more information.
539    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    /// Create a [`SocketMatcher`] matcher.
548    pub fn socket(socket: SocketMatcher<State, Request<Body>>) -> Self {
549        Self {
550            kind: HttpMatcherKind::Socket(socket),
551            negate: false,
552        }
553    }
554
555    /// Add a [`SocketMatcher`] matcher to match on top of the existing set of [`HttpMatcher`] matchers.
556    ///
557    /// See [`SocketMatcher`] for more information.
558    pub fn and_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
559        self.and(Self::socket(socket))
560    }
561
562    /// Create a [`SocketMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
563    ///
564    /// See [`SocketMatcher`] for more information.
565    pub fn or_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
566        self.or(Self::socket(socket))
567    }
568
569    /// Create a [`PathMatcher`] matcher to match for a GET request.
570    pub fn get(path: impl AsRef<str>) -> Self {
571        Self::method_get().and_path(path)
572    }
573
574    /// Create a matcher that matches according to a custom predicate.
575    ///
576    /// See [`rama_core::matcher::Matcher`] for more information.
577    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    /// Add a custom matcher to match on top of the existing set of [`HttpMatcher`] matchers.
588    ///
589    /// See [`rama_core::matcher::Matcher`] for more information.
590    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    /// Create a custom matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
598    ///
599    /// See [`rama_core::matcher::Matcher`] for more information.
600    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    /// Create a [`PathMatcher`] matcher to match for a POST request.
608    pub fn post(path: impl AsRef<str>) -> Self {
609        Self::method_post().and_path(path)
610    }
611
612    /// Create a [`PathMatcher`] matcher to match for a PUT request.
613    pub fn put(path: impl AsRef<str>) -> Self {
614        Self::method_put().and_path(path)
615    }
616
617    /// Create a [`PathMatcher`] matcher to match for a DELETE request.
618    pub fn delete(path: impl AsRef<str>) -> Self {
619        Self::method_delete().and_path(path)
620    }
621
622    /// Create a [`PathMatcher`] matcher to match for a PATCH request.
623    pub fn patch(path: impl AsRef<str>) -> Self {
624        Self::method_patch().and_path(path)
625    }
626
627    /// Create a [`PathMatcher`] matcher to match for a HEAD request.
628    pub fn head(path: impl AsRef<str>) -> Self {
629        Self::method_head().and_path(path)
630    }
631
632    /// Create a [`PathMatcher`] matcher to match for a OPTIONS request.
633    pub fn options(path: impl AsRef<str>) -> Self {
634        Self::method_options().and_path(path)
635    }
636
637    /// Create a [`PathMatcher`] matcher to match for a TRACE request.
638    pub fn trace(path: impl AsRef<str>) -> Self {
639        Self::method_trace().and_path(path)
640    }
641
642    /// Add a [`HttpMatcher`] to match on top of the existing set of [`HttpMatcher`] matchers.
643    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    /// Create a [`HttpMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
657    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    /// Negate the current matcher
671    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}