iota_rest_api/
content_type.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use axum::http::{self, HeaderMap, StatusCode, header};
6use mime::Mime;
7use tap::Pipe;
8
9/// `Content-Type` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-3.1.1.5)
10#[derive(Debug, Clone)]
11pub struct ContentType(pub Mime);
12
13impl ContentType {
14    pub fn from_headers(headers: &HeaderMap) -> Option<Self> {
15        parse_content_type(headers).ok()?.map(Self)
16    }
17}
18
19fn parse_content_type(headers: &HeaderMap) -> Result<Option<Mime>, mime::FromStrError> {
20    let Some(header) = headers
21        .get(header::CONTENT_TYPE)
22        .and_then(|hval| hval.to_str().ok())
23    else {
24        return Ok(None);
25    };
26
27    let mime: Mime = header.parse()?;
28    Ok(Some(mime))
29}
30
31impl<S> axum::extract::FromRequestParts<S> for ContentType
32where
33    S: Send + Sync,
34{
35    type Rejection = (StatusCode, &'static str);
36
37    async fn from_request_parts(
38        parts: &mut http::request::Parts,
39        _: &S,
40    ) -> Result<Self, Self::Rejection> {
41        parse_content_type(&parts.headers)
42            .map_err(|_| (StatusCode::BAD_REQUEST, "invalid Content-Type mime"))?
43            .ok_or((StatusCode::BAD_REQUEST, "Content-Type header missing"))?
44            .pipe(Self)
45            .pipe(Ok)
46    }
47}