mirror of
https://github.com/tokio-rs/axum.git
synced 2025-03-16 12:25:41 +01:00
* Move `IntoResponse` to axum-core * Move `FromRequest` to axum-core * some clean up * Remove hyper dependency from axum-core * Fix docs reference * Use default * Update changelog * Remove mention of default type
92 lines
3 KiB
Rust
92 lines
3 KiB
Rust
//! HTTP body utilities.
|
|
|
|
use crate::{BoxError, Error};
|
|
use bytes::Bytes;
|
|
use bytes::{Buf, BufMut};
|
|
use http_body::Body;
|
|
|
|
/// A boxed [`Body`] trait object.
|
|
///
|
|
/// This is used in axum as the response body type for applications. It's
|
|
/// necessary to unify multiple response bodies types into one.
|
|
pub type BoxBody = http_body::combinators::UnsyncBoxBody<Bytes, Error>;
|
|
|
|
/// Convert a [`http_body::Body`] into a [`BoxBody`].
|
|
pub fn boxed<B>(body: B) -> BoxBody
|
|
where
|
|
B: http_body::Body<Data = Bytes> + Send + 'static,
|
|
B::Error: Into<BoxError>,
|
|
{
|
|
try_downcast(body).unwrap_or_else(|body| body.map_err(Error::new).boxed_unsync())
|
|
}
|
|
|
|
pub(crate) fn try_downcast<T, K>(k: K) -> Result<T, K>
|
|
where
|
|
T: 'static,
|
|
K: Send + 'static,
|
|
{
|
|
let mut k = Some(k);
|
|
if let Some(k) = <dyn std::any::Any>::downcast_mut::<Option<T>>(&mut k) {
|
|
Ok(k.take().unwrap())
|
|
} else {
|
|
Err(k.unwrap())
|
|
}
|
|
}
|
|
|
|
// copied from hyper under the following license:
|
|
// Copyright (c) 2014-2021 Sean McArthur
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
pub(crate) async fn to_bytes<T>(body: T) -> Result<Bytes, T::Error>
|
|
where
|
|
T: Body,
|
|
{
|
|
futures_util::pin_mut!(body);
|
|
|
|
// If there's only 1 chunk, we can just return Buf::to_bytes()
|
|
let mut first = if let Some(buf) = body.data().await {
|
|
buf?
|
|
} else {
|
|
return Ok(Bytes::new());
|
|
};
|
|
|
|
let second = if let Some(buf) = body.data().await {
|
|
buf?
|
|
} else {
|
|
return Ok(first.copy_to_bytes(first.remaining()));
|
|
};
|
|
|
|
// With more than 1 buf, we gotta flatten into a Vec first.
|
|
let cap = first.remaining() + second.remaining() + body.size_hint().lower() as usize;
|
|
let mut vec = Vec::with_capacity(cap);
|
|
vec.put(first);
|
|
vec.put(second);
|
|
|
|
while let Some(buf) = body.data().await {
|
|
vec.put(buf?);
|
|
}
|
|
|
|
Ok(vec.into())
|
|
}
|
|
|
|
#[test]
|
|
fn test_try_downcast() {
|
|
assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32));
|
|
assert_eq!(try_downcast::<i32, _>(5_i32), Ok(5_i32));
|
|
}
|