Skip to main content

sword_layers/req_timeout/
layer.rs

1use crate::{ResponseFnMapper, req_timeout::RequestTimeoutConfig};
2
3use axum::{
4    http::StatusCode,
5    response::{IntoResponse, Response},
6};
7
8use axum_responses::JsonResponse;
9use tower::{ServiceBuilder, util::MapResponseLayer};
10use tower_http::timeout::TimeoutLayer as TowerTimeoutLayer;
11use tower_layer::{Identity, Stack};
12
13type TimeoutLayerType = (
14    TowerTimeoutLayer,
15    ServiceBuilder<Stack<MapResponseLayer<ResponseFnMapper>, Identity>>,
16);
17
18/// ### Request Timeout Layer
19///
20/// This struct represents the Request Timeout Layer which
21/// enforces a maximum duration for incoming requests.
22///
23/// The layer is a combination of `tower_http::timeout::TimeoutLayer` and a response mapper.
24/// Returns a 408 Request Timeout status when a request exceeds the configured duration.
25pub struct RequestTimeoutLayer;
26
27impl RequestTimeoutLayer {
28    pub fn new(config: &RequestTimeoutConfig) -> TimeoutLayerType {
29        let layer =
30            TowerTimeoutLayer::with_status_code(StatusCode::REQUEST_TIMEOUT, config.timeout.parsed);
31
32        fn timeout_mapper(response: Response) -> Response {
33            if response.status().as_u16() == 408 {
34                return JsonResponse::RequestTimeout().into_response();
35            }
36
37            response
38        }
39
40        let response_layer = ServiceBuilder::new().map_response(timeout_mapper as ResponseFnMapper);
41
42        (layer, response_layer)
43    }
44}