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
use async_trait::async_trait;
use axum::{
body::{Bytes, HttpBody},
extract::{FromRequest, RequestParts},
http::{header, StatusCode},
response::IntoResponse,
BoxError,
};
use libipld_cbor::DagCborCodec;
use mime_guess::mime;
use noosphere_storage::{block_deserialize, block_serialize};
use serde::{de::DeserializeOwned, Serialize};
#[derive(Debug, Clone, Copy, Default)]
pub struct Cbor<T: Serialize + DeserializeOwned>(pub T);
impl<T> IntoResponse for Cbor<T>
where
T: Serialize + DeserializeOwned,
{
fn into_response(self) -> axum::response::Response {
match block_serialize::<DagCborCodec, _>(self.0) {
Ok((_, bytes)) => bytes.into_response(),
Err(error) => {
error!("{:?}", error);
StatusCode::INTERNAL_SERVER_ERROR.into_response()
}
}
}
}
#[async_trait]
impl<T, B> FromRequest<B> for Cbor<T>
where
T: Serialize + DeserializeOwned,
B: HttpBody + Send,
B::Data: Send,
B::Error: Into<BoxError>,
{
type Rejection = StatusCode;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
if !is_octet_stream_content_type(req) {
return Err(StatusCode::BAD_REQUEST);
}
let bytes = Bytes::from_request(req).await.map_err(|error| {
error!("{:?}", error);
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Cbor(block_deserialize::<DagCborCodec, T>(&bytes).map_err(
|error| {
error!("{:?}", error);
StatusCode::BAD_REQUEST
},
)?))
}
}
fn is_octet_stream_content_type<B>(req: &RequestParts<B>) -> bool {
let content_type = if let Some(content_type) = req.headers().get(header::CONTENT_TYPE) {
content_type
} else {
return false;
};
let content_type = if let Ok(content_type) = content_type.to_str() {
content_type
} else {
return false;
};
let mime = if let Ok(mime) = content_type.parse::<mime::Mime>() {
mime
} else {
return false;
};
mime == mime::APPLICATION_OCTET_STREAM
}