rama_http/layer/json_capture/
body.rs1use std::pin::Pin;
5use std::task::{Context, Poll};
6
7use pin_project_lite::pin_project;
8use rama_core::bytes::{Buf, Bytes};
9use rama_core::error::BoxError;
10use rama_core::futures::ready;
11use rama_json::capture::{CaptureHandler, JsonCapturer};
12use rama_json::path::JsonPath;
13use rama_json::tokenizer::DEFAULT_MAX_BUFFERED_BYTES;
14
15use crate::body::{Frame, SizeHint, StreamingBody};
16
17type OnEnd<H> = Box<dyn FnOnce(H) + Send + Sync>;
20
21pin_project! {
22 pub struct JsonCaptureBody<B, H> {
29 #[pin]
30 inner: B,
31 capturer: Option<JsonCapturer<H>>,
33 on_end: Option<OnEnd<H>>,
35 done: bool,
36 }
37}
38
39impl<B, H> JsonCaptureBody<B, H>
40where
41 H: CaptureHandler,
42{
43 pub fn new(
45 inner: B,
46 selectors: impl IntoIterator<Item = JsonPath>,
47 max_capture_bytes: usize,
48 handler: H,
49 ) -> Self {
50 Self::with_max_buffered_bytes(
51 inner,
52 selectors,
53 max_capture_bytes,
54 DEFAULT_MAX_BUFFERED_BYTES,
55 handler,
56 )
57 }
58
59 pub fn with_max_buffered_bytes(
61 inner: B,
62 selectors: impl IntoIterator<Item = JsonPath>,
63 max_capture_bytes: usize,
64 max_buffered_bytes: usize,
65 handler: H,
66 ) -> Self {
67 Self {
68 inner,
69 capturer: Some(JsonCapturer::with_max_buffered_bytes(
70 selectors,
71 max_capture_bytes,
72 max_buffered_bytes,
73 handler,
74 )),
75 on_end: None,
76 done: false,
77 }
78 }
79}
80
81impl<B, H> JsonCaptureBody<B, H> {
82 pub fn passthrough(inner: B) -> Self {
85 Self {
86 inner,
87 capturer: None,
88 on_end: None,
89 done: false,
90 }
91 }
92
93 #[must_use]
101 pub fn on_end<F>(mut self, on_end: F) -> Self
102 where
103 F: FnOnce(H) + Send + Sync + 'static,
104 {
105 self.on_end = Some(Box::new(on_end));
106 self
107 }
108}
109
110fn fire_on_end<H: CaptureHandler>(
112 capturer: &mut Option<JsonCapturer<H>>,
113 on_end: &mut Option<OnEnd<H>>,
114) {
115 if let (Some(capturer), Some(on_end)) = (capturer.take(), on_end.take()) {
116 on_end(capturer.into_handler());
117 }
118}
119
120impl<B, H> StreamingBody for JsonCaptureBody<B, H>
121where
122 B: StreamingBody<Error: Into<BoxError>>,
123 H: CaptureHandler,
124{
125 type Data = Bytes;
126 type Error = BoxError;
127
128 fn poll_frame(
129 self: Pin<&mut Self>,
130 cx: &mut Context<'_>,
131 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
132 let mut this = self.project();
133
134 if *this.done {
135 return Poll::Ready(None);
136 }
137
138 let Some(capturer) = this.capturer.as_mut() else {
139 return match ready!(this.inner.as_mut().poll_frame(cx)) {
140 Some(Ok(frame)) => Poll::Ready(Some(Ok(normalize_frame(frame)))),
141 Some(Err(err)) => Poll::Ready(Some(Err(err.into()))),
142 None => {
143 *this.done = true;
144 Poll::Ready(None)
145 }
146 };
147 };
148
149 match ready!(this.inner.as_mut().poll_frame(cx)) {
150 Some(Ok(frame)) => match frame.into_data() {
151 Ok(mut data) => {
152 let bytes = data.copy_to_bytes(data.remaining());
153 if let Err(err) = capturer.write(&bytes) {
154 return Poll::Ready(Some(Err(err.into())));
155 }
156 Poll::Ready(Some(Ok(Frame::data(bytes))))
157 }
158 Err(frame) => match frame.into_trailers() {
159 Ok(trailers) => {
160 if let Err(err) = capturer.end() {
161 return Poll::Ready(Some(Err(err.into())));
162 }
163 fire_on_end(this.capturer, this.on_end);
164 *this.done = true;
165 Poll::Ready(Some(Ok(Frame::trailers(trailers))))
166 }
167 Err(_) => Poll::Ready(Some(Ok(Frame::data(Bytes::new())))),
168 },
169 },
170 Some(Err(err)) => Poll::Ready(Some(Err(err.into()))),
171 None => {
172 *this.done = true;
173 if let Err(err) = capturer.end() {
174 return Poll::Ready(Some(Err(err.into())));
175 }
176 fire_on_end(this.capturer, this.on_end);
177 Poll::Ready(None)
178 }
179 }
180 }
181
182 fn size_hint(&self) -> SizeHint {
183 self.inner.size_hint()
184 }
185}
186
187fn normalize_frame<D: Buf>(frame: Frame<D>) -> Frame<Bytes> {
189 match frame.into_data() {
190 Ok(mut data) => Frame::data(data.copy_to_bytes(data.remaining())),
191 Err(frame) => match frame.into_trailers() {
192 Ok(trailers) => Frame::trailers(trailers),
193 Err(_) => Frame::data(Bytes::new()),
194 },
195 }
196}