rama_http/matcher/
mod.rs

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