jsonrpsee_core/
http_helpers.rs1use crate::{classify_message, BoxError};
30use bytes::{Buf, Bytes};
31use http_body::Frame;
32use http_body_util::{BodyExt, Limited};
33use std::{
34 pin::Pin,
35 task::{Context, Poll},
36};
37
38const MAX_BODY_PREALLOCATION: usize = 1024 * 1024;
43
44pub type Request<T = Body> = http::Request<T>;
46pub type Response<T = Body> = http::Response<T>;
48
49#[derive(Debug, Default)]
51pub struct Body(http_body_util::combinators::UnsyncBoxBody<Bytes, BoxError>);
52
53impl Body {
54 pub fn empty() -> Self {
56 Self::default()
57 }
58
59 pub fn new<B>(body: B) -> Self
61 where
62 B: http_body::Body<Data = Bytes> + Send + 'static,
63 B::Data: Send + 'static,
64 B::Error: Into<BoxError>,
65 {
66 Self(body.map_err(|e| e.into()).boxed_unsync())
67 }
68}
69
70impl From<String> for Body {
71 fn from(s: String) -> Self {
72 let body = http_body_util::Full::from(s);
73 Self::new(body)
74 }
75}
76
77impl From<&'static str> for Body {
78 fn from(s: &'static str) -> Self {
79 let body = http_body_util::Full::from(s);
80 Self::new(body)
81 }
82}
83
84impl From<Vec<u8>> for Body {
85 fn from(bytes: Vec<u8>) -> Self {
86 let body = http_body_util::Full::from(bytes);
87 Self::new(body)
88 }
89}
90
91impl http_body::Body for Body {
92 type Data = Bytes;
93 type Error = BoxError;
94
95 #[inline]
96 fn poll_frame(
97 mut self: Pin<&mut Self>,
98 cx: &mut Context<'_>,
99 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
100 Pin::new(&mut self.0).poll_frame(cx)
101 }
102
103 #[inline]
104 fn size_hint(&self) -> http_body::SizeHint {
105 self.0.size_hint()
106 }
107
108 #[inline]
109 fn is_end_stream(&self) -> bool {
110 self.0.is_end_stream()
111 }
112}
113
114#[derive(Debug, thiserror::Error)]
116pub enum HttpError {
117 #[error("The HTTP message was too big")]
119 TooLarge,
120 #[error("Malformed request")]
122 Malformed,
123 #[error(transparent)]
125 Stream(#[from] BoxError),
126}
127
128pub async fn read_body<B>(
135 headers: &http::HeaderMap,
136 body: B,
137 max_body_size: u32,
138) -> Result<(Vec<u8>, bool), HttpError>
139where
140 B: http_body::Body<Data = Bytes> + Send + 'static,
141 B::Data: Send,
142 B::Error: Into<BoxError>,
143{
144 let body_size = read_header_content_length(headers).unwrap_or(0);
148
149 if body_size > max_body_size {
150 return Err(HttpError::TooLarge);
151 }
152
153 futures_util::pin_mut!(body);
154
155 let mut received_data =
156 Vec::with_capacity(std::cmp::min(body_size as usize, MAX_BODY_PREALLOCATION));
157 let mut limited_body = Limited::new(body, max_body_size as usize);
158
159 let mut is_single = None;
160
161 while let Some(frame_or_err) = limited_body.frame().await {
162 let frame = frame_or_err.map_err(HttpError::Stream)?;
163 let Some(data) = frame.data_ref() else {
164 continue;
165 };
166
167 if received_data.is_empty() {
170 let Some((data, single)) = classify_message(data.chunk()) else {
171 return Err(HttpError::Malformed);
172 };
173 is_single = Some(single);
174
175 received_data.extend_from_slice(data);
177 } else {
178 received_data.extend_from_slice(data.chunk());
179 }
180 }
181
182 match is_single {
183 Some(single) if !received_data.is_empty() => {
184 tracing::trace!(
185 target: "jsonrpsee-http",
186 "HTTP body: {}",
187 std::str::from_utf8(&received_data).unwrap_or("Invalid UTF-8 data")
188 );
189 Ok((received_data, single))
190 }
191 _ => Err(HttpError::Malformed),
192 }
193}
194
195fn read_header_content_length(headers: &http::header::HeaderMap) -> Option<u32> {
200 let mut values = headers.get_all(http::header::CONTENT_LENGTH).iter();
201 let length = values.next()?;
202 if values.next().is_some() {
204 return None
205 }
206 length.to_str().ok()?.parse().ok()
208}
209
210#[cfg(test)]
211mod tests {
212 use super::{read_body, read_header_content_length};
213
214 type Body = http_body_util::Full<bytes::Bytes>;
215
216 #[tokio::test]
217 async fn body_to_bytes_size_limit_works() {
218 let headers = http::header::HeaderMap::new();
219 let body = Body::from(vec![0; 128]);
220 assert!(read_body(&headers, body, 127).await.is_err());
221 }
222
223 #[test]
224 fn read_content_length_works() {
225 let mut headers = http::header::HeaderMap::new();
226 headers.insert(http::header::CONTENT_LENGTH, "177".parse().unwrap());
227 assert_eq!(read_header_content_length(&headers), Some(177));
228
229 headers.append(http::header::CONTENT_LENGTH, "999".parse().unwrap());
230 assert_eq!(read_header_content_length(&headers), None);
231 }
232
233 #[test]
234 fn read_content_length_too_big_value() {
235 let mut headers = http::header::HeaderMap::new();
236 headers.insert(http::header::CONTENT_LENGTH, "18446744073709551616".parse().unwrap());
237 assert_eq!(read_header_content_length(&headers), None);
238 }
239}