Skip to main content

rama_http/layer/upgrade/
layer.rs

1use crate::io::upgrade::Upgraded;
2
3use super::UpgradeResponse;
4
5use super::{UpgradeService, service::UpgradeHandler};
6use rama_core::error::BoxError;
7use rama_core::error_sink::{DropErrorSink, ErrorSink, TracingErrorSink};
8use rama_core::{Layer, Service, matcher::Matcher, rt::Executor};
9use rama_http_types::Request;
10use std::{fmt, sync::Arc};
11
12/// UpgradeLayer is a middleware that can be used to upgrade a request.
13///
14/// See [`UpgradeService`] for more details.
15///
16/// [`UpgradeService`]: crate::layer::upgrade::UpgradeService
17pub struct UpgradeLayer<O> {
18    handlers: Vec<Arc<UpgradeHandler<O>>>,
19    exec: Executor,
20    error_sink: Arc<dyn ErrorSink>,
21}
22
23impl<O> UpgradeLayer<O> {
24    /// Create a new upgrade layer whose handler's errors are routed to the
25    /// default [`ErrorSink`] ([`TracingErrorSink::default`], DEBUG level).
26    ///
27    /// Use [`UpgradeLayer::new_with_error_sink`] to give the handler a custom
28    /// sink (which also lifts the `Error: Into<BoxError>` requirement, allowing
29    /// any handler error type).
30    pub fn new<M, R, H>(exec: Executor, matcher: M, responder: R, handler: H) -> Self
31    where
32        M: Matcher<Request>,
33        R: Service<Request, Output = UpgradeResponse<Request, O>, Error = O> + Clone,
34        H: Service<Upgraded, Output = (), Error: Into<BoxError>> + Clone,
35    {
36        Self::new_with_error_sink(
37            exec,
38            matcher,
39            responder,
40            handler,
41            TracingErrorSink::default(),
42        )
43    }
44
45    /// Create a new upgrade layer, routing the handler's errors (of any type)
46    /// to the given [`ErrorSink`].
47    pub fn new_with_error_sink<M, R, H, Sink>(
48        exec: Executor,
49        matcher: M,
50        responder: R,
51        handler: H,
52        sink: Sink,
53    ) -> Self
54    where
55        M: Matcher<Request>,
56        R: Service<Request, Output = UpgradeResponse<Request, O>, Error = O> + Clone,
57        H: Service<Upgraded, Output = ()> + Clone,
58        Sink: ErrorSink<H::Error>,
59    {
60        Self {
61            handlers: vec![Arc::new(UpgradeHandler::new(
62                matcher, responder, handler, sink,
63            ))],
64            exec,
65            error_sink: Arc::new(TracingErrorSink::default()),
66        }
67    }
68
69    /// Create a new upgrade layer whose handler's errors (of any type) are
70    /// silently dropped ([`DropErrorSink`]). Use this for handlers whose errors
71    /// are neither actionable nor traceable.
72    pub fn new_dropping_errors<M, R, H>(
73        exec: Executor,
74        matcher: M,
75        responder: R,
76        handler: H,
77    ) -> Self
78    where
79        M: Matcher<Request>,
80        R: Service<Request, Output = UpgradeResponse<Request, O>, Error = O> + Clone,
81        H: Service<Upgraded, Output = ()> + Clone,
82    {
83        Self::new_with_error_sink(exec, matcher, responder, handler, DropErrorSink::new())
84    }
85
86    /// Add an extra upgrade handler, routing its errors to the default
87    /// [`ErrorSink`] ([`TracingErrorSink::default`], DEBUG level).
88    #[must_use]
89    pub fn on<M, R, H>(self, matcher: M, responder: R, handler: H) -> Self
90    where
91        M: Matcher<Request>,
92        R: Service<Request, Output = UpgradeResponse<Request, O>, Error = O> + Clone,
93        H: Service<Upgraded, Output = (), Error: Into<BoxError>> + Clone,
94    {
95        self.on_with_error_sink(matcher, responder, handler, TracingErrorSink::default())
96    }
97
98    /// Add an extra upgrade handler whose errors (of any type) are silently
99    /// dropped ([`DropErrorSink`]).
100    #[must_use]
101    pub fn on_dropping_errors<M, R, H>(self, matcher: M, responder: R, handler: H) -> Self
102    where
103        M: Matcher<Request>,
104        R: Service<Request, Output = UpgradeResponse<Request, O>, Error = O> + Clone,
105        H: Service<Upgraded, Output = ()> + Clone,
106    {
107        self.on_with_error_sink(matcher, responder, handler, DropErrorSink::new())
108    }
109
110    /// Add an extra upgrade handler, routing its errors (of any type) to the
111    /// given [`ErrorSink`].
112    #[must_use]
113    pub fn on_with_error_sink<M, R, H, Sink>(
114        mut self,
115        matcher: M,
116        responder: R,
117        handler: H,
118        sink: Sink,
119    ) -> Self
120    where
121        M: Matcher<Request>,
122        R: Service<Request, Output = UpgradeResponse<Request, O>, Error = O> + Clone,
123        H: Service<Upgraded, Output = ()> + Clone,
124        Sink: ErrorSink<H::Error>,
125    {
126        self.handlers.push(Arc::new(UpgradeHandler::new(
127            matcher, responder, handler, sink,
128        )));
129        self
130    }
131
132    /// Set the [`ErrorSink`] used for errors that occur while *establishing*
133    /// the upgraded connection (i.e. the HTTP upgrade itself fails, before any
134    /// handler runs). Per-handler errors are routed to their own sink instead;
135    /// see [`UpgradeLayer::on_with_error_sink`].
136    ///
137    /// Defaults to [`TracingErrorSink::default`] (traces at DEBUG level).
138    #[must_use]
139    pub fn with_upgrade_error_sink(mut self, sink: impl ErrorSink) -> Self {
140        self.error_sink = Arc::new(sink);
141        self
142    }
143}
144
145impl<O> fmt::Debug for UpgradeLayer<O> {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        f.debug_struct("UpgradeLayer")
148            .field("handlers", &self.handlers)
149            .finish()
150    }
151}
152
153impl<O> Clone for UpgradeLayer<O> {
154    fn clone(&self) -> Self {
155        Self {
156            handlers: self.handlers.clone(),
157            exec: self.exec.clone(),
158            error_sink: self.error_sink.clone(),
159        }
160    }
161}
162
163impl<S, O> Layer<S> for UpgradeLayer<O> {
164    type Service = UpgradeService<S, O>;
165
166    fn layer(&self, inner: S) -> Self::Service {
167        UpgradeService::new(
168            self.handlers.clone(),
169            inner,
170            self.exec.clone(),
171            self.error_sink.clone(),
172        )
173    }
174
175    fn into_layer(self, inner: S) -> Self::Service {
176        UpgradeService::new(self.handlers, inner, self.exec, self.error_sink)
177    }
178}