1const LOG_TARGET: &str = "jsonrpsee-core";
30
31use std::{
32 io,
33 sync::atomic::{AtomicUsize, Ordering},
34};
35
36use jsonrpsee_types::{
37 error::{
38 reject_too_big_batch_response, ErrorCode, ErrorObject, OVERSIZED_RESPONSE_CODE,
39 OVERSIZED_RESPONSE_MSG,
40 },
41 Id, Response,
42};
43use serde::Serialize;
44use serde_json::value::to_raw_value;
45
46pub use jsonrpsee_types::ResponsePayload;
47
48#[derive(Debug, Clone)]
49enum ResponseKind {
50 MethodCall,
51 Subscription,
52 Batch,
53 Notification,
54}
55
56#[derive(Debug)]
63pub struct MethodResponse {
64 json: String,
66 success_or_error: MethodResponseResult,
68 kind: ResponseKind,
70}
71
72impl AsRef<str> for MethodResponse {
73 fn as_ref(&self) -> &str {
74 &self.json
75 }
76}
77
78impl std::fmt::Display for MethodResponse {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 write!(f, "{}", self.json)
81 }
82}
83
84impl MethodResponse {
85 pub fn is_success(&self) -> bool {
87 self.success_or_error.is_success()
88 }
89
90 pub fn is_error(&self) -> bool {
92 self.success_or_error.is_error()
93 }
94
95 pub fn is_subscription(&self) -> bool {
97 matches!(self.kind, ResponseKind::Subscription)
98 }
99
100 pub fn is_method_call(&self) -> bool {
102 matches!(self.kind, ResponseKind::MethodCall)
103 }
104
105 pub fn is_batch(&self) -> bool {
107 matches!(self.kind, ResponseKind::Batch)
108 }
109
110 pub fn into_json(self) -> String {
112 self.json
113 }
114
115 pub fn to_json(&self) -> String {
117 self.json.clone()
118 }
119
120 pub fn as_error_code(&self) -> Option<i32> {
124 self.success_or_error.as_error_code()
125 }
126
127 pub fn subscription_response<T>(
130 id: Id,
131 result: ResponsePayload<T>,
132 max_response_size: usize,
133 ) -> Self
134 where
135 T: Serialize + Clone,
136 {
137 let mut rp = Self::response(id, result, max_response_size);
138 rp.kind = ResponseKind::Subscription;
139 rp
140 }
141
142 pub fn response<T>(id: Id, rp: ResponsePayload<T>, max_response_size: usize) -> Self
147 where
148 T: Serialize + Clone,
149 {
150 Self::response_with_capacity(id, rp, max_response_size, 128)
151 }
152
153 pub(crate) fn sized_response<T>(
156 id: Id,
157 rp: ResponsePayload<T>,
158 max_response_size: usize,
159 size_hint: &ResponseSizeHint,
160 ) -> Self
161 where
162 T: Serialize + Clone,
163 {
164 let mut rp = Self::response_with_capacity(id, rp, max_response_size, size_hint.get());
165 if rp.json.capacity() / 2 > rp.json.len() {
168 rp.json.shrink_to_fit();
169 }
170 size_hint.record(rp.json.len());
171 rp
172 }
173
174 fn response_with_capacity<T>(
175 id: Id,
176 rp: ResponsePayload<T>,
177 max_response_size: usize,
178 capacity: usize,
179 ) -> Self
180 where
181 T: Serialize + Clone,
182 {
183 let mut writer = BoundedWriter::new(max_response_size, capacity);
184
185 let success_or_error = if let ResponsePayload::Error(e) = &rp {
186 MethodResponseResult::Failed(e.code())
187 } else {
188 MethodResponseResult::Success
189 };
190
191 let kind = ResponseKind::MethodCall;
192
193 match serde_json::to_writer(&mut writer, &Response::new(rp, id.clone())) {
194 Ok(_) => {
195 let json = unsafe { String::from_utf8_unchecked(writer.into_bytes()) };
197
198 Self { json, success_or_error, kind }
199 }
200 Err(err) => {
201 tracing::error!(target: LOG_TARGET, "Error serializing response: {:?}", err);
202
203 if err.is_io() {
204 let data =
205 to_raw_value(&format!("Exceeded max limit of {max_response_size}")).ok();
206 let err_code = OVERSIZED_RESPONSE_CODE;
207
208 let err = ResponsePayload::<()>::error_borrowed(ErrorObject::borrowed(
209 err_code,
210 OVERSIZED_RESPONSE_MSG,
211 data.as_deref(),
212 ));
213 let json = serde_json::to_string(&Response::new(err, id))
214 .expect("JSON serialization infallible; qed");
215
216 Self { json, success_or_error: MethodResponseResult::Failed(err_code), kind }
217 } else {
218 let err = ErrorCode::InternalError;
219 let payload = ResponsePayload::<()>::error(err);
220 let json = serde_json::to_string(&Response::new(payload, id))
221 .expect("JSON serialization infallible; qed");
222 Self { json, success_or_error: MethodResponseResult::Failed(err.code()), kind }
223 }
224 }
225 }
226 }
227
228 pub fn subscription_error<'a>(id: Id, err: impl Into<ErrorObject<'a>>) -> Self {
231 let mut rp = Self::error(id, err);
232 rp.kind = ResponseKind::Subscription;
233 rp
234 }
235
236 pub fn error<'a>(id: Id, err: impl Into<ErrorObject<'a>>) -> Self {
238 let err: ErrorObject = err.into();
239 let err_code = err.code();
240 let err = ResponsePayload::<()>::error_borrowed(err);
241 let json = serde_json::to_string(&Response::new(err, id))
242 .expect("JSON serialization infallible; qed");
243 Self {
244 json,
245 success_or_error: MethodResponseResult::Failed(err_code),
246 kind: ResponseKind::MethodCall,
247 }
248 }
249
250 pub fn notification() -> Self {
252 Self {
253 json: String::from("null"),
254 success_or_error: MethodResponseResult::Success,
255 kind: ResponseKind::Notification,
256 }
257 }
258}
259
260#[derive(Debug, Copy, Clone)]
262enum MethodResponseResult {
263 Success,
265 Failed(i32),
267}
268
269impl MethodResponseResult {
270 fn is_success(&self) -> bool {
272 matches!(self, MethodResponseResult::Success)
273 }
274
275 fn is_error(&self) -> bool {
277 matches!(self, MethodResponseResult::Failed(_))
278 }
279
280 fn as_error_code(&self) -> Option<i32> {
284 match self {
285 Self::Failed(e) => Some(*e),
286 _ => None,
287 }
288 }
289}
290
291#[derive(Debug)]
293pub struct BatchResponseBuilder {
294 result: String,
296 max_response_size: usize,
298}
299
300impl BatchResponseBuilder {
301 pub fn new_with_limit(limit: usize) -> Self {
303 let mut initial = String::with_capacity(2048);
304 initial.push('[');
305
306 Self { result: initial, max_response_size: limit }
307 }
308
309 pub fn append(&mut self, response: MethodResponse) -> Result<(), MethodResponse> {
314 let len = response.json.len() + self.result.len() + 1;
317
318 if len > self.max_response_size {
319 Err(MethodResponse::error(
320 Id::Null,
321 reject_too_big_batch_response(self.max_response_size),
322 ))
323 } else {
324 self.result.push_str(&response.json);
325 self.result.push(',');
326 Ok(())
327 }
328 }
329
330 pub fn is_empty(&self) -> bool {
332 self.result.len() <= 1
333 }
334
335 pub fn finish(mut self) -> MethodResponse {
339 if self.is_empty() {
340 return MethodResponse::error(Id::Null, ErrorObject::from(ErrorCode::InvalidRequest))
341 }
342 self.result.pop();
344 self.result.push(']');
345 MethodResponse {
346 json: self.result,
347 success_or_error: MethodResponseResult::Success,
348 kind: ResponseKind::Batch,
349 }
350 }
351}
352
353#[derive(Debug)]
358pub(crate) struct ResponseSizeHint(AtomicUsize);
359
360impl ResponseSizeHint {
361 pub(crate) const fn new() -> Self {
362 Self(AtomicUsize::new(128))
363 }
364
365 fn get(&self) -> usize {
366 self.0.load(Ordering::Relaxed)
367 }
368
369 fn record(&self, len: usize) {
370 self.0.store(len.min(MAX_RESPONSE_SIZE_HINT), Ordering::Relaxed);
371 }
372}
373
374const MAX_RESPONSE_SIZE_HINT: usize = 8 * 1024 * 1024;
377
378#[derive(Debug, Clone)]
380struct BoundedWriter {
381 max_len: usize,
382 buf: Vec<u8>,
383}
384
385impl BoundedWriter {
386 pub fn new(max_len: usize, capacity: usize) -> Self {
388 Self { max_len, buf: Vec::with_capacity(capacity.min(max_len)) }
389 }
390
391 pub fn into_bytes(self) -> Vec<u8> {
393 self.buf
394 }
395}
396
397impl io::Write for &mut BoundedWriter {
400 #[inline]
401 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
402 self.write_all(buf)?;
403 Ok(buf.len())
404 }
405
406 #[inline]
407 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
408 if buf.len() > self.max_len - self.buf.len() {
409 return Err(limit_exceeded());
410 }
411 self.buf.extend_from_slice(buf);
412 Ok(())
413 }
414
415 #[inline]
416 fn flush(&mut self) -> io::Result<()> {
417 Ok(())
418 }
419}
420
421#[cold]
422fn limit_exceeded() -> io::Error {
423 io::Error::new(io::ErrorKind::OutOfMemory, "Memory capacity exceeded")
424}
425
426#[cfg(test)]
427mod tests {
428 use super::{
429 BatchResponseBuilder, BoundedWriter, Id, MethodResponse, ResponsePayload, ResponseSizeHint,
430 MAX_RESPONSE_SIZE_HINT,
431 };
432
433 #[test]
434 fn batch_with_single_works() {
435 let method = MethodResponse::response(
436 Id::Number(1),
437 ResponsePayload::success_borrowed(&"a"),
438 usize::MAX,
439 );
440 assert_eq!(method.json.len(), 37);
441
442 let mut builder = BatchResponseBuilder::new_with_limit(39);
444 builder.append(method).unwrap();
445 let batch = builder.finish();
446
447 assert_eq!(batch.json, r#"[{"jsonrpc":"2.0","id":1,"result":"a"}]"#)
448 }
449
450 #[test]
451 fn batch_with_multiple_works() {
452 let m1 = MethodResponse::response(
453 Id::Number(1),
454 ResponsePayload::success_borrowed(&"a"),
455 usize::MAX,
456 );
457 let m11 = MethodResponse::response(
458 Id::Number(1),
459 ResponsePayload::success_borrowed(&"a"),
460 usize::MAX,
461 );
462 assert_eq!(m1.json.len(), 37);
463
464 let limit = 2 + (37 * 2) + 1;
467 let mut builder = BatchResponseBuilder::new_with_limit(limit);
468 builder.append(m1).unwrap();
469 builder.append(m11).unwrap();
470 let batch = builder.finish();
471
472 assert_eq!(
473 batch.json,
474 r#"[{"jsonrpc":"2.0","id":1,"result":"a"},{"jsonrpc":"2.0","id":1,"result":"a"}]"#
475 )
476 }
477
478 #[test]
479 fn batch_empty_err() {
480 let batch = BatchResponseBuilder::new_with_limit(1024).finish();
481
482 let exp_err =
483 r#"{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"Invalid request"}}"#;
484 assert_eq!(batch.json, exp_err);
485 }
486
487 #[test]
488 fn batch_too_big() {
489 let method = MethodResponse::response(
490 Id::Number(1),
491 ResponsePayload::success_borrowed(&"a".repeat(28)),
492 128,
493 );
494 assert_eq!(method.json.len(), 64);
495
496 let batch = BatchResponseBuilder::new_with_limit(63).append(method).unwrap_err();
497
498 let exp_err = r#"{"jsonrpc":"2.0","id":null,"error":{"code":-32011,"message":"The batch response was too large","data":"Exceeded max limit of 63"}}"#;
499 assert_eq!(batch.json, exp_err);
500 }
501
502 #[test]
503 fn bounded_serializer_work() {
504 use jsonrpsee_types::{Response, ResponsePayload};
505
506 let mut writer = BoundedWriter::new(100, 128);
507 let result = ResponsePayload::success(&"success");
508 let rp = &Response::new(result, Id::Number(1));
509
510 assert!(serde_json::to_writer(&mut writer, rp).is_ok());
511 assert_eq!(
512 String::from_utf8(writer.into_bytes()).unwrap(),
513 r#"{"jsonrpc":"2.0","id":1,"result":"success"}"#
514 );
515 }
516
517 #[test]
518 fn bounded_serializer_cap_works() {
519 let mut writer = BoundedWriter::new(100, 128);
520 assert!(serde_json::to_writer(&mut writer, &"x".repeat(99)).is_err());
522 }
523
524 #[test]
525 fn size_hint_is_capped_and_small_responses_shrink() {
526 let hint = ResponseSizeHint::new();
527 let big = "x".repeat(MAX_RESPONSE_SIZE_HINT);
528 let rp = MethodResponse::sized_response(
529 Id::Number(1),
530 ResponsePayload::success_borrowed(&big),
531 usize::MAX,
532 &hint,
533 );
534 assert!(rp.json.len() > MAX_RESPONSE_SIZE_HINT);
535 assert_eq!(hint.get(), MAX_RESPONSE_SIZE_HINT);
536
537 let rp = MethodResponse::sized_response(
538 Id::Number(1),
539 ResponsePayload::success_borrowed(&"a"),
540 usize::MAX,
541 &hint,
542 );
543 assert_eq!(rp.json, r#"{"jsonrpc":"2.0","id":1,"result":"a"}"#);
544 assert!(rp.json.capacity() < 2 * rp.json.len());
545 assert_eq!(hint.get(), rp.json.len());
546 }
547}