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
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(
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    /// Add a [`HeaderMatcher`] to match on top of the existing set of [`HttpMatcher`] matchers.
469    ///
470    /// See [`HeaderMatcher`] for more information.
471    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    /// Create a [`HeaderMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
480    ///
481    /// See [`HeaderMatcher`] for more information.
482    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    /// Create a [`HeaderMatcher`] matcher when the given header exists
491    /// to match on the existence of a header.
492    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    /// Add a [`HeaderMatcher`] to match when the given header exists
500    /// on top of the existing set of [`HttpMatcher`] matchers.
501    ///
502    /// See [`HeaderMatcher`] for more information.
503    pub fn and_header_exists(self, name: rama_http_types::header::HeaderName) -> Self {
504        self.and(Self::header_exists(name))
505    }
506
507    /// Create a [`HeaderMatcher`] matcher to match when the given header exists
508    /// as an alternative to the existing set of [`HttpMatcher`] matchers.
509    ///
510    /// See [`HeaderMatcher`] for more information.
511    pub fn or_header_exists(self, name: rama_http_types::header::HeaderName) -> Self {
512        self.or(Self::header_exists(name))
513    }
514
515    /// Create a [`HeaderMatcher`] matcher to match on it containing the given value.
516    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    /// Add a [`HeaderMatcher`] to match when it contains the given value
527    /// on top of the existing set of [`HttpMatcher`] matchers.
528    ///
529    /// See [`HeaderMatcher`] for more information.
530    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    /// Create a [`HeaderMatcher`] matcher to match if it contains the given value
539    /// as an alternative to the existing set of [`HttpMatcher`] matchers.
540    ///
541    /// See [`HeaderMatcher`] for more information.
542    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    /// Create a [`SocketMatcher`] matcher.
551    pub fn socket(socket: SocketMatcher<State, Request<Body>>) -> Self {
552        Self {
553            kind: HttpMatcherKind::Socket(socket),
554            negate: false,
555        }
556    }
557
558    /// Add a [`SocketMatcher`] matcher to match on top of the existing set of [`HttpMatcher`] matchers.
559    ///
560    /// See [`SocketMatcher`] for more information.
561    pub fn and_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
562        self.and(Self::socket(socket))
563    }
564
565    /// Create a [`SocketMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
566    ///
567    /// See [`SocketMatcher`] for more information.
568    pub fn or_socket(self, socket: SocketMatcher<State, Request<Body>>) -> Self {
569        self.or(Self::socket(socket))
570    }
571
572    /// Create a [`PathMatcher`] matcher to match for a GET request.
573    pub fn get(path: impl AsRef<str>) -> Self {
574        Self::method_get().and_path(path)
575    }
576
577    /// Create a matcher that matches according to a custom predicate.
578    ///
579    /// See [`rama_core::matcher::Matcher`] for more information.
580    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    /// Add a custom matcher to match on top of the existing set of [`HttpMatcher`] matchers.
591    ///
592    /// See [`rama_core::matcher::Matcher`] for more information.
593    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    /// Create a custom matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
601    ///
602    /// See [`rama_core::matcher::Matcher`] for more information.
603    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    /// Create a [`PathMatcher`] matcher to match for a POST request.
611    pub fn post(path: impl AsRef<str>) -> Self {
612        Self::method_post().and_path(path)
613    }
614
615    /// Create a [`PathMatcher`] matcher to match for a PUT request.
616    pub fn put(path: impl AsRef<str>) -> Self {
617        Self::method_put().and_path(path)
618    }
619
620    /// Create a [`PathMatcher`] matcher to match for a DELETE request.
621    pub fn delete(path: impl AsRef<str>) -> Self {
622        Self::method_delete().and_path(path)
623    }
624
625    /// Create a [`PathMatcher`] matcher to match for a PATCH request.
626    pub fn patch(path: impl AsRef<str>) -> Self {
627        Self::method_patch().and_path(path)
628    }
629
630    /// Create a [`PathMatcher`] matcher to match for a HEAD request.
631    pub fn head(path: impl AsRef<str>) -> Self {
632        Self::method_head().and_path(path)
633    }
634
635    /// Create a [`PathMatcher`] matcher to match for a OPTIONS request.
636    pub fn options(path: impl AsRef<str>) -> Self {
637        Self::method_options().and_path(path)
638    }
639
640    /// Create a [`PathMatcher`] matcher to match for a TRACE request.
641    pub fn trace(path: impl AsRef<str>) -> Self {
642        Self::method_trace().and_path(path)
643    }
644
645    /// Add a [`HttpMatcher`] to match on top of the existing set of [`HttpMatcher`] matchers.
646    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    /// Create a [`HttpMatcher`] matcher to match as an alternative to the existing set of [`HttpMatcher`] matchers.
660    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    /// Negate the current matcher
674    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}