Skip to main content

scion_h3_axum/
lib.rs

1// Copyright 2026 Anapaya Systems
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! # SCION HTTP/3 Axum Server
16//!
17//! [ScionH3AxumServer] allows serving an Axum application over SCION/Http3 using a
18//! [GenericScionUdpSocket].
19
20use std::{convert::Infallible, sync::Arc};
21
22use axum::http;
23use scion_quic::{
24    h3::server::{H3RequestBody, Http3Server, Http3ServerConfig, HttpService},
25    quic::{
26        connection::ConnectionHandle,
27        server_endpoint::{Metrics, QuicScionEndpointDriver, QuicScionServerEndpoint},
28    },
29    reexport::squiche::{self},
30    socket::{GenericScionUdpSocket, SocketError},
31};
32use tokio_util::sync::CancellationToken;
33
34/// Axum-based HTTP/3 server using a GenericScionUdpSocket
35pub struct ScionH3AxumServer;
36
37impl ScionH3AxumServer {
38    /// Serves the given Axum app over HTTP/3 using the provided socket.
39    ///
40    /// This function will return when the server is stopped or encounters an error.
41    ///
42    /// ### Parameters
43    /// * `sock`: An `Arc` to a `GenericScionUdpSocket` that will be used to listen for incoming
44    ///   connections.
45    /// * `app`: The Axum application to serve over HTTP/3.
46    /// * `quic_config`: The QUIC configuration to use for the server.
47    pub async fn serve(
48        sock: Arc<dyn GenericScionUdpSocket>,
49        app: axum::Router,
50        quic_config: squiche::Config,
51    ) -> Result<(), Box<dyn SocketError>> {
52        let cancel_token = CancellationToken::new();
53        Self::serve_with_graceful_shutdown(sock, app, quic_config, cancel_token).await
54    }
55
56    /// Serves the given Axum app over HTTP/3 using the provided socket.
57    ///
58    /// This function will return when the server is stopped or encounters an error.
59    /// The `cancel_token` can be used to stop the server gracefully.
60    ///
61    /// ### Parameters
62    /// * `sock`: An `Arc` to a `GenericScionUdpSocket` that will be used to listen for incoming
63    ///   connections.
64    /// * `app`: The Axum application to serve over HTTP/3.
65    /// * `quic_config`: The QUIC configuration to use for the server.
66    /// * `cancel_token`: A `CancellationToken` that can be used to stop the server gracefully.
67    pub async fn serve_with_graceful_shutdown(
68        sock: Arc<dyn GenericScionUdpSocket>,
69        app: axum::Router,
70        quic_config: squiche::Config,
71        cancel_token: CancellationToken,
72    ) -> Result<(), Box<dyn SocketError>> {
73        let addr = sock.local_addr();
74        let metrics = Metrics::new_without_registry();
75        let ep = QuicScionServerEndpoint::new([0u8; 32], quic_config, addr, metrics);
76        let driver = QuicScionEndpointDriver::with_config(
77            ep,
78            sock,
79            |_: ConnectionHandle<Http3Server<AxumH3Service>>| {},
80            Http3ServerConfig::new(AxumH3Service { app: app.clone() }),
81        );
82
83        driver.run(cancel_token).await
84    }
85}
86
87struct AxumH3Service {
88    app: axum::Router,
89}
90
91impl HttpService for AxumH3Service {
92    type Body = H3RequestBody;
93    type ResponseBody = axum::body::Body;
94
95    async fn call(&self, req: http::Request<Self::Body>) -> http::Response<Self::ResponseBody> {
96        // Pinning the type to Infallible
97        let res: Result<http::Response<axum::body::Body>, Infallible> =
98            tower::ServiceExt::oneshot(self.app.clone(), req).await;
99        res.expect("Infallible")
100    }
101}