1use super::Upgraded;
6use crate::opentelemetry::version_as_protocol_version;
7use rama_core::Layer;
8use rama_core::error::{BoxError, ErrorExt as _};
9use rama_core::error_sink::ErrorSink;
10use rama_core::extensions::{Extension, ExtensionsRef};
11use rama_core::layer::{ConsumeErrLayer, MapOutputLayer};
12use rama_core::rt::Executor;
13use rama_core::telemetry::tracing::{self, Instrument};
14use rama_core::{Service, extensions::Extensions, matcher::Matcher, service::BoxService};
15use rama_http_types::Request;
16use rama_utils::macros::define_inner_service_accessors;
17use std::{convert::Infallible, fmt, future::Future, pin::Pin, sync::Arc};
18
19pub struct UpgradeService<S, O> {
22 handlers: Vec<Arc<UpgradeHandler<O>>>,
23 inner: S,
24 exec: Executor,
25 error_sink: Arc<dyn ErrorSink>,
26}
27
28#[derive(Clone, Debug)]
35pub struct UpgradeResponse<I, O> {
36 pub response: O,
38 pub request: I,
40 pub extensions: Extensions,
43}
44
45impl<I, O> UpgradeResponse<I, O> {
46 #[must_use]
48 pub fn new(request: I, response: O) -> Self {
49 Self {
50 response,
51 request,
52 extensions: Extensions::new(),
53 }
54 }
55
56 #[must_use]
58 pub fn with_extension<T: Extension>(self, extension: T) -> Self {
59 self.extensions.insert(extension);
60 self
61 }
62
63 pub fn with_handler<F, Fut, T, E>(self, handler: F) -> UpgradeOutput<I, O>
69 where
70 F: FnOnce(Upgraded) -> Fut + Send + 'static,
71 Fut: Future<Output = Result<T, E>> + Send + 'static,
72 E: Into<BoxError>,
73 {
74 UpgradeOutput {
75 response: self.response,
76 request: self.request,
77 extensions: self.extensions,
78 handler: Box::new(move |upgraded| {
79 Box::pin(async move { handler(upgraded).await.map(drop).map_err(Into::into) })
80 }),
81 }
82 }
83}
84
85pub(crate) type UpgradeHandlerFuture =
86 Pin<Box<dyn Future<Output = Result<(), BoxError>> + Send + 'static>>;
87pub(crate) type ResponseUpgradeHandler =
88 Box<dyn FnOnce(Upgraded) -> UpgradeHandlerFuture + Send + 'static>;
89
90#[must_use]
95pub struct UpgradeOutput<I, O> {
96 pub response: O,
98 pub request: I,
100 pub extensions: Extensions,
102 pub(crate) handler: ResponseUpgradeHandler,
103}
104
105impl<I, O> fmt::Debug for UpgradeOutput<I, O>
106where
107 I: fmt::Debug,
108 O: fmt::Debug,
109{
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 f.debug_struct("UpgradeOutput")
112 .field("response", &self.response)
113 .field("request", &self.request)
114 .field("extensions", &self.extensions)
115 .finish_non_exhaustive()
116 }
117}
118
119pub struct UpgradeHandler<O> {
121 matcher: Box<dyn Matcher<Request>>,
122 kind: UpgradeHandlerKind<O>,
123 _phantom: std::marker::PhantomData<fn(O) -> ()>,
124}
125
126enum UpgradeHandlerKind<O> {
127 ResponseLocal {
128 responder: BoxService<Request, UpgradeOutput<Request, O>, O>,
129 handler_error_sink: Arc<dyn ErrorSink>,
130 },
131 SeparateServices {
132 responder: BoxService<Request, UpgradeResponse<Request, O>, O>,
133 handler: BoxService<Upgraded, (), Infallible>,
134 },
135}
136
137enum UpgradeContinuation {
138 ResponseLocal {
139 handler: ResponseUpgradeHandler,
140 error_sink: Arc<dyn ErrorSink>,
141 },
142 Service(BoxService<Upgraded, (), Infallible>),
143}
144
145struct PreparedUpgrade<O> {
146 response: O,
147 request: Request,
148 extensions: Extensions,
149 continuation: UpgradeContinuation,
150}
151
152impl<O: Send + 'static> UpgradeHandler<O> {
153 pub(crate) fn new<M, R, Sink>(matcher: M, responder: R, sink: Sink) -> Self
155 where
156 M: Matcher<Request>,
157 R: Service<Request, Output = UpgradeOutput<Request, O>, Error = O> + Clone,
158 Sink: ErrorSink,
159 {
160 Self {
161 matcher: Box::new(matcher),
162 kind: UpgradeHandlerKind::ResponseLocal {
163 responder: responder.boxed(),
164 handler_error_sink: Arc::new(sink),
165 },
166 _phantom: std::marker::PhantomData,
167 }
168 }
169
170 pub(crate) fn new_with_services<M, R, H, Sink>(
172 matcher: M,
173 responder: R,
174 handler: H,
175 sink: Sink,
176 ) -> Self
177 where
178 M: Matcher<Request>,
179 R: Service<Request, Output = UpgradeResponse<Request, O>, Error = O> + Clone,
180 H: Service<Upgraded> + Clone,
181 Sink: ErrorSink<H::Error>,
182 {
183 let sink = Arc::new(sink);
184 let handler = (
185 ConsumeErrLayer::new(move |err| sink.sink_error(err)),
186 MapOutputLayer::new(drop),
187 )
188 .into_layer(handler)
189 .boxed();
190
191 Self {
192 matcher: Box::new(matcher),
193 kind: UpgradeHandlerKind::SeparateServices {
194 responder: responder.boxed(),
195 handler,
196 },
197 _phantom: std::marker::PhantomData,
198 }
199 }
200
201 async fn prepare(&self, request: Request) -> Result<PreparedUpgrade<O>, O> {
202 match &self.kind {
203 UpgradeHandlerKind::ResponseLocal {
204 responder,
205 handler_error_sink,
206 } => responder.serve(request).await.map(
207 |UpgradeOutput {
208 response,
209 request,
210 extensions,
211 handler,
212 }| PreparedUpgrade {
213 response,
214 request,
215 extensions,
216 continuation: UpgradeContinuation::ResponseLocal {
217 handler,
218 error_sink: handler_error_sink.clone(),
219 },
220 },
221 ),
222 UpgradeHandlerKind::SeparateServices { responder, handler } => {
223 responder.serve(request).await.map(
224 |UpgradeResponse {
225 response,
226 request,
227 extensions,
228 }| PreparedUpgrade {
229 response,
230 request,
231 extensions,
232 continuation: UpgradeContinuation::Service(handler.clone()),
233 },
234 )
235 }
236 }
237 }
238}
239
240impl<S, O> UpgradeService<S, O> {
241 pub fn new(
243 handlers: Vec<Arc<UpgradeHandler<O>>>,
244 inner: S,
245 exec: Executor,
246 error_sink: Arc<dyn ErrorSink>,
247 ) -> Self {
248 Self {
249 handlers,
250 inner,
251 exec,
252 error_sink,
253 }
254 }
255
256 define_inner_service_accessors!();
257}
258
259impl<S, O> fmt::Debug for UpgradeService<S, O>
260where
261 S: fmt::Debug,
262{
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 f.debug_struct("UpgradeService")
265 .field("handlers", &self.handlers)
266 .field("inner", &self.inner)
267 .field("exec", &self.exec)
268 .finish()
269 }
270}
271
272impl<S, O> Clone for UpgradeService<S, O>
273where
274 S: Clone,
275{
276 fn clone(&self) -> Self {
277 Self {
278 handlers: self.handlers.clone(),
279 inner: self.inner.clone(),
280 exec: self.exec.clone(),
281 error_sink: self.error_sink.clone(),
282 }
283 }
284}
285
286impl<S, O> Service<Request> for UpgradeService<S, O>
287where
288 S: Service<Request, Output = O>,
289 O: Send + 'static,
290{
291 type Output = O;
292 type Error = S::Error;
293
294 async fn serve(&self, req: Request) -> Result<Self::Output, Self::Error> {
295 for handler in &self.handlers {
296 let ext = Extensions::new();
297 if !handler.matcher.matches(Some(&ext), &req) {
298 continue;
299 }
300 req.extensions().extend(&ext);
301
302 return match handler.prepare(req).await {
303 Ok(PreparedUpgrade {
304 response,
305 request,
306 extensions,
307 continuation,
308 }) => {
309 let upgrade_error_sink = self.error_sink.clone();
310
311 let span = tracing::trace_root_span!(
312 "upgrade::serve",
313 otel.kind = "server",
314 http.request.method = %request.method().as_str(),
315 url.full = %request.request_uri(),
316 url.path = %request.uri().path_or_root().as_ref(),
317 url.query = %request.uri().query_or_empty().as_ref(),
318 url.scheme = %request.uri().scheme_str().unwrap_or_default(),
319 network.protocol.name = "http",
320 network.protocol.version = version_as_protocol_version(request.version()),
321 );
322
323 self.exec.spawn_task(
324 async move {
325 match crate::io::upgrade::handle_upgrade(request).await {
326 Ok(upgraded) => {
327 upgraded.extensions().extend(&extensions);
328 match continuation {
329 UpgradeContinuation::ResponseLocal {
330 handler,
331 error_sink,
332 } => {
333 if let Err(err) = handler(upgraded).await {
334 error_sink.sink_error(err);
335 }
336 }
337 UpgradeContinuation::Service(handler) => {
338 _ = handler.serve(upgraded).await;
339 }
340 }
341 }
342 Err(err) => {
343 upgrade_error_sink.sink_error(
346 err.context("http upgrade failed before handler"),
347 );
348 }
349 }
350 }
351 .instrument(span),
352 );
353 Ok(response)
354 }
355 Err(e) => Ok(e),
356 };
357 }
358
359 self.inner.serve(req).await
360 }
361}
362
363impl<O> fmt::Debug for UpgradeHandler<O> {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 f.debug_struct("UpgradeHandler").finish()
366 }
367}
368
369#[cfg(test)]
370mod tests {
371 use super::*;
372 use crate::io::upgrade::{Upgraded, pending};
373 use crate::layer::upgrade::UpgradeLayer;
374 use rama_core::Layer;
375 use rama_core::ServiceInput;
376 use rama_core::bytes::Bytes;
377 use rama_core::error::{BoxError, BoxErrorExt as _};
378 use rama_core::service::service_fn;
379 use rama_http_types::{Body, Response};
380 use std::time::Duration;
381 use std::{cell::Cell, convert::Infallible};
382 use tokio::sync::mpsc;
383 use tokio_test::io::Builder;
384
385 #[derive(Debug)]
386 struct ResponseLocalMarker;
387
388 impl Extension for ResponseLocalMarker {}
389
390 #[derive(Clone)]
391 struct SendOnlyOutputResponder;
392
393 impl Service<Request> for SendOnlyOutputResponder {
394 type Output = UpgradeOutput<Request, Cell<u8>>;
395 type Error = Cell<u8>;
396
397 async fn serve(&self, req: Request) -> Result<Self::Output, Self::Error> {
398 Ok(UpgradeResponse::new(req, Cell::new(1))
399 .with_handler(|_upgraded| async { Ok::<_, BoxError>(()) }))
400 }
401 }
402
403 #[derive(Clone)]
404 struct SendOnlyInner;
405
406 impl Service<Request> for SendOnlyInner {
407 type Output = Cell<u8>;
408 type Error = Cell<u8>;
409
410 async fn serve(&self, _req: Request) -> Result<Self::Output, Self::Error> {
411 Err(Cell::new(2))
412 }
413 }
414
415 #[tokio::test]
416 async fn output_and_error_need_not_be_sync() {
417 let service = UpgradeLayer::new(Executor::default(), false, SendOnlyOutputResponder)
418 .into_layer(SendOnlyInner);
419
420 let error = service
421 .serve(Request::new(Body::empty()))
422 .await
423 .unwrap_err();
424
425 assert_eq!(error.get(), 2);
426 }
427
428 #[tokio::test]
429 async fn response_local_handler_runs_after_upgrade() {
430 let (handled_tx, mut handled_rx) = mpsc::unbounded_channel();
431 let (pending_upgrade, on_upgrade) = pending();
432 let req = Request::new(Body::empty());
433 req.extensions().insert(on_upgrade);
434
435 let service = service_fn(move |req: Request| {
436 let handled_tx = handled_tx.clone();
437 async move {
438 Ok::<_, Response>(
439 UpgradeResponse::new(req, Response::new(Body::empty()))
440 .with_extension(ResponseLocalMarker)
441 .with_handler(move |upgraded| async move {
442 assert!(upgraded.extensions().contains::<ResponseLocalMarker>());
443 _ = handled_tx.send(());
444 Ok::<_, BoxError>(())
445 }),
446 )
447 }
448 });
449 let inner =
450 service_fn(
451 |_req: Request| async move { Ok::<_, Infallible>(Response::new(Body::empty())) },
452 );
453 let svc = UpgradeLayer::new(Executor::default(), true, service).into_layer(inner);
454
455 let _response = svc.serve(req).await.expect("upgrade response");
456 assert!(handled_rx.try_recv().is_err());
457
458 pending_upgrade.fulfill(Upgraded::new(
459 ServiceInput::new(Builder::default().build()),
460 Bytes::new(),
461 ));
462 tokio::time::timeout(Duration::from_secs(5), handled_rx.recv())
463 .await
464 .expect("response-local handler should run")
465 .expect("handler notification");
466 }
467
468 #[tokio::test]
469 async fn response_local_handler_error_is_routed_to_sink() {
470 let (error_tx, mut error_rx) = mpsc::unbounded_channel();
471 let (pending_upgrade, on_upgrade) = pending();
472 let req = Request::new(Body::empty());
473 req.extensions().insert(on_upgrade);
474
475 let service = service_fn(|req: Request| async move {
476 Ok::<_, Response>(
477 UpgradeResponse::new(req, Response::new(Body::empty())).with_handler(
478 |_upgraded| async move {
479 Err::<(), _>(BoxError::from_static_str("response-local handler boom"))
480 },
481 ),
482 )
483 });
484 let inner =
485 service_fn(
486 |_req: Request| async move { Ok::<_, Infallible>(Response::new(Body::empty())) },
487 );
488 let svc = UpgradeLayer::new_with_error_sink(
489 Executor::default(),
490 true,
491 service,
492 move |err: BoxError| {
493 _ = error_tx.send(format!("{err:?}"));
494 },
495 )
496 .into_layer(inner);
497
498 let _response = svc.serve(req).await.expect("upgrade response");
499 pending_upgrade.fulfill(Upgraded::new(
500 ServiceInput::new(Builder::default().build()),
501 Bytes::new(),
502 ));
503
504 let reported = tokio::time::timeout(Duration::from_secs(5), error_rx.recv())
505 .await
506 .expect("handler error should reach sink")
507 .expect("handler error notification");
508 assert!(reported.contains("response-local handler boom"));
509 }
510
511 #[tokio::test]
514 async fn upgrade_handler_error_is_routed_to_sink() {
515 let (tx, mut rx) = mpsc::unbounded_channel::<String>();
517
518 let (pending_upgrade, on_upgrade) = pending();
520 let req = Request::new(Body::empty());
521 req.extensions().insert(on_upgrade);
522
523 let responder = service_fn(|req: Request| async move {
526 Ok::<_, Response>(UpgradeResponse {
527 response: Response::new(Body::empty()),
528 request: req,
529 extensions: Extensions::new(),
530 })
531 });
532
533 let handler = service_fn(|_upgraded: Upgraded| async move {
535 Err::<(), BoxError>(BoxError::from_static_str("handler boom"))
536 });
537
538 let inner =
540 service_fn(
541 |_req: Request| async move { Ok::<_, Infallible>(Response::new(Body::empty())) },
542 );
543
544 let svc = UpgradeLayer::new_with_services_and_error_sink(
547 Executor::default(),
548 true,
549 responder,
550 handler,
551 move |err: BoxError| {
552 _ = tx.send(format!("{err:?}"));
553 },
554 )
555 .into_layer(inner);
556
557 let _resp = svc.serve(req).await.expect("upgrade match -> Ok(response)");
559
560 let upgraded = Upgraded::new(ServiceInput::new(Builder::default().build()), Bytes::new());
562 pending_upgrade.fulfill(upgraded);
563
564 let reported = tokio::time::timeout(Duration::from_secs(5), rx.recv())
566 .await
567 .expect("sink should be called within timeout")
568 .expect("sink channel should yield the error");
569 assert!(
570 reported.contains("handler boom"),
571 "unexpected sink message: {reported}"
572 );
573 }
574}