Skip to main content

relay_server/endpoints/
nel.rs

1//! Endpoint for Network Error Logging (NEL) reports.
2
3use axum::extract::DefaultBodyLimit;
4use axum::http::StatusCode;
5use axum::response::IntoResponse;
6use axum::routing::{MethodRouter, post};
7use relay_config::ConfigSnapshot;
8
9use crate::endpoints::common;
10use crate::extractors::{IntegrationBuilder, Mime};
11use crate::integrations::LogsIntegration;
12use crate::service::ServiceState;
13
14fn is_nel_mime(mime: Mime) -> bool {
15    let ty = mime.type_().as_str();
16    let subty = mime.subtype().as_str();
17    let suffix = mime.suffix().map(|suffix| suffix.as_str());
18
19    matches!(
20        (ty, subty, suffix),
21        ("application", "json", None) | ("application", "reports", Some("json"))
22    )
23}
24
25/// Handles all messages coming on the NEL endpoint.
26async fn handle(
27    state: ServiceState,
28    mime: Mime,
29    builder: IntegrationBuilder,
30) -> axum::response::Result<impl IntoResponse> {
31    if !is_nel_mime(mime) {
32        return Ok(StatusCode::UNSUPPORTED_MEDIA_TYPE);
33    }
34
35    let envelope = builder.with_type(LogsIntegration::Nel).build();
36
37    common::handle_envelope(&state, envelope)
38        .await?
39        .ignore_rate_limits();
40
41    Ok(StatusCode::OK)
42}
43
44pub fn route(config: &ConfigSnapshot) -> MethodRouter<ServiceState> {
45    post(handle).route_layer(DefaultBodyLimit::max(config.max_container_size()))
46}