1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
use std::{
    fmt,
    ops::{Deref, DerefMut},
};

use bytes::buf::Buf;
use serde::de::DeserializeOwned;

use viz_utils::{futures::future::BoxFuture, serde::json, tracing};

use crate::{
    types::{Payload, PayloadDetect, PayloadError},
    Context, Extract,
};

/// Json Extractor
#[derive(Clone)]
pub struct Json<T = ()>(pub T);

impl<T> Json<T> {
    /// Create new `Json` instance.
    pub fn new(t: T) -> Self {
        Self(t)
    }

    /// Deconstruct to an inner value
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T> AsRef<T> for Json<T> {
    fn as_ref(&self) -> &T {
        &self.0
    }
}

impl<T> Deref for Json<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> DerefMut for Json<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

impl<T: fmt::Debug> fmt::Debug for Json<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        T::fmt(&self, f)
    }
}

impl<T> Extract for Json<T>
where
    T: DeserializeOwned + Send + Sync,
{
    type Error = PayloadError;

    #[inline]
    fn extract<'a>(cx: &'a mut Context) -> BoxFuture<'a, Result<Self, Self::Error>> {
        Box::pin(async move { cx.json().await.map(Json) })
    }
}

impl PayloadDetect for Json {
    #[inline]
    fn detect(m: &mime::Mime) -> bool {
        m.type_() == mime::APPLICATION
            && (m.subtype() == mime::JSON || m.suffix() == Some(mime::JSON))
    }
}

impl Context {
    /// Extracts JSON Data from the request' body.
    pub async fn json<T>(&mut self) -> Result<T, PayloadError>
    where
        T: DeserializeOwned,
    {
        // @TODO: cache Payload<JSON> to extensions
        let mut payload = Payload::<Json>::new();

        payload.set_limit(self.config().limits.json);

        payload.check_header(self.mime(), self.len())?;

        json::from_slice(
            payload
                .check_real_length(self.take_body().ok_or_else(|| PayloadError::Read)?)
                .await?
                .chunk(),
        )
        .map_err(|e| {
            tracing::debug!("Json deserialize error: {}", e);
            PayloadError::Parse
        })
    }
}