credence_lib/server/
routers.rs

1use super::super::{configuration::*, middleware::*};
2
3use {
4    ::axum::{
5        extract::{Request, *},
6        http::{header::*, *},
7        middleware::*,
8        response::*,
9        routing::*,
10    },
11    bytestring::*,
12    kutil_http::{
13        axum::*,
14        cache::{axum::*, *},
15    },
16    tower_http::{limit::*, services::*, timeout::*, trace::*},
17};
18
19/// Create a Credence site router.
20pub fn new_site_router<CacheT>(shutdown: &Shutdown, cache: &CacheT, configuration: &CredenceConfiguration) -> Router
21where
22    CacheT: Cache<CommonCacheKey>,
23{
24    let admin_router = Router::new()
25        .route("/shutdown", post(shutdown_handler))
26        .with_state(shutdown.clone())
27        .route("/reset-cache", post(reset_cache_handler::<CacheT, _>))
28        .with_state(cache.clone())
29        .route("/status/{status_code}", get(status_code));
30
31    let router = Router::new()
32        .fallback_service(ServeDir::new(&configuration.files.assets).append_index_html_on_directories(false))
33        .nest("/admin", admin_router)
34        .layer(from_fn_with_state(RenderMiddleware::new(configuration.clone()), RenderMiddleware::function))
35        .layer(configuration.caching_layer(cache.clone()))
36        .layer(from_fn_with_state(CatchMiddleware::new(configuration.files.status.clone()), CatchMiddleware::function));
37
38    // Request rewriting cannot happen in the handling router
39    // https://docs.rs/axum/latest/axum/middleware/index.html#rewriting-request-uri-in-middleware
40
41    let router = Router::new()
42        .merge(router)
43        .layer(map_request_with_state(FacadeMiddleware::new(configuration.clone()), FacadeMiddleware::function))
44        .layer(RequestBodyLimitLayer::new(configuration.requests.max_body_size.value.into()))
45        .layer(TimeoutLayer::new(configuration.requests.max_duration.value.into()))
46        .layer(TraceLayer::new_for_http());
47
48    router
49}
50
51/// Create a Credence redirecting router.
52pub fn new_redirecting_router(tls: bool, host: ByteString, tcp_port: u16) -> Router {
53    let scheme = if tls { "https://" } else { "http://" };
54
55    let tcp_port = match tcp_port {
56        80 | 443 => "".into(),
57        _ => format!(":{}", tcp_port),
58    };
59
60    Router::new().fallback(async move |request: Request| {
61        let path_and_query = request
62            .uri()
63            .path_and_query()
64            .map(|path_and_query| path_and_query.to_string())
65            .unwrap_or_else(|| "/".into());
66
67        let uri = format!("{}{}{}{}", scheme, host, tcp_port, path_and_query);
68
69        (StatusCode::MOVED_PERMANENTLY, [(LOCATION, uri)]).into_response()
70    })
71}
72
73async fn status_code(Path(status_code): Path<u16>) -> StatusCode {
74    tracing::debug!("status code: {}", status_code);
75    StatusCode::from_u16(status_code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
76}