1use std::ops::{Deref, DerefMut};
2
3use axum_core::{
4 extract::{FromRequest, Request},
5 response::{IntoResponse, Response},
6};
7use bytes::Bytes;
8use http::{header, HeaderValue, StatusCode};
9use serde::{de::DeserializeOwned, Serialize};
10use thiserror::Error;
11
12pub struct Bson<T>(pub T);
13
14#[derive(Debug, Error)]
15pub enum BsonRejection {
16 #[error("bytes read error: {}",.0)]
17 BytesRead(#[from] axum_core::extract::rejection::BytesRejection),
18 #[error("missing octet-stream content type")]
19 MissingContentType,
20 #[error("bson parse error: {}",.0)]
21 BsonError(#[from] bson::de::Error),
22}
23
24impl IntoResponse for BsonRejection {
25 fn into_response(self) -> axum_core::response::Response {
26 (
27 StatusCode::BAD_REQUEST,
28 [(header::CONTENT_TYPE, HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()))],
29 self.to_string(),
30 )
31 .into_response()
32 }
33}
34
35impl<S, T> FromRequest<S> for Bson<T>
36where
37 T: DeserializeOwned,
38 S: Send + Sync,
39{
40 type Rejection = BsonRejection;
41
42 async fn from_request(req: Request, _s: &S) -> Result<Self, Self::Rejection> {
43 if bson_content_type(&req) {
44 let bytes = Bytes::from_request(req, _s).await?;
45 match bson::from_slice(&bytes) {
46 Ok(value) => Ok(Bson(value)),
47 Err(err) => Err(err.into()),
48 }
49 } else {
50 Err(BsonRejection::MissingContentType)
51 }
52 }
53}
54
55fn bson_content_type<B>(req: &Request<B>) -> bool {
56 let content_type = if let Some(content_type) = req.headers().get(header::CONTENT_TYPE) {
57 content_type
58 } else {
59 return false;
60 };
61
62 let content_type = if let Ok(content_type) = content_type.to_str() {
63 content_type
64 } else {
65 return false;
66 };
67
68 let mime = if let Ok(mime) = content_type.parse::<mime::Mime>() {
69 mime
70 } else {
71 return false;
72 };
73
74 let is_binary_content_type = mime.type_() == "application"
75 && (mime.subtype() == "octet-stream"
76 || mime.suffix().map_or(false, |name| name == "octet-stream"));
77
78 is_binary_content_type
79}
80
81impl<T> Deref for Bson<T> {
82 type Target = T;
83
84 fn deref(&self) -> &Self::Target {
85 &self.0
86 }
87}
88
89impl<T> DerefMut for Bson<T> {
90 fn deref_mut(&mut self) -> &mut Self::Target {
91 &mut self.0
92 }
93}
94
95impl<T> From<T> for Bson<T> {
96 fn from(inner: T) -> Self {
97 Self(inner)
98 }
99}
100
101impl<T> IntoResponse for Bson<T>
102where
103 T: Serialize,
104{
105 fn into_response(self) -> Response {
106 match bson::to_raw_document_buf(&self.0) {
107 Ok(buf) => (
108 [(
109 header::CONTENT_TYPE,
110 HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
111 )],
112 Bytes::from(buf.into_bytes()),
113 )
114 .into_response(),
115 Err(err) => {
116 (
117 StatusCode::INTERNAL_SERVER_ERROR,
118 [(
119 header::CONTENT_TYPE,
120 HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
121 )],
122 err.to_string(),
123 )
124 .into_response()
125 }
126 }
127 }
128}
129
130