rama_http/layer/json_rewrite/
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::path::JsonPath;
12use rama_json::rewrite::{JsonRewriter, JsonValueHandler};
13use rama_json::tokenizer::DEFAULT_MAX_BUFFERED_BYTES;
14
15use crate::HeaderMap;
16use crate::body::{Frame, SizeHint, StreamingBody};
17
18type OnEnd<H> = Box<dyn FnOnce(H) + Send + Sync>;
21
22pin_project! {
23 pub struct JsonRewriteBody<B, H> {
33 #[pin]
34 inner: B,
35 rewriter: Option<JsonRewriter<H>>,
37 on_end: Option<OnEnd<H>>,
39 pending_trailers: Option<HeaderMap>,
40 done: bool,
42 }
43}
44
45impl<B, H> JsonRewriteBody<B, H>
46where
47 H: JsonValueHandler,
48{
49 pub fn new(inner: B, selectors: impl IntoIterator<Item = JsonPath>, handler: H) -> Self {
51 Self::with_max_buffered_bytes(inner, selectors, handler, DEFAULT_MAX_BUFFERED_BYTES)
52 }
53
54 pub fn with_max_buffered_bytes(
56 inner: B,
57 selectors: impl IntoIterator<Item = JsonPath>,
58 handler: H,
59 max_buffered_bytes: usize,
60 ) -> Self {
61 Self {
62 inner,
63 rewriter: Some(JsonRewriter::with_max_buffered_bytes(
64 selectors,
65 handler,
66 max_buffered_bytes,
67 )),
68 on_end: None,
69 pending_trailers: None,
70 done: false,
71 }
72 }
73}
74
75impl<B, H> JsonRewriteBody<B, H> {
76 pub fn passthrough(inner: B) -> Self {
82 Self {
83 inner,
84 rewriter: None,
85 on_end: None,
86 pending_trailers: None,
87 done: false,
88 }
89 }
90
91 #[must_use]
99 pub fn on_end<F>(mut self, on_end: F) -> Self
100 where
101 F: FnOnce(H) + Send + Sync + 'static,
102 {
103 self.on_end = Some(Box::new(on_end));
104 self
105 }
106}
107
108fn fire_on_end<H: JsonValueHandler>(
110 rewriter: &mut Option<JsonRewriter<H>>,
111 on_end: &mut Option<OnEnd<H>>,
112) {
113 if let (Some(rewriter), Some(on_end)) = (rewriter.take(), on_end.take()) {
114 on_end(rewriter.into_handler());
115 }
116}
117
118impl<B, H> StreamingBody for JsonRewriteBody<B, H>
119where
120 B: StreamingBody<Error: Into<BoxError>>,
121 H: JsonValueHandler,
122{
123 type Data = Bytes;
124 type Error = BoxError;
125
126 fn poll_frame(
127 self: Pin<&mut Self>,
128 cx: &mut Context<'_>,
129 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
130 let mut this = self.project();
131
132 if let Some(trailers) = this.pending_trailers.take() {
133 *this.done = true;
134 return Poll::Ready(Some(Ok(Frame::trailers(trailers))));
135 }
136
137 if *this.done {
138 return Poll::Ready(None);
139 }
140
141 let Some(rewriter) = this.rewriter.as_mut() else {
142 return match ready!(this.inner.as_mut().poll_frame(cx)) {
144 Some(Ok(frame)) => Poll::Ready(Some(Ok(normalize_frame(frame)))),
145 Some(Err(err)) => Poll::Ready(Some(Err(err.into()))),
146 None => {
147 *this.done = true;
148 Poll::Ready(None)
149 }
150 };
151 };
152
153 loop {
154 match ready!(this.inner.as_mut().poll_frame(cx)) {
155 Some(Ok(frame)) => match frame.into_data() {
156 Ok(mut data) => {
157 while data.has_remaining() {
161 let chunk = data.chunk();
162 let len = chunk.len();
163 if let Err(err) = rewriter.write(chunk) {
164 return Poll::Ready(Some(Err(err.into())));
165 }
166 data.advance(len);
167 }
168 let out = rewriter.take_output();
169 if !out.is_empty() {
170 return Poll::Ready(Some(Ok(Frame::data(Bytes::from(out)))));
171 }
172 }
175 Err(frame) => {
178 if let Ok(trailers) = frame.into_trailers() {
179 if let Err(err) = rewriter.end() {
180 return Poll::Ready(Some(Err(err.into())));
181 }
182 let out = rewriter.take_output();
183 fire_on_end(this.rewriter, this.on_end);
184 if out.is_empty() {
185 *this.done = true;
186 return Poll::Ready(Some(Ok(Frame::trailers(trailers))));
187 }
188 *this.pending_trailers = Some(trailers);
189 return Poll::Ready(Some(Ok(Frame::data(Bytes::from(out)))));
190 }
191 }
192 },
193 Some(Err(err)) => return Poll::Ready(Some(Err(err.into()))),
194 None => {
195 *this.done = true;
196 if let Err(err) = rewriter.end() {
197 return Poll::Ready(Some(Err(err.into())));
198 }
199 let out = rewriter.take_output();
200 fire_on_end(this.rewriter, this.on_end);
201 return if out.is_empty() {
202 Poll::Ready(None)
203 } else {
204 Poll::Ready(Some(Ok(Frame::data(Bytes::from(out)))))
205 };
206 }
207 }
208 }
209 }
210
211 fn size_hint(&self) -> SizeHint {
212 if self.rewriter.is_some() {
213 SizeHint::default()
215 } else {
216 self.inner.size_hint()
217 }
218 }
219}
220
221fn normalize_frame<D: Buf>(frame: Frame<D>) -> Frame<Bytes> {
223 match frame.into_data() {
224 Ok(mut data) => Frame::data(data.copy_to_bytes(data.remaining())),
225 Err(frame) => match frame.into_trailers() {
226 Ok(trailers) => Frame::trailers(trailers),
227 Err(_) => Frame::data(Bytes::new()),
230 },
231 }
232}