Skip to main content

jsonrpsee_server/
server.rs

1// Copyright 2019-2021 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any
4// person obtaining a copy of this software and associated
5// documentation files (the "Software"), to deal in the
6// Software without restriction, including without
7// limitation the rights to use, copy, modify, merge,
8// publish, distribute, sublicense, and/or sell copies of
9// the Software, and to permit persons to whom the Software
10// is furnished to do so, subject to the following
11// conditions:
12//
13// The above copyright notice and this permission notice
14// shall be included in all copies or substantial portions
15// of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25// DEALINGS IN THE SOFTWARE.
26
27use std::{
28    borrow::Cow, fmt, future::Future, net::SocketAddr, pin::Pin, sync::Arc, task::Poll,
29    time::Duration,
30};
31
32use crate::{
33    future::{ConnectionGuard, ServerHandle, StopHandle},
34    middleware::rpc::{catch_call_panic, RpcService},
35    transport::{http, ws, ws::BackgroundTaskParams},
36    utils::{
37        accept_error_backoff, deserialize_notification, no_request_within, NotifyOnRequest,
38        PermitBody, WriteTimeoutIo, DEFAULT_FIRST_REQUEST_TIMEOUT, DEFAULT_WRITE_TIMEOUT,
39    },
40    HttpBody, HttpRequest, HttpResponse, LOG_TARGET,
41};
42
43use futures_util::{
44    future::{Either, FutureExt},
45    io::{BufReader, BufWriter},
46};
47use hyper::body::{Bytes, Incoming};
48use hyper_util::{
49    rt::{TokioExecutor, TokioIo},
50    service::TowerToHyperService,
51};
52use jsonrpsee_core::{
53    id_providers::RandomIntegerIdProvider,
54    middleware::{Batch, BatchEntry, BatchEntryErr, RpcServiceBuilder, RpcServiceT},
55    server::{
56        helpers::prepare_error, BoundedSubscriptions, ConnectionId, MethodResponse, MethodSink,
57        Methods,
58    },
59    traits::IdProvider,
60    BoxError, JsonRawValue, TEN_MB_SIZE_BYTES,
61};
62use jsonrpsee_types::{
63    error::{
64        reject_too_big_batch_request, ErrorCode, BATCHES_NOT_SUPPORTED_CODE,
65        BATCHES_NOT_SUPPORTED_MSG,
66    },
67    ErrorObject, Id, Notification, Request, TwoPointZero,
68};
69use serde::{
70    de::{
71        value::MapAccessDeserializer, DeserializeSeed, Deserializer, Error as _, IgnoredAny,
72        MapAccess, SeqAccess, Visitor,
73    },
74    Deserialize,
75};
76use soketto::handshake::http::is_upgrade_request;
77use tokio::{
78    net::{TcpListener, TcpStream, ToSocketAddrs},
79    sync::{mpsc, watch, Notify, OwnedSemaphorePermit},
80};
81use tokio_util::compat::TokioAsyncReadCompatExt;
82use tower::{layer::util::Identity, Layer, Service, ServiceExt};
83use tracing::{instrument, Instrument};
84
85/// Default maximum connections allowed.
86const MAX_CONNECTIONS: u32 = 100;
87
88/// JSON RPC server.
89pub struct Server<HttpMiddleware = Identity, RpcMiddleware = Identity> {
90    listener: TcpListener,
91    server_cfg: ServerConfig,
92    rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
93    http_middleware: tower::ServiceBuilder<HttpMiddleware>,
94}
95
96impl Server<Identity, Identity> {
97    /// Create a builder for the server.
98    pub fn builder() -> Builder<Identity, Identity> {
99        Builder::new()
100    }
101}
102
103impl<RpcMiddleware, HttpMiddleware> std::fmt::Debug for Server<RpcMiddleware, HttpMiddleware> {
104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105        f.debug_struct("Server")
106            .field("listener", &self.listener)
107            .field("server_cfg", &self.server_cfg)
108            .finish()
109    }
110}
111
112impl<RpcMiddleware, HttpMiddleware> Server<RpcMiddleware, HttpMiddleware> {
113    /// Returns socket address to which the server is bound.
114    pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
115        self.listener.local_addr()
116    }
117}
118
119impl<HttpMiddleware, RpcMiddleware, Body> Server<HttpMiddleware, RpcMiddleware>
120where
121    RpcMiddleware: Layer<RpcService> + Clone + Send + 'static,
122    <RpcMiddleware as Layer<RpcService>>::Service: RpcServiceT,
123    HttpMiddleware: Layer<TowerServiceNoHttp<RpcMiddleware>> + Send + 'static,
124    <HttpMiddleware as Layer<TowerServiceNoHttp<RpcMiddleware>>>::Service:
125        Service<HttpRequest, Response = HttpResponse<Body>, Error = BoxError> + Clone + Send,
126    <<HttpMiddleware as Layer<TowerServiceNoHttp<RpcMiddleware>>>::Service as Service<
127        HttpRequest,
128    >>::Future: Send,
129    Body: http_body::Body<Data = Bytes> + Send + 'static,
130    <Body as http_body::Body>::Error: Into<BoxError>,
131{
132    /// Start responding to connections requests.
133    ///
134    /// This will run on the tokio runtime until the server is stopped or the `ServerHandle` is
135    /// dropped.
136    pub fn start(mut self, methods: impl Into<Methods>) -> ServerHandle {
137        let methods = methods.into();
138        let (stop_tx, stop_rx) = watch::channel(());
139
140        let stop_handle = StopHandle::new(stop_rx);
141
142        match self.server_cfg.tokio_runtime.take() {
143            Some(rt) => rt.spawn(self.start_inner(methods, stop_handle)),
144            None => tokio::spawn(self.start_inner(methods, stop_handle)),
145        };
146
147        ServerHandle::new(stop_tx)
148    }
149
150    async fn start_inner(self, methods: Methods, stop_handle: StopHandle) {
151        let connection_guard = ConnectionGuard::new(self.server_cfg.max_connections as usize);
152        let listener = self.listener;
153
154        let stopped = stop_handle.clone().shutdown();
155        tokio::pin!(stopped);
156
157        let (drop_on_completion, mut process_connection_awaiter) = mpsc::channel::<()>(1);
158
159        loop {
160            match try_accept_conn(&listener, stopped).await {
161                AcceptConnection::Established { socket, remote_addr, stop } => {
162                    process_connection(ProcessConnection {
163                        http_middleware: &self.http_middleware,
164                        rpc_middleware: self.rpc_middleware.clone(),
165                        remote_addr,
166                        methods: methods.clone(),
167                        stop_handle: stop_handle.clone(),
168                        conn_id: ConnectionId::next_unique().0,
169                        server_cfg: self.server_cfg.clone(),
170                        conn_guard: &connection_guard,
171                        socket,
172                        drop_on_completion: drop_on_completion.clone(),
173                    });
174                    stopped = stop;
175                }
176                AcceptConnection::Err((e, stop)) => {
177                    tracing::debug!(target: LOG_TARGET, "Error while awaiting a new connection: {:?}", e);
178                    let Some(stop) = accept_error_backoff(&e, stop).await else { break };
179                    stopped = stop;
180                }
181                AcceptConnection::Shutdown => break,
182            }
183        }
184
185        // Drop the last Sender
186        drop(drop_on_completion);
187
188        // Once this channel is closed it is safe to assume that all connections have been
189        // gracefully shutdown
190        while process_connection_awaiter.recv().await.is_some() {
191            // Generally, messages should not be sent across this channel,
192            // but we'll loop here to wait for `None` just to be on the safe side
193        }
194    }
195}
196
197/// Static server configuration which is shared per connection.
198#[derive(Debug, Clone)]
199pub struct ServerConfig {
200    /// Maximum size in bytes of a request.
201    pub(crate) max_request_body_size: u32,
202    /// Maximum size in bytes of a response.
203    pub(crate) max_response_body_size: u32,
204    /// Maximum number of incoming connections allowed.
205    pub(crate) max_connections: u32,
206    /// Maximum number of subscriptions per connection.
207    pub(crate) max_subscriptions_per_connection: u32,
208    /// Whether batch requests are supported by this server or not.
209    pub(crate) batch_requests_config: BatchRequestConfig,
210    /// Custom tokio runtime to run the server on.
211    pub(crate) tokio_runtime: Option<tokio::runtime::Handle>,
212    /// Enable HTTP.
213    pub(crate) enable_http: bool,
214    /// Enable WS.
215    pub(crate) enable_ws: bool,
216    /// Number of messages that server is allowed to `buffer` until backpressure kicks in.
217    pub(crate) message_buffer_capacity: u32,
218    /// ID provider.
219    pub(crate) id_provider: Arc<dyn IdProvider>,
220    /// Timeout for receiving the first request of a connection.
221    pub(crate) first_request_timeout: Option<Duration>,
222    /// Timeout for writing a single message to a WebSocket connection and for a stalled HTTP
223    /// response write.
224    pub(crate) write_timeout: Duration,
225}
226
227/// The builder to configure and create a JSON-RPC server configuration.
228#[derive(Debug, Clone)]
229pub struct ServerConfigBuilder(ServerConfig);
230
231/// Configuration for batch request handling.
232#[derive(Debug, Copy, Clone)]
233pub enum BatchRequestConfig {
234    /// Batch requests are disabled.
235    Disabled,
236    /// Each batch request is limited to `len` and any batch request bigger than `len` will not be
237    /// processed.
238    Limit(u32),
239    /// The batch request is unlimited.
240    Unlimited,
241}
242
243/// Connection related state that is needed
244/// to execute JSON-RPC calls.
245#[derive(Debug, Clone)]
246pub struct ConnectionState {
247    /// Stop handle.
248    pub(crate) stop_handle: StopHandle,
249    /// Connection ID
250    pub(crate) conn_id: usize,
251    /// Connection guard.
252    pub(crate) _conn_permit: Arc<OwnedSemaphorePermit>,
253}
254
255impl ConnectionState {
256    /// Create a new connection state.
257    pub fn new(
258        stop_handle: StopHandle,
259        conn_id: usize,
260        conn_permit: OwnedSemaphorePermit,
261    ) -> ConnectionState {
262        Self { stop_handle, conn_id, _conn_permit: Arc::new(conn_permit) }
263    }
264}
265
266impl Default for ServerConfig {
267    fn default() -> Self {
268        ServerConfig::builder().build()
269    }
270}
271
272impl ServerConfig {
273    /// Create a new builder for the [`ServerConfig`].
274    pub fn builder() -> ServerConfigBuilder {
275        ServerConfigBuilder::default()
276    }
277}
278
279impl Default for ServerConfigBuilder {
280    fn default() -> Self {
281        Self(ServerConfig {
282            max_request_body_size: TEN_MB_SIZE_BYTES,
283            max_response_body_size: TEN_MB_SIZE_BYTES,
284            max_connections: MAX_CONNECTIONS,
285            max_subscriptions_per_connection: 1024,
286            batch_requests_config: BatchRequestConfig::Unlimited,
287            tokio_runtime: None,
288            enable_http: true,
289            enable_ws: true,
290            message_buffer_capacity: 1024,
291            id_provider: Arc::new(RandomIntegerIdProvider),
292            first_request_timeout: Some(DEFAULT_FIRST_REQUEST_TIMEOUT),
293            write_timeout: DEFAULT_WRITE_TIMEOUT,
294        })
295    }
296}
297
298impl ServerConfigBuilder {
299    /// Create a new [`ServerConfigBuilder`].
300    pub fn new() -> Self {
301        Self::default()
302    }
303
304    /// Set the maximum size of a request body in bytes. Default is 10 MiB.
305    pub fn max_request_body_size(mut self, size: u32) -> Self {
306        self.0.max_request_body_size = size;
307        self
308    }
309
310    /// Set the maximum size of a response body in bytes. Default is 10 MiB.
311    pub fn max_response_body_size(mut self, size: u32) -> Self {
312        self.0.max_response_body_size = size;
313        self
314    }
315
316    /// Set the maximum number of connections allowed. Default is 100.
317    pub fn max_connections(mut self, max: u32) -> Self {
318        self.0.max_connections = max;
319        self
320    }
321
322    /// Set the maximum number of subscriptions per connection. Default is 1024.
323    pub fn max_subscriptions_per_connection(mut self, max: u32) -> Self {
324        self.0.max_subscriptions_per_connection = max;
325        self
326    }
327
328    /// Configure how [batch requests](https://www.jsonrpc.org/specification#batch) shall be handled
329    /// by the server.
330    ///
331    /// Default: batch requests are allowed and can be arbitrary big but the maximum payload size is
332    /// limited.
333    pub fn set_batch_request_config(mut self, cfg: BatchRequestConfig) -> Self {
334        self.0.batch_requests_config = cfg;
335        self
336    }
337
338    /// Configure a custom [`tokio::runtime::Handle`] to run the server on.
339    ///
340    /// Default: [`tokio::spawn`]
341    pub fn custom_tokio_runtime(mut self, rt: tokio::runtime::Handle) -> Self {
342        self.0.tokio_runtime = Some(rt);
343        self
344    }
345
346    /// Configure the server to only serve JSON-RPC HTTP requests.
347    ///
348    /// Default: both http and ws are enabled.
349    pub fn http_only(mut self) -> Self {
350        self.0.enable_http = true;
351        self.0.enable_ws = false;
352        self
353    }
354
355    /// Configure the server to only serve JSON-RPC WebSocket requests.
356    ///
357    /// That implies that server just denies HTTP requests which isn't a WebSocket upgrade request
358    ///
359    /// Default: both http and ws are enabled.
360    pub fn ws_only(mut self) -> Self {
361        self.0.enable_http = false;
362        self.0.enable_ws = true;
363        self
364    }
365
366    /// The server enforces backpressure which means that
367    /// `n` messages can be buffered and if the client
368    /// can't keep with up the server.
369    ///
370    /// This `capacity` is applied per connection and
371    /// applies globally on the connection which implies
372    /// all JSON-RPC messages.
373    ///
374    /// It is the number of messages (responses and subscription notifications) that can wait to
375    /// be written to the client, and also the most calls a WebSocket connection runs at once.
376    ///
377    /// For example if a subscription produces plenty of new items
378    /// and the client can't keep up then no new messages are handled.
379    ///
380    /// If the client can't keep up then calls wait to queue their response. Once that many calls
381    /// are running, the server stops reading new messages from the connection until one
382    /// completes.
383    ///
384    /// # Panics
385    ///
386    /// Panics if the buffer capacity is 0.
387    pub fn set_message_buffer_capacity(mut self, c: u32) -> Self {
388        assert!(c > 0, "buffer capacity must be set to > 0");
389        self.0.message_buffer_capacity = c;
390        self
391    }
392
393    /// Configure custom `subscription ID` provider for the server to use
394    /// to when getting new subscription calls.
395    ///
396    /// You may choose static dispatch or dynamic dispatch because
397    /// `IdProvider` is implemented for `Box<T>`.
398    ///
399    /// Default: [`RandomIntegerIdProvider`].
400    ///
401    /// # Examples
402    ///
403    /// ```rust
404    /// use jsonrpsee_server::{IdProvider, RandomStringIdProvider, ServerConfigBuilder};
405    ///
406    /// // static dispatch
407    /// let builder1 = ServerConfigBuilder::default().set_id_provider(RandomStringIdProvider::new(16));
408    ///
409    /// // or dynamic dispatch
410    /// let builder2 =
411    ///     ServerConfigBuilder::default().set_id_provider(Box::new(RandomStringIdProvider::new(16)));
412    /// ```
413    pub fn set_id_provider<I: IdProvider + 'static>(mut self, id_provider: I) -> Self {
414        self.0.id_provider = Arc::new(id_provider);
415        self
416    }
417
418    /// Configure how long a connection may take to send its first request, e.g. the WebSocket
419    /// upgrade request, before it is closed. `None` disables the timeout.
420    ///
421    /// Default is 30 seconds.
422    pub fn set_first_request_timeout(mut self, first_request_timeout: Option<Duration>) -> Self {
423        self.0.first_request_timeout = first_request_timeout;
424        self
425    }
426
427    /// Configure how long writing a single message, ping or close frame to a WebSocket
428    /// connection may take, and how long an HTTP response write may make no progress, before the
429    /// connection is closed.
430    ///
431    /// A client that stops reading fills the socket's send buffer, which blocks the write. When
432    /// the timeout expires, the connection is dropped together with its queued messages,
433    /// subscriptions and pending calls, or with its buffered HTTP response.
434    ///
435    /// Default is 10 seconds.
436    pub fn set_write_timeout(mut self, write_timeout: Duration) -> Self {
437        self.0.write_timeout = write_timeout;
438        self
439    }
440
441    /// Build the [`ServerConfig`].
442    pub fn build(self) -> ServerConfig {
443        self.0
444    }
445}
446
447/// Builder to configure and create a JSON-RPC server.
448#[derive(Debug)]
449pub struct Builder<HttpMiddleware, RpcMiddleware> {
450    server_cfg: ServerConfig,
451    rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
452    http_middleware: tower::ServiceBuilder<HttpMiddleware>,
453}
454
455impl Default for Builder<Identity, Identity> {
456    fn default() -> Self {
457        Builder {
458            server_cfg: ServerConfig::default(),
459            rpc_middleware: RpcServiceBuilder::new(),
460            http_middleware: tower::ServiceBuilder::new(),
461        }
462    }
463}
464
465impl Builder<Identity, Identity> {
466    /// Create a default server builder.
467    pub fn new() -> Self {
468        Self::default()
469    }
470
471    /// Create a server builder with the given [`ServerConfig`].
472    pub fn with_config(config: ServerConfig) -> Self {
473        Self { server_cfg: config, ..Default::default() }
474    }
475}
476
477impl<HttpMiddleware, RpcMiddleware> Builder<HttpMiddleware, RpcMiddleware> {
478    /// Configure the [`ServerConfig`].
479    pub fn set_config(mut self, cfg: ServerConfig) -> Self {
480        self.server_cfg = cfg;
481        self
482    }
483
484    /// Enable middleware that is invoked on every JSON-RPC call.
485    ///
486    /// The middleware itself is very similar to the `tower middleware` but
487    /// it has a different service trait which takes &self instead &mut self
488    /// which means that you can't use built-in middleware from tower.
489    ///
490    /// Another consequence of `&self` is that you must wrap any of the middleware state in
491    /// a type which is Send and provides interior mutability such as `Arc<Mutex>`.
492    ///
493    /// The builder itself exposes a similar API as the [`tower::ServiceBuilder`]
494    /// where it is possible to compose layers to the middleware.
495    ///
496    /// To add middleware [`RpcServiceBuilder`] exposes a few different layer APIs that
497    /// are wrapped on top of the [`tower::ServiceBuilder`].
498    ///
499    /// When the server is started these layers are wrapped in the [`RpcService`] and
500    /// that's why the service APIs is not exposed.
501    /// ```
502    /// use std::{
503    ///     net::SocketAddr,
504    ///     sync::{
505    ///         atomic::{AtomicUsize, Ordering},
506    ///         Arc,
507    ///     },
508    ///     time::Instant,
509    /// };
510    ///
511    /// use jsonrpsee_server::{
512    ///     middleware::rpc::{
513    ///         Batch, MethodResponse, Notification, Request, RpcService, RpcServiceBuilder,
514    ///         RpcServiceT,
515    ///     },
516    ///     ServerBuilder,
517    /// };
518    ///
519    /// #[derive(Clone)]
520    /// struct MyMiddleware<S> {
521    ///     service: S,
522    ///     count: Arc<AtomicUsize>,
523    /// }
524    ///
525    /// impl<S> RpcServiceT for MyMiddleware<S>
526    /// where
527    ///     S: RpcServiceT + Clone + Send + Sync + 'static,
528    /// {
529    ///     fn call<'a>(&self, req: Request<'a>) -> impl Future<Output = MethodResponse> + Send + 'a {
530    ///         tracing::info!("MyMiddleware processed call {}", req.method);
531    ///         let count = self.count.clone();
532    ///         let service = self.service.clone();
533    ///
534    ///         async move {
535    ///             let rp = service.call(req).await;
536    ///             // Modify the state.
537    ///             count.fetch_add(1, Ordering::Relaxed);
538    ///             rp
539    ///         }
540    ///     }
541    ///
542    ///     fn batch<'a>(&self, batch: Batch<'a>) -> impl Future<Output = MethodResponse> + Send + 'a {
543    ///         self.service.batch(batch)
544    ///     }
545    ///
546    ///     fn notification<'a>(
547    ///         &self,
548    ///         notif: Notification<'a>,
549    ///     ) -> impl Future<Output = MethodResponse> + Send + 'a {
550    ///         self.service.notification(notif)
551    ///     }
552    /// }
553    ///
554    /// // Create a state per connection
555    /// // NOTE: The service type can be omitted once `start` is called on the server.
556    /// let m = RpcServiceBuilder::new().layer_fn(move |service: ()| MyMiddleware {
557    ///     service,
558    ///     count: Arc::new(AtomicUsize::new(0)),
559    /// });
560    /// let builder = ServerBuilder::default().set_rpc_middleware(m);
561    /// ```
562    pub fn set_rpc_middleware<T>(
563        self,
564        rpc_middleware: RpcServiceBuilder<T>,
565    ) -> Builder<HttpMiddleware, T> {
566        Builder {
567            server_cfg: self.server_cfg,
568            rpc_middleware,
569            http_middleware: self.http_middleware,
570        }
571    }
572
573    /// Configure a custom [`tower::ServiceBuilder`] middleware for composing layers to be applied
574    /// to the RPC service.
575    ///
576    /// Default: No tower layers are applied to the RPC service.
577    ///
578    /// # Examples
579    ///
580    /// ```rust
581    /// use std::{net::SocketAddr, time::Duration};
582    ///
583    /// #[tokio::main]
584    /// async fn main() {
585    ///     let builder = tower::ServiceBuilder::new().timeout(Duration::from_secs(2));
586    ///
587    ///     let server = jsonrpsee_server::ServerBuilder::new()
588    ///         .set_http_middleware(builder)
589    ///         .build("127.0.0.1:0".parse::<SocketAddr>().unwrap())
590    ///         .await
591    ///         .unwrap();
592    /// }
593    /// ```
594    pub fn set_http_middleware<T>(
595        self,
596        http_middleware: tower::ServiceBuilder<T>,
597    ) -> Builder<T, RpcMiddleware> {
598        Builder {
599            server_cfg: self.server_cfg,
600            http_middleware,
601            rpc_middleware: self.rpc_middleware,
602        }
603    }
604
605    /// Finalize the configuration of the server. Consumes the [`Builder`].
606    ///
607    /// ```rust
608    /// #[tokio::main]
609    /// async fn main() {
610    ///     let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
611    ///     let occupied_addr = listener.local_addr().unwrap();
612    ///     let addrs: &[std::net::SocketAddr] = &[occupied_addr, "127.0.0.1:0".parse().unwrap()];
613    ///     assert!(jsonrpsee_server::ServerBuilder::default().build(occupied_addr).await.is_err());
614    ///     assert!(jsonrpsee_server::ServerBuilder::default().build(addrs).await.is_ok());
615    /// }
616    /// ```
617    pub async fn build(
618        self,
619        addrs: impl ToSocketAddrs,
620    ) -> std::io::Result<Server<HttpMiddleware, RpcMiddleware>> {
621        let listener = TcpListener::bind(addrs).await?;
622
623        Ok(Server {
624            listener,
625            server_cfg: self.server_cfg,
626            rpc_middleware: self.rpc_middleware,
627            http_middleware: self.http_middleware,
628        })
629    }
630}
631
632/// Data required by the server to handle requests.
633#[derive(Debug, Clone)]
634struct ServiceData {
635    /// Registered server methods.
636    methods: Methods,
637    /// Stop handle.
638    stop_handle: StopHandle,
639    /// Connection ID
640    conn_id: usize,
641    /// Connection guard.
642    conn_guard: ConnectionGuard,
643    /// ServerConfig
644    server_cfg: ServerConfig,
645}
646
647/// jsonrpsee tower service without HTTP specific middleware.
648///
649/// # Note
650/// This is similar to [`hyper::service::service_fn`].
651#[derive(Debug, Clone)]
652pub struct TowerServiceNoHttp<L> {
653    inner: ServiceData,
654    rpc_middleware: RpcServiceBuilder<L>,
655}
656
657impl<Body, RpcMiddleware> Service<HttpRequest<Body>> for TowerServiceNoHttp<RpcMiddleware>
658where
659    RpcMiddleware: Layer<RpcService>,
660    <RpcMiddleware as Layer<RpcService>>::Service: RpcServiceT + Send + Sync + 'static,
661    Body: http_body::Body<Data = Bytes> + Send + 'static,
662    <Body as http_body::Body>::Error: Into<BoxError>,
663{
664    type Response = HttpResponse;
665
666    // The following associated type is required by the `impl<B, U, M: JsonRpcMiddleware> Server<B,
667    // L>` bounds. It satisfies the server's bounds when the `tower::ServiceBuilder<B>` is not
668    // set (ie `B: Identity`).
669    type Error = BoxError;
670
671    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
672
673    fn poll_ready(&mut self, _cx: &mut std::task::Context<'_>) -> Poll<Result<(), Self::Error>> {
674        Poll::Ready(Ok(()))
675    }
676
677    fn call(&mut self, request: HttpRequest<Body>) -> Self::Future {
678        let request = request.map(HttpBody::new);
679
680        let conn_guard = &self.inner.conn_guard;
681        let stop_handle = self.inner.stop_handle.clone();
682        let conn_id = self.inner.conn_id;
683
684        tracing::trace!(target: LOG_TARGET, "{:?}", request);
685
686        let Some(conn_permit) = conn_guard.try_acquire() else {
687            return async move { Ok(http::response::too_many_requests()) }.boxed();
688        };
689
690        let conn = ConnectionState::new(stop_handle.clone(), conn_id, conn_permit);
691
692        let max_conns = conn_guard.max_connections();
693        let curr_conns = max_conns - conn_guard.available_connections();
694        tracing::debug!(target: LOG_TARGET, "Accepting new connection {}/{}", curr_conns, max_conns);
695
696        let is_upgrade_request = is_upgrade_request(&request);
697
698        if self.inner.server_cfg.enable_ws && is_upgrade_request {
699            let this = self.inner.clone();
700
701            let mut server = soketto::handshake::http::Server::new();
702
703            let response = match server.receive_request(&request) {
704                Ok(response) => {
705                    let (tx, rx) = mpsc::channel(this.server_cfg.message_buffer_capacity as usize);
706                    let sink =
707                        MethodSink::new_with_limit(tx, this.server_cfg.max_response_body_size);
708
709                    // On each method call the `pending_calls` is cloned
710                    // then when all pending_calls are dropped
711                    // a graceful shutdown can occur.
712                    let (pending_calls, pending_calls_completed) = mpsc::channel::<()>(1);
713
714                    let rpc_service = RpcService::new(
715                        this.methods.clone(),
716                        this.server_cfg.max_response_body_size as usize,
717                        this.conn_id.into(),
718                        BoundedSubscriptions::new(this.server_cfg.max_subscriptions_per_connection),
719                        sink.clone(),
720                        this.server_cfg.id_provider.clone(),
721                    );
722
723                    let rpc_service = self.rpc_middleware.service(rpc_service);
724
725                    tokio::spawn(
726                        async move {
727                            let upgraded = match hyper::upgrade::on(request).await {
728                                Ok(u) => u,
729                                Err(e) => {
730                                    tracing::debug!(target: LOG_TARGET, "Could not upgrade connection: {}", e);
731                                    return;
732                                }
733                            };
734
735                            let io = TokioIo::new(upgraded);
736
737                            let stream = BufReader::new(BufWriter::new(io.compat()));
738                            let mut ws_builder = server.into_builder(stream);
739                            ws_builder.set_max_message_size(this.server_cfg.max_request_body_size as usize);
740                            let (sender, receiver) = ws_builder.finish();
741
742                            let params = BackgroundTaskParams {
743                                server_cfg: this.server_cfg,
744                                conn,
745                                ws_sender: sender,
746                                ws_receiver: receiver,
747                                rpc_service,
748                                sink,
749                                rx,
750                                pending_calls,
751                                pending_calls_completed,
752                            };
753
754                            ws::background_task(params).await;
755                        }
756                        .in_current_span(),
757                    );
758
759                    response.map(|()| HttpBody::empty())
760                }
761                Err(e) => {
762                    tracing::debug!(target: LOG_TARGET, "Could not upgrade connection: {}", e);
763                    HttpResponse::new(HttpBody::from(format!("Could not upgrade connection: {e}")))
764                }
765            };
766
767            async { Ok(response) }.boxed()
768        } else if self.inner.server_cfg.enable_http && !is_upgrade_request {
769            let this = &self.inner;
770            let max_response_size = this.server_cfg.max_response_body_size;
771            let max_request_size = this.server_cfg.max_request_body_size;
772            let methods = this.methods.clone();
773            let batch_config = this.server_cfg.batch_requests_config;
774
775            let rpc_service = self.rpc_middleware.service(RpcService::without_subscriptions(
776                methods,
777                max_response_size as usize,
778                this.conn_id.into(),
779            ));
780
781            Box::pin(async move {
782                let rp =
783                    http::call_with_service(request, batch_config, max_request_size, rpc_service)
784                        .await;
785                // NOTE: The `conn guard` must be held until the response body is written (or
786                // dropped) to respect the `max_connections` limit, because hyper writes the body
787                // after this future completes.
788                Ok(rp.map(|body| HttpBody::new(PermitBody::new(body, conn))))
789            })
790        } else {
791            // NOTE: the `conn guard` is dropped when this function which is fine
792            // because it doesn't rely on any async operations.
793            Box::pin(async { Ok(http::response::denied()) })
794        }
795    }
796}
797
798struct ProcessConnection<'a, HttpMiddleware, RpcMiddleware> {
799    http_middleware: &'a tower::ServiceBuilder<HttpMiddleware>,
800    rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
801    conn_guard: &'a ConnectionGuard,
802    conn_id: usize,
803    server_cfg: ServerConfig,
804    stop_handle: StopHandle,
805    socket: TcpStream,
806    drop_on_completion: mpsc::Sender<()>,
807    remote_addr: SocketAddr,
808    methods: Methods,
809}
810
811#[instrument(name = "connection", target = LOG_TARGET, skip_all, fields(remote_addr = %params.remote_addr, conn_id = %params.conn_id), level = "INFO")]
812fn process_connection<RpcMiddleware, HttpMiddleware, Body>(
813    params: ProcessConnection<HttpMiddleware, RpcMiddleware>,
814) where
815    HttpMiddleware: Layer<TowerServiceNoHttp<RpcMiddleware>> + Send + 'static,
816    <HttpMiddleware as Layer<TowerServiceNoHttp<RpcMiddleware>>>::Service: Service<HttpRequest, Response = HttpResponse<Body>, Error = BoxError>
817        + Clone
818        + Send
819        + 'static,
820    <<HttpMiddleware as Layer<TowerServiceNoHttp<RpcMiddleware>>>::Service as Service<
821        HttpRequest,
822    >>::Future: Send + 'static,
823    Body: http_body::Body<Data = Bytes> + Send + 'static,
824    <Body as http_body::Body>::Error: Into<BoxError>,
825{
826    let ProcessConnection {
827        http_middleware,
828        rpc_middleware,
829        conn_guard,
830        conn_id,
831        server_cfg,
832        socket,
833        stop_handle,
834        drop_on_completion,
835        methods,
836        ..
837    } = params;
838
839    if let Err(e) = socket.set_nodelay(true) {
840        tracing::warn!(target: LOG_TARGET, "Could not set NODELAY on socket: {:?}", e);
841        return;
842    }
843
844    let first_request_timeout = server_cfg.first_request_timeout;
845    let write_timeout = server_cfg.write_timeout;
846
847    let tower_service = TowerServiceNoHttp {
848        inner: ServiceData {
849            server_cfg,
850            methods,
851            stop_handle: stop_handle.clone(),
852            conn_id,
853            conn_guard: conn_guard.clone(),
854        },
855        rpc_middleware,
856    };
857
858    let service = http_middleware.service(tower_service);
859
860    let serve = async move {
861        let request_received = Arc::new(Notify::new());
862        // this requires Clone.
863        let service = NotifyOnRequest::new(
864            TowerToHyperService::new(
865                service.map_request(|request: HttpRequest<Incoming>| request.map(HttpBody::new)),
866            ),
867            request_received.clone(),
868        );
869        let io = TokioIo::new(WriteTimeoutIo::new(socket, write_timeout));
870        let builder = hyper_util::server::conn::auto::Builder::new(TokioExecutor::new());
871        let conn = builder.serve_connection_with_upgrades(io, service);
872        let stopped = stop_handle.shutdown();
873
874        tokio::pin!(stopped, conn);
875
876        let res = tokio::select! {
877            res = &mut conn => res,
878            _ = &mut stopped => {
879                // NOTE: the connection should continue to be polled until shutdown can finish.
880                // Thus, both lines below are needed and not a nit.
881                conn.as_mut().graceful_shutdown();
882                conn.await
883            }
884            err = no_request_within(&request_received, first_request_timeout) => Err(err),
885        };
886
887        if let Err(e) = res {
888            tracing::debug!(target: LOG_TARGET, "HTTP serve connection failed {:?}", e);
889        }
890        drop(drop_on_completion)
891    };
892    // `#[instrument]` only spans this function, so the connection span is carried into the task.
893    tokio::spawn(serve.in_current_span());
894}
895
896enum AcceptConnection<S> {
897    Shutdown,
898    Established { socket: TcpStream, remote_addr: SocketAddr, stop: S },
899    Err((std::io::Error, S)),
900}
901
902async fn try_accept_conn<S>(listener: &TcpListener, stopped: S) -> AcceptConnection<S>
903where
904    S: Future + Unpin,
905{
906    let accept = listener.accept();
907    tokio::pin!(accept);
908
909    // `select` polls its first argument first and returns as soon as that one is ready, so the
910    // stop signal has to come first: with `accept` first, a listener that keeps returning without
911    // ever pending starves the stop signal and the server can no longer be stopped.
912    match futures_util::future::select(stopped, accept).await {
913        Either::Left(_) => AcceptConnection::Shutdown,
914        Either::Right((res, stop)) => match res {
915            Ok((socket, remote_addr)) => {
916                AcceptConnection::Established { socket, remote_addr, stop }
917            }
918            Err(e) => AcceptConnection::Err((e, stop)),
919        },
920    }
921}
922
923/// Parses `body` as a single JSON-RPC message (`is_single`) or a batch, dispatches it to
924/// `rpc_service` and returns the serialized response.
925///
926/// A panicking call is answered with an internal error. The caller sends the response only if it
927/// [is a method call](MethodResponse::is_method_call) or [a batch](MethodResponse::is_batch):
928/// notifications are not answered and subscription calls answer through the subscription sink.
929pub async fn handle_rpc_call<S>(
930    body: &[u8],
931    is_single: bool,
932    batch_config: BatchRequestConfig,
933    rpc_service: &S,
934) -> MethodResponse
935where
936    S: RpcServiceT + Send,
937{
938    // Single request or notification
939    if is_single {
940        if let Ok(req) = serde_json::from_slice::<Request<'_>>(body) {
941            catch_call_panic(req.id(), || rpc_service.call(req)).await
942        } else if let Ok(notif) = deserialize_notification(body) {
943            rpc_service.notification(notif).await
944        } else {
945            let (id, code) = prepare_error(body);
946            MethodResponse::error(id, ErrorObject::from(code))
947        }
948    }
949    // Batch of requests.
950    else {
951        let max_len = match batch_config {
952            BatchRequestConfig::Disabled => {
953                let rp = MethodResponse::error(
954                    Id::Null,
955                    ErrorObject::borrowed(
956                        BATCHES_NOT_SUPPORTED_CODE,
957                        BATCHES_NOT_SUPPORTED_MSG,
958                        None,
959                    ),
960                );
961                return rp;
962            }
963            BatchRequestConfig::Limit(limit) => limit as usize,
964            BatchRequestConfig::Unlimited => usize::MAX,
965        };
966
967        match parse_batch(body, max_len) {
968            Ok(batch) => rpc_service.batch(batch).await,
969            Err(rp) => rp,
970        }
971    }
972}
973
974/// Reads `body` as a batch of at most `max_len` entries, or returns the response to a batch that
975/// can't be read.
976fn parse_batch(body: &[u8], max_len: usize) -> Result<Batch<'_>, MethodResponse> {
977    let mut entries = Vec::new();
978    let mut too_big = false;
979
980    // Most batches hold only valid requests, so the entries are decoded as they are read. Once an
981    // entry doesn't decode, the batch is read again from that entry on, classifying each raw entry
982    // to answer the invalid ones in place.
983    for raw in [false, true] {
984        let mut deserializer = serde_json::Deserializer::from_slice(body);
985        let read = BatchSeed { max_len, too_big: &mut too_big, entries: &mut entries, raw }
986            .deserialize(&mut deserializer)
987            .and_then(|()| deserializer.end());
988
989        if read.is_ok() {
990            return Ok(Batch::from(entries));
991        }
992        // The seed stops reading as soon as the batch exceeds the limit, which surfaces as a
993        // deserialization error.
994        if too_big {
995            return Err(MethodResponse::error(Id::Null, reject_too_big_batch_request(max_len)));
996        }
997    }
998
999    Err(MethodResponse::error(Id::Null, ErrorObject::from(ErrorCode::ParseError)))
1000}
1001
1002/// Classifies a raw batch entry as a call, a notification or an invalid request.
1003fn parse_batch_entry(call: &JsonRawValue) -> Result<BatchEntry<'_>, BatchEntryErr<'_>> {
1004    // The derived `Deserialize` impls below also accept a JSON array holding the fields in
1005    // order, so only objects may reach them.
1006    if !call.get().starts_with('{') {
1007        return Err(BatchEntryErr::new(Id::Null, ErrorCode::InvalidRequest.into()));
1008    }
1009
1010    if let Ok(req) = serde_json::from_str(call.get()) {
1011        Ok(BatchEntry::Call(req))
1012    } else if let Ok(notif) = deserialize_notification(call.get().as_bytes()) {
1013        Ok(BatchEntry::Notification(notif))
1014    } else {
1015        let id = match serde_json::from_str::<jsonrpsee_types::InvalidRequest>(call.get()) {
1016            Ok(err) => err.id,
1017            Err(_) => Id::Null,
1018        };
1019
1020        Err(BatchEntryErr::new(id, ErrorCode::InvalidRequest.into()))
1021    }
1022}
1023
1024/// A valid batch entry: a call if it has an `id`, a notification otherwise.
1025///
1026/// Unknown members use the raw pass, which validates UTF-8 even in ignored values.
1027#[derive(Deserialize)]
1028#[serde(deny_unknown_fields)]
1029struct ValidBatchEntry<'a> {
1030    jsonrpc: TwoPointZero,
1031    #[serde(borrow, default, deserialize_with = "deserialize_present_id")]
1032    id: Option<Id<'a>>,
1033    #[serde(borrow)]
1034    method: Cow<'a, str>,
1035    #[serde(borrow)]
1036    params: Option<&'a JsonRawValue>,
1037}
1038
1039impl<'a> From<ValidBatchEntry<'a>> for BatchEntry<'a> {
1040    fn from(entry: ValidBatchEntry<'a>) -> Self {
1041        let ValidBatchEntry { jsonrpc, id, method, params } = entry;
1042        let params = params.map(Cow::Borrowed);
1043        match id {
1044            Some(id) => Self::Call(Request { jsonrpc, id, method, params }),
1045            None => Self::Notification(Notification::new(method, params)),
1046        }
1047    }
1048}
1049
1050/// Only runs for an `id` that is present, so `null` is an id and not a missing one.
1051fn deserialize_present_id<'de, D: Deserializer<'de>>(
1052    deserializer: D,
1053) -> Result<Option<Id<'de>>, D::Error> {
1054    Id::deserialize(deserializer).map(Some)
1055}
1056
1057/// Decodes a [`ValidBatchEntry`] from a JSON object only, because its derived `Deserialize` impl
1058/// also accepts a JSON array holding the fields in order.
1059struct ValidBatchEntrySeed;
1060
1061impl<'de> DeserializeSeed<'de> for ValidBatchEntrySeed {
1062    type Value = ValidBatchEntry<'de>;
1063
1064    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
1065        deserializer.deserialize_map(self)
1066    }
1067}
1068
1069impl<'de> Visitor<'de> for ValidBatchEntrySeed {
1070    type Value = ValidBatchEntry<'de>;
1071
1072    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1073        formatter.write_str("a JSON-RPC request object")
1074    }
1075
1076    fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
1077        ValidBatchEntry::deserialize(MapAccessDeserializer::new(map))
1078    }
1079}
1080
1081/// Reads a JSON array of batch entries into `entries`.
1082///
1083/// Entries are decoded as they are read, or, if `raw`, classified from their raw JSON, after
1084/// skipping the entries that `entries` already holds.
1085///
1086/// Stops with an error as soon as an entry beyond `max_len` is read and sets `too_big`, so an
1087/// oversized batch is never collected.
1088struct BatchSeed<'a, 'de> {
1089    max_len: usize,
1090    too_big: &'a mut bool,
1091    entries: &'a mut Vec<Result<BatchEntry<'de>, BatchEntryErr<'de>>>,
1092    raw: bool,
1093}
1094
1095impl<'de> DeserializeSeed<'de> for BatchSeed<'_, 'de> {
1096    type Value = ();
1097
1098    fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
1099        deserializer.deserialize_seq(self)
1100    }
1101}
1102
1103impl<'de> Visitor<'de> for BatchSeed<'_, 'de> {
1104    type Value = ();
1105
1106    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1107        formatter.write_str("a batch of JSON-RPC requests")
1108    }
1109
1110    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
1111        if self.raw {
1112            for _ in 0..self.entries.len() {
1113                seq.next_element::<IgnoredAny>()?;
1114            }
1115        }
1116
1117        loop {
1118            if self.entries.len() == self.max_len {
1119                // Read the excess entry without decoding or allocating its fields.
1120                if seq.next_element::<&'de JsonRawValue>()?.is_some() {
1121                    *self.too_big = true;
1122                    return Err(A::Error::custom("batch too big"));
1123                }
1124                return Ok(());
1125            }
1126
1127            let entry = if self.raw {
1128                seq.next_element::<&'de JsonRawValue>()?.map(parse_batch_entry)
1129            } else {
1130                seq.next_element_seed(ValidBatchEntrySeed)?.map(|entry| Ok(entry.into()))
1131            };
1132            let Some(entry) = entry else { return Ok(()) };
1133
1134            // Not preallocated from the size hint, which the input controls.
1135            self.entries.push(entry);
1136        }
1137    }
1138}
1139
1140#[cfg(test)]
1141mod tests {
1142    use super::*;
1143    use futures_util::future;
1144    use test_case::test_case;
1145
1146    const CALL: &str = r#"{"jsonrpc":"2.0","method":"m","params":[1],"id":1}"#;
1147
1148    const NOTIFICATION: &str = r#"{"jsonrpc":"2.0","method":"m"}"#;
1149
1150    /// Classifies every entry of `body` from its raw JSON.
1151    fn classify_raw_batch(body: &str, max_len: usize) -> Option<String> {
1152        let (mut entries, mut too_big) = (Vec::new(), false);
1153        let mut deserializer = serde_json::Deserializer::from_str(body);
1154        BatchSeed { max_len, too_big: &mut too_big, entries: &mut entries, raw: true }
1155            .deserialize(&mut deserializer)
1156            .and_then(|()| deserializer.end())
1157            .ok()
1158            .map(|()| format!("{entries:?}"))
1159    }
1160
1161    #[tokio::test]
1162    async fn try_accept_conn_observes_stop_before_a_waiting_connection() {
1163        let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
1164        let addr = listener.local_addr().unwrap();
1165
1166        let _client = TcpStream::connect(addr).await.unwrap();
1167        // Let the kernel put the connection in the backlog, so that `accept` would hand it over on
1168        // its first poll and only the polling order keeps it waiting.
1169        tokio::time::sleep(Duration::from_millis(50)).await;
1170
1171        let accepted = try_accept_conn(&listener, future::ready(())).await;
1172        assert!(matches!(accepted, AcceptConnection::Shutdown));
1173    }
1174
1175    #[test_case(&[CALL, CALL], usize::MAX; "calls")]
1176    #[test_case(&[CALL, NOTIFICATION, r#"{"jsonrpc":"2.0","method":"m","id":null}"#], usize::MAX; "call, notification and null id")]
1177    #[test_case(&[r#"{"id":"a","params":null,"method":"\"m\"","x":1,"jsonrpc":"2.0"}"#], usize::MAX; "escaped method, null params and unknown member")]
1178    #[test_case(&[CALL, r#"{"jsonrpc":"2.0","id":2}"#, NOTIFICATION, CALL], usize::MAX; "missing method between valid entries")]
1179    #[test_case(&[r#"{"jsonrpc":"1.0","method":"m","id":3}"#, CALL], usize::MAX; "wrong version first")]
1180    #[test_case(&[CALL, r#"{"jsonrpc":"2.0","method":"m","id":{}}"#], usize::MAX; "object id")]
1181    #[test_case(&[CALL, r#"{"jsonrpc":"2.0","method":"m","id":1,"id":2}"#], usize::MAX; "duplicate id")]
1182    #[test_case(&[CALL, r#"["2.0",2,"m",[]]"#, "7", CALL], usize::MAX; "array and number entries")]
1183    #[test_case(&[CALL, r#"{"id":2}"#], 2; "invalid entry at the limit")]
1184    #[test_case(&[CALL, r#"{"id":2}"#, CALL], 2; "valid entry past the limit")]
1185    #[test_case(&[CALL, CALL, r#"{"id":2}"#], 2; "invalid entry past the limit")]
1186    #[test_case(&[CALL, r#"{"jsonrpc""#], usize::MAX; "not json")]
1187    fn batch_entries_decode_like_their_raw_json(entries: &[&str], max_len: usize) {
1188        let body = format!("[{}]", entries.join(","));
1189        let batch = parse_batch(body.as_bytes(), max_len)
1190            .ok()
1191            .map(|batch| format!("{:?}", batch.into_iter().collect::<Vec<_>>()));
1192        assert_eq!(batch, classify_raw_batch(&body, max_len));
1193    }
1194
1195    #[test]
1196    fn batch_with_invalid_utf8_is_a_parse_error() {
1197        // Unknown members must still be validated as UTF-8 by the raw pass.
1198        let body = b"[{\"jsonrpc\":\"2.0\",\"method\":\"m\",\"id\":1,\"x\":\"\xff\"}]";
1199        let rp = parse_batch(body, usize::MAX).unwrap_err();
1200        assert_eq!(rp.as_error_code(), Some(ErrorCode::ParseError.code()));
1201    }
1202
1203    #[test]
1204    fn valid_batch_entries_are_calls_or_notifications() {
1205        let body = br#"[{"jsonrpc":"2.0","method":"a","id":null},{"jsonrpc":"2.0","method":"b"}]"#;
1206        let batch = parse_batch(body, usize::MAX).unwrap().into_iter().collect::<Vec<_>>();
1207        assert!(matches!(
1208            batch.as_slice(),
1209            [Ok(BatchEntry::Call(call)), Ok(BatchEntry::Notification(notification))]
1210                if call.id == Id::Null && call.method == "a" && notification.method == "b"
1211        ));
1212    }
1213
1214    #[test_case(&[CALL.as_bytes(), CALL.as_bytes(), b"\"\xff\""], 1, reject_too_big_batch_request(1); "invalid utf8 after excess call")]
1215    #[test_case(&[br#"{"id":2}"#, CALL.as_bytes(), b"\"\xff\""], 1, reject_too_big_batch_request(1); "invalid utf8 after fallback exceeds limit")]
1216    #[test_case(&[CALL.as_bytes(), b"\"\xff\""], 1, ErrorCode::ParseError.into(); "invalid utf8 in excess entry")]
1217    #[test_case(&[b"{\"jsonrpc\":\"2.0\",\"method\":\"m\",\"x\":\"\xff\"}", CALL.as_bytes()], 1, ErrorCode::ParseError.into(); "invalid utf8 before excess entry")]
1218    #[test_case(&[CALL.as_bytes(), br#"{"jsonrpc"#], 1, ErrorCode::ParseError.into(); "malformed excess entry")]
1219    #[test_case(&[CALL.as_bytes(), b"7", b"\"\xff\""], 1, reject_too_big_batch_request(1); "invalid utf8 after excess scalar")]
1220    #[test_case(&[CALL.as_bytes(), b"\"\xff\""], 0, reject_too_big_batch_request(0); "zero limit ignores tail")]
1221    fn batch_limit_preserves_parse_errors(
1222        entries: &[&[u8]],
1223        max_len: usize,
1224        expected: ErrorObject<'_>,
1225    ) {
1226        let body = [b"[".as_slice(), entries.join(b",".as_slice()).as_slice(), b"]"].concat();
1227        assert_eq!(
1228            parse_batch(&body, max_len).unwrap_err().into_json(),
1229            MethodResponse::error(Id::Null, expected).into_json()
1230        );
1231    }
1232
1233    #[test_case(b"[]", 0; "empty batch")]
1234    #[test_case(b"[{\"jsonrpc\":\"2.0\",\"method\":\"m\"}]", 1; "notification")]
1235    fn batch_at_limit_is_accepted(body: &[u8], max_len: usize) {
1236        assert_eq!(parse_batch(body, max_len).unwrap().len(), max_len);
1237    }
1238}