1use crate::body::util::BodyExt;
6use pin_project_lite::pin_project;
7use rama_core::bytes::Bytes;
8use rama_core::error::BoxError;
9use rama_core::futures::TryStream;
10use rama_core::futures::stream::Stream;
11use rama_core::stream::json;
12use rama_utils::str::arcstr::ArcStr;
13use serde::de::DeserializeOwned;
14use sse::{EventDataRead, EventStream};
15use std::pin::Pin;
16use std::task::{Context, Poll};
17use sync_wrapper::SyncWrapper;
18
19pub mod http_body;
22mod http_body_util;
23
24pub use http_body::Body as StreamingBody;
25pub use http_body::Frame;
26pub use http_body::SizeHint;
27
28pub mod util {
30 pub use super::http_body_util::*;
31}
32
33mod limit;
34pub use limit::BodyLimit;
35
36mod ext;
37pub use ext::BodyExtractExt;
38
39#[doc(inline)]
40pub use util::{CollectError, CollectErrorKind, CollectOptions};
41
42pub mod sse;
43
44mod infinite;
45pub use infinite::InfiniteReader;
46
47mod on_drop;
48pub use on_drop::OnDropBody;
49
50mod guarded;
51pub use guarded::GuardedBody;
52
53mod optional;
54pub use optional::OptionalBody;
55
56mod capture;
57pub use capture::{
58 BodyCaptureEvent, BodyCaptureSink, BufferedBodyCapture, CaptureBody, CaptureCanceled,
59 CaptureHandle, CaptureLimit, CaptureOutcome, CapturedBody,
60};
61
62impl<B: StreamingBody> StreamingBody for crate::Request<B> {
65 type Data = B::Data;
66 type Error = B::Error;
67
68 fn poll_frame(
69 self: Pin<&mut Self>,
70 cx: &mut Context<'_>,
71 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
72 unsafe { self.map_unchecked_mut(Self::body_mut).poll_frame(cx) }
75 }
76
77 fn is_end_stream(&self) -> bool {
78 self.body().is_end_stream()
79 }
80
81 fn size_hint(&self) -> SizeHint {
82 self.body().size_hint()
83 }
84}
85
86impl<B: StreamingBody> StreamingBody for crate::Response<B> {
87 type Data = B::Data;
88 type Error = B::Error;
89
90 fn poll_frame(
91 self: Pin<&mut Self>,
92 cx: &mut Context<'_>,
93 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
94 unsafe { self.map_unchecked_mut(Self::body_mut).poll_frame(cx) }
97 }
98
99 fn is_end_stream(&self) -> bool {
100 self.body().is_end_stream()
101 }
102
103 fn size_hint(&self) -> SizeHint {
104 self.body().size_hint()
105 }
106}
107
108type BoxBody = util::combinators::BoxBody<Bytes, BoxError>;
111
112fn boxed<B>(body: B) -> BoxBody
113where
114 B: StreamingBody<Data = Bytes, Error: Into<BoxError>> + Send + Sync + 'static,
115{
116 try_downcast(body).unwrap_or_else(|body| body.map_err(Into::into).boxed())
117}
118
119#[expect(clippy::unwrap_used)]
120pub(crate) fn try_downcast<T, K>(k: K) -> Result<T, K>
121where
122 T: 'static,
123 K: Send + 'static,
124{
125 let mut k = Some(k);
126 if let Some(k) = <dyn std::any::Any>::downcast_mut::<Option<T>>(&mut k) {
127 Ok(k.take().unwrap())
128 } else {
129 Err(k.unwrap())
130 }
131}
132
133#[must_use]
135#[derive(Debug)]
136pub struct Body(BoxBody);
137
138impl Body {
139 pub fn new<B>(body: B) -> Self
141 where
142 B: StreamingBody<Data = Bytes, Error: Into<BoxError>> + Send + Sync + 'static,
143 {
144 try_downcast(body).unwrap_or_else(|body| Self(boxed(body)))
145 }
146
147 pub fn with_limit<B>(body: B, limit: usize) -> Self
149 where
150 B: StreamingBody<Data = Bytes, Error: Into<BoxError>> + Send + Sync + 'static,
151 {
152 Self::new(util::Limited::new(body, limit))
153 }
154
155 pub fn empty() -> Self {
157 Self::new(util::Empty::new())
158 }
159
160 pub fn from_stream<S>(stream: S) -> Self
164 where
165 S: TryStream<Ok: Into<Bytes>, Error: Into<BoxError>> + Send + 'static,
166 {
167 Self::new(StreamBody {
168 stream: SyncWrapper::new(stream),
169 })
170 }
171
172 pub fn limited(self, limit: usize) -> Self {
174 Self::new(util::Limited::new(self.0, limit))
175 }
176
177 pub fn on_drop<F>(self, on_drop: F) -> Self
183 where
184 F: FnOnce() + Send + Sync + 'static,
185 {
186 Self::new(OnDropBody::new(self.0, on_drop))
187 }
188
189 pub fn capture<S>(self, sink: S) -> Self
191 where
192 S: BodyCaptureSink,
193 {
194 Self::new(CaptureBody::new(self.0, sink))
195 }
196
197 pub fn capture_buffered(self, limit: CaptureLimit) -> (Self, CaptureHandle) {
217 let (body, handle) = CaptureBody::buffered(self.0, limit);
218 (Self::new(body), handle)
219 }
220
221 pub fn with_trailer_headers(self, headers: crate::HeaderMap) -> Self {
228 Self::new(self.0.with_trailers(std::future::ready(Some(Ok(headers)))))
229 }
230
231 pub fn into_data_stream(self) -> BodyDataStream {
238 BodyDataStream { inner: self }
239 }
240
241 #[must_use]
245 pub fn into_event_stream<T: EventDataRead>(self) -> EventStream<BodyDataStream, T> {
246 EventStream::new(self.into_data_stream())
247 }
248
249 #[must_use]
253 pub fn into_json_stream<T: DeserializeOwned>(self) -> json::JsonReadStream<T, BodyDataStream> {
254 let stream = self.into_data_stream();
255 json::JsonReadStream::new(stream)
256 }
257
258 #[must_use]
262 pub fn into_json_stream_with_config<T: DeserializeOwned>(
263 self,
264 cfg: json::ParseConfig,
265 ) -> json::JsonReadStream<T, BodyDataStream> {
266 let stream = self.into_data_stream();
267 json::JsonReadStream::new_with_config(stream, cfg)
268 }
269
270 #[must_use]
274 pub fn into_string_data_event_stream(self) -> EventStream<BodyDataStream> {
275 EventStream::new(self.into_data_stream())
276 }
277
278 pub async fn chunk(&mut self) -> Result<Option<Bytes>, BoxError> {
282 loop {
284 if let Some(res) = self.frame().await {
285 let frame = res?;
286 if let Ok(buf) = frame.into_data() {
287 return Ok(Some(buf));
288 }
289 } else {
291 return Ok(None);
292 }
293 }
294 }
295}
296
297impl Default for Body {
298 fn default() -> Self {
299 Self::empty()
300 }
301}
302
303impl From<()> for Body {
304 fn from(_: ()) -> Self {
305 Self::empty()
306 }
307}
308
309macro_rules! body_from_impl {
310 ($ty:ty) => {
311 impl From<$ty> for Body {
312 fn from(buf: $ty) -> Self {
313 Self::new(crate::body::util::Full::from(buf))
314 }
315 }
316 };
317}
318
319body_from_impl!(&'static [u8]);
320body_from_impl!(std::borrow::Cow<'static, [u8]>);
321body_from_impl!(Vec<u8>);
322
323body_from_impl!(&'static str);
324body_from_impl!(std::borrow::Cow<'static, str>);
325body_from_impl!(String);
326
327impl From<&ArcStr> for Body {
328 fn from(buf: &ArcStr) -> Self {
329 Self::new(if let Some(s) = ArcStr::as_static(buf) {
330 crate::body::util::Full::from(s)
331 } else {
332 crate::body::util::Full::from(buf.to_string())
333 })
334 }
335}
336
337impl From<ArcStr> for Body {
338 #[inline(always)]
339 fn from(buf: ArcStr) -> Self {
340 Self::from(&buf)
341 }
342}
343
344body_from_impl!(Bytes);
345
346impl StreamingBody for Body {
347 type Data = Bytes;
348 type Error = BoxError;
349
350 #[inline]
351 fn poll_frame(
352 mut self: Pin<&mut Self>,
353 cx: &mut Context<'_>,
354 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
355 Pin::new(&mut self.0).poll_frame(cx)
356 }
357
358 #[inline]
359 fn size_hint(&self) -> SizeHint {
360 self.0.size_hint()
361 }
362
363 #[inline]
364 fn is_end_stream(&self) -> bool {
365 self.0.is_end_stream()
366 }
367}
368
369#[derive(Debug)]
373#[must_use]
374pub struct BodyDataStream {
375 inner: Body,
376}
377
378impl Stream for BodyDataStream {
379 type Item = Result<Bytes, BoxError>;
380
381 #[inline]
382 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
383 loop {
384 match rama_core::futures::ready!(Pin::new(&mut self.inner).poll_frame(cx)?) {
385 Some(frame) => match frame.into_data() {
386 Ok(data) => return Poll::Ready(Some(Ok(data))),
387 Err(_frame) => {}
388 },
389 None => return Poll::Ready(None),
390 }
391 }
392 }
393}
394
395impl StreamingBody for BodyDataStream {
396 type Data = Bytes;
397 type Error = BoxError;
398
399 #[inline]
400 fn poll_frame(
401 mut self: Pin<&mut Self>,
402 cx: &mut Context<'_>,
403 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
404 Pin::new(&mut self.inner).poll_frame(cx)
405 }
406
407 #[inline]
408 fn is_end_stream(&self) -> bool {
409 self.inner.is_end_stream()
410 }
411
412 #[inline]
413 fn size_hint(&self) -> SizeHint {
414 self.inner.size_hint()
415 }
416}
417
418pin_project! {
419 struct StreamBody<S> {
420 #[pin]
421 stream: SyncWrapper<S>,
422 }
423}
424
425impl<S> StreamingBody for StreamBody<S>
426where
427 S: TryStream<Ok: Into<Bytes>, Error: Into<BoxError>>,
428{
429 type Data = Bytes;
430 type Error = BoxError;
431
432 fn poll_frame(
433 self: Pin<&mut Self>,
434 cx: &mut Context<'_>,
435 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
436 let stream = self.project().stream.get_pin_mut();
437 match rama_core::futures::ready!(stream.try_poll_next(cx)) {
438 Some(Ok(chunk)) => Poll::Ready(Some(Ok(Frame::data(chunk.into())))),
439 Some(Err(err)) => Poll::Ready(Some(Err(err.into()))),
440 None => Poll::Ready(None),
441 }
442 }
443}
444
445#[test]
446fn test_try_downcast() {
447 assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32));
448 assert_eq!(try_downcast::<i32, _>(5_i32), Ok(5_i32));
449}
450
451#[tokio::test]
452async fn capture_convenience_forwards_and_observes_body() {
453 let (sink, mut events) = tokio::sync::mpsc::unbounded_channel();
454 let forwarded = Body::from("captured").capture(sink);
455
456 assert_eq!(
457 forwarded.collect().await.unwrap().to_bytes(),
458 Bytes::from_static(b"captured")
459 );
460 let BodyCaptureEvent::Frame(frame) = events.recv().await.unwrap() else {
461 panic!("the first capture event must contain the data frame");
462 };
463 assert_eq!(frame.into_data().unwrap(), Bytes::from_static(b"captured"));
464 assert!(matches!(
465 events.recv().await,
466 Some(BodyCaptureEvent::End(CaptureOutcome::Complete))
467 ));
468}