From 1bee42259e196c121d02a5634696241ed7b1286d Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 31 May 2024 12:00:45 +0200 Subject: [PATCH 1/4] fix: make jsonrpc field optional --- client/http-client/src/client.rs | 7 +-- core/src/client/async_client/mod.rs | 7 +-- types/src/request.rs | 92 +++++++++++++++++++---------- 3 files changed, 63 insertions(+), 43 deletions(-) diff --git a/client/http-client/src/client.rs b/client/http-client/src/client.rs index a318217db6..d62050cd38 100644 --- a/client/http-client/src/client.rs +++ b/client/http-client/src/client.rs @@ -385,12 +385,7 @@ where let mut batch_request = Vec::with_capacity(batch.len()); for ((method, params), id) in batch.into_iter().zip(id_range.clone()) { let id = self.id_manager.as_id_kind().into_id(id); - batch_request.push(RequestSer { - jsonrpc: TwoPointZero, - id, - method: method.into(), - params: params.map(StdCow::Owned), - }); + batch_request.push(RequestSer::owned(id, method, params)); } let fut = self.transport.send_and_read_body(serde_json::to_string(&batch_request).map_err(Error::ParseError)?); diff --git a/core/src/client/async_client/mod.rs b/core/src/client/async_client/mod.rs index 5b00b0dd36..2f8a46f710 100644 --- a/core/src/client/async_client/mod.rs +++ b/core/src/client/async_client/mod.rs @@ -545,12 +545,7 @@ impl ClientT for Client { let mut batches = Vec::with_capacity(batch.len()); for ((method, params), id) in batch.into_iter().zip(id_range.clone()) { let id = self.id_manager.as_id_kind().into_id(id); - batches.push(RequestSer { - jsonrpc: TwoPointZero, - id, - method: method.into(), - params: params.map(StdCow::Owned), - }); + batches.push(RequestSer::owned(id, method, params)); } let (send_back_tx, send_back_rx) = oneshot::channel(); diff --git a/types/src/request.rs b/types/src/request.rs index 6cfd8dacc8..2363943f37 100644 --- a/types/src/request.rs +++ b/types/src/request.rs @@ -42,7 +42,7 @@ use serde_json::value::RawValue; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Request<'a> { /// JSON-RPC version. - pub jsonrpc: TwoPointZero, + pub jsonrpc: Option, /// Request ID #[serde(borrow)] pub id: Id<'a>, @@ -60,7 +60,13 @@ pub struct Request<'a> { impl<'a> Request<'a> { /// Create a new [`Request`]. pub fn new(method: Cow<'a, str>, params: Option<&'a RawValue>, id: Id<'a>) -> Self { - Self { jsonrpc: TwoPointZero, id, method, params: params.map(StdCow::Borrowed), extensions: Extensions::new() } + Self { + jsonrpc: Some(TwoPointZero), + id, + method, + params: params.map(StdCow::Borrowed), + extensions: Extensions::new(), + } } /// Get the ID of the request. @@ -102,7 +108,7 @@ pub struct InvalidRequest<'a> { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Notification<'a, T> { /// JSON-RPC version. - pub jsonrpc: TwoPointZero, + pub jsonrpc: Option, /// Name of the method to be invoked. #[serde(borrow)] pub method: Cow<'a, str>, @@ -113,7 +119,7 @@ pub struct Notification<'a, T> { impl<'a, T> Notification<'a, T> { /// Create a new [`Notification`]. pub fn new(method: Cow<'a, str>, params: T) -> Self { - Self { jsonrpc: TwoPointZero, method, params } + Self { jsonrpc: Some(TwoPointZero), method, params } } } @@ -121,22 +127,22 @@ impl<'a, T> Notification<'a, T> { #[derive(Serialize, Debug, Clone)] pub struct RequestSer<'a> { /// JSON-RPC version. - pub jsonrpc: TwoPointZero, + jsonrpc: Option, /// Request ID - pub id: Id<'a>, + id: Id<'a>, /// Name of the method to be invoked. // NOTE: as this type only implements serialize `#[serde(borrow)]` is not needed. - pub method: Cow<'a, str>, + method: Cow<'a, str>, /// Parameter values of the request. #[serde(skip_serializing_if = "Option::is_none")] - pub params: Option>, + params: Option>, } impl<'a> RequestSer<'a> { /// Create a borrowed serializable JSON-RPC method call. pub fn borrowed(id: &'a Id<'a>, method: &'a impl AsRef, params: Option<&'a RawValue>) -> Self { Self { - jsonrpc: TwoPointZero, + jsonrpc: Some(TwoPointZero), id: id.clone(), method: method.as_ref().into(), params: params.map(StdCow::Borrowed), @@ -145,7 +151,7 @@ impl<'a> RequestSer<'a> { /// Create a owned serializable JSON-RPC method call. pub fn owned(id: Id<'a>, method: impl Into, params: Option>) -> Self { - Self { jsonrpc: TwoPointZero, id, method: method.into().into(), params: params.map(StdCow::Owned) } + Self { jsonrpc: Some(TwoPointZero), id, method: method.into().into(), params: params.map(StdCow::Owned) } } } @@ -153,24 +159,24 @@ impl<'a> RequestSer<'a> { #[derive(Serialize, Debug, Clone)] pub struct NotificationSer<'a> { /// JSON-RPC version. - pub jsonrpc: TwoPointZero, + jsonrpc: Option, /// Name of the method to be invoked. // NOTE: as this type only implements serialize `#[serde(borrow)]` is not needed. - pub method: Cow<'a, str>, + method: Cow<'a, str>, /// Parameter values of the request. #[serde(skip_serializing_if = "Option::is_none")] - pub params: Option>, + params: Option>, } impl<'a> NotificationSer<'a> { /// Create a borrowed serializable JSON-RPC notification. pub fn borrowed(method: &'a impl AsRef, params: Option<&'a RawValue>) -> Self { - Self { jsonrpc: TwoPointZero, method: method.as_ref().into(), params: params.map(StdCow::Borrowed) } + Self { jsonrpc: Some(TwoPointZero), method: method.as_ref().into(), params: params.map(StdCow::Borrowed) } } /// Create an owned serializable JSON-RPC notification. pub fn owned(method: impl Into, params: Option>) -> Self { - Self { jsonrpc: TwoPointZero, method: method.into().into(), params: params.map(StdCow::Owned) } + Self { jsonrpc: Some(TwoPointZero), method: method.into().into(), params: params.map(StdCow::Owned) } } } @@ -179,8 +185,14 @@ mod test { use super::{Id, InvalidRequest, Notification, NotificationSer, Request, RequestSer, StdCow, TwoPointZero}; use serde_json::value::RawValue; - fn assert_request<'a>(request: Request<'a>, id: Id<'a>, method: &str, params: Option<&str>) { - assert_eq!(request.jsonrpc, TwoPointZero); + fn assert_request<'a>( + request: Request<'a>, + id: Id<'a>, + method: &str, + params: Option<&str>, + version: Option, + ) { + assert_eq!(request.jsonrpc, version); assert_eq!(request.id, id); assert_eq!(request.method, method); assert_eq!(request.params.as_ref().map(|p| RawValue::get(p)), params); @@ -199,16 +211,19 @@ mod test { Id::Number(1), Some(params), method, + Some(TwoPointZero), ), // Without params field - (r#"{"jsonrpc":"2.0", "method":"subtract", "id":null}"#, Id::Null, None, method), + (r#"{"jsonrpc":"2.0", "method":"subtract", "id":null}"#, Id::Null, None, method, Some(TwoPointZero)), // Escaped method name. - (r#"{"jsonrpc":"2.0", "method":"\"m", "id":null}"#, Id::Null, None, "\"m"), + (r#"{"jsonrpc":"2.0", "method":"\"m", "id":null}"#, Id::Null, None, "\"m", Some(TwoPointZero)), + // Without jsonrpc field + (r#"{"method":"m", "id":null}"#, Id::Null, None, "m", None), ]; - for (ser, id, params, method) in test_vector.into_iter() { + for (ser, id, params, method, version) in test_vector.into_iter() { let request = serde_json::from_str(ser).unwrap(); - assert_request(request, id, method, params); + assert_request(request, id, method, params, version); } } @@ -216,7 +231,7 @@ mod test { fn deserialize_call_escaped_method_name() { let ser = r#"{"jsonrpc":"2.0","id":1,"method":"\"m\""}"#; let req: Request = serde_json::from_str(ser).unwrap(); - assert_request(req, Id::Number(1), "\"m\"", None); + assert_request(req, Id::Number(1), "\"m\"", None, Some(TwoPointZero)); } #[test] @@ -224,7 +239,15 @@ mod test { let ser = r#"{"jsonrpc":"2.0","method":"say_hello","params":[]}"#; let dsr: Notification<&RawValue> = serde_json::from_str(ser).unwrap(); assert_eq!(dsr.method, "say_hello"); - assert_eq!(dsr.jsonrpc, TwoPointZero); + assert_eq!(dsr.jsonrpc, Some(TwoPointZero)); + } + + #[test] + fn deserialize_notif_without_version() { + let ser = r#"{"method":"say_hello","params":[]}"#; + let dsr: Notification<&RawValue> = serde_json::from_str(ser).unwrap(); + assert_eq!(dsr.method, "say_hello"); + assert_eq!(dsr.jsonrpc, None); } #[test] @@ -232,7 +255,7 @@ mod test { let ser = r#"{"jsonrpc":"2.0","method":"\"m\"","params":[]}"#; let dsr: Notification<&RawValue> = serde_json::from_str(ser).unwrap(); assert_eq!(dsr.method, "\"m\""); - assert_eq!(dsr.jsonrpc, TwoPointZero); + assert_eq!(dsr.jsonrpc, Some(TwoPointZero)); } #[test] @@ -255,27 +278,34 @@ mod test { let id = Id::Number(1); // It's enough to check one variant, since the type itself also has tests. let params = Some(RawValue::from_string("[42,23]".into()).unwrap()); - let test_vector: &[(&'static str, Option<_>, Option<_>, &'static str)] = &[ + let test_vector: &[(&'static str, Option<_>, Option<_>, &'static str, Option)] = &[ // With all fields set. ( r#"{"jsonrpc":"2.0","id":1,"method":"subtract","params":[42,23]}"#, Some(id.clone()), params.clone(), method, + Some(TwoPointZero), ), // Escaped method name. - (r#"{"jsonrpc":"2.0","id":1,"method":"\"m"}"#, Some(id.clone()), None, "\"m"), + (r#"{"jsonrpc":"2.0","id":1,"method":"\"m"}"#, Some(id.clone()), None, "\"m", Some(TwoPointZero)), // Without ID field. - (r#"{"jsonrpc":"2.0","id":null,"method":"subtract","params":[42,23]}"#, None, params, method), + ( + r#"{"jsonrpc":"2.0","id":null,"method":"subtract","params":[42,23]}"#, + None, + params, + method, + Some(TwoPointZero), + ), // Without params field - (r#"{"jsonrpc":"2.0","id":1,"method":"subtract"}"#, Some(id), None, method), + (r#"{"jsonrpc":"2.0","id":1,"method":"subtract"}"#, Some(id), None, method, Some(TwoPointZero)), // Without params and ID. - (r#"{"jsonrpc":"2.0","id":null,"method":"subtract"}"#, None, None, method), + (r#"{"jsonrpc":"2.0","id":null,"method":"subtract"}"#, None, None, method, Some(TwoPointZero)), ]; - for (ser, id, params, method) in test_vector.iter().cloned() { + for (ser, id, params, method, version) in test_vector.iter().cloned() { let request = serde_json::to_string(&RequestSer { - jsonrpc: TwoPointZero, + jsonrpc: version, method: method.into(), id: id.unwrap_or(Id::Null), params: params.map(StdCow::Owned), From 8205835d2f9a8b5cd969e943e8f4f6900f0c34fb Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 31 May 2024 14:05:19 +0200 Subject: [PATCH 2/4] fix tests --- server/src/tests/http.rs | 2 +- server/src/tests/ws.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/tests/http.rs b/server/src/tests/http.rs index 3942304683..1a92443295 100644 --- a/server/src/tests/http.rs +++ b/server/src/tests/http.rs @@ -398,7 +398,7 @@ async fn invalid_request_object() { let (addr, _handle) = server().with_default_timeout().await.unwrap(); let uri = to_http_uri(addr); - let req = r#"{"method":"bar","id":1}"#; + let req = r#"{"nethod":"bar","id":1}"#; let response = http_request(req.into(), uri).with_default_timeout().await.unwrap().unwrap(); assert_eq!(response.status, StatusCode::OK); assert_eq!(response.body, invalid_request(Id::Num(1))); diff --git a/server/src/tests/ws.rs b/server/src/tests/ws.rs index c16c88961f..10e7976cda 100644 --- a/server/src/tests/ws.rs +++ b/server/src/tests/ws.rs @@ -399,7 +399,7 @@ async fn invalid_request_object() { let addr = server().await; let mut client = WebSocketTestClient::new(addr).with_default_timeout().await.unwrap().unwrap(); - let req = r#"{"method":"bar","id":1}"#; + let req = r#"{"nethod":"bar","id":1}"#; let response = client.send_request_text(req).with_default_timeout().await.unwrap().unwrap(); assert_eq!(response, invalid_request(Id::Num(1))); } From 0ed4b49a88d78cf44dbab3988767bbaad311c5f9 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 31 May 2024 14:24:58 +0200 Subject: [PATCH 3/4] fix tests v2 --- client/http-client/src/client.rs | 3 +-- core/src/client/async_client/mod.rs | 3 +-- server/src/tests/ws.rs | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/client/http-client/src/client.rs b/client/http-client/src/client.rs index d62050cd38..55b613d7c1 100644 --- a/client/http-client/src/client.rs +++ b/client/http-client/src/client.rs @@ -24,7 +24,6 @@ // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use std::borrow::Cow as StdCow; use std::fmt; use std::sync::Arc; use std::time::Duration; @@ -41,7 +40,7 @@ use jsonrpsee_core::client::{ use jsonrpsee_core::params::BatchRequestBuilder; use jsonrpsee_core::traits::ToRpcParams; use jsonrpsee_core::{BoxError, JsonRawValue, TEN_MB_SIZE_BYTES}; -use jsonrpsee_types::{ErrorObject, InvalidRequestId, ResponseSuccess, TwoPointZero}; +use jsonrpsee_types::{ErrorObject, InvalidRequestId, ResponseSuccess}; use serde::de::DeserializeOwned; use tower::layer::util::Identity; use tower::{Layer, Service}; diff --git a/core/src/client/async_client/mod.rs b/core/src/client/async_client/mod.rs index 2f8a46f710..7da18053e3 100644 --- a/core/src/client/async_client/mod.rs +++ b/core/src/client/async_client/mod.rs @@ -41,14 +41,13 @@ use crate::params::{BatchRequestBuilder, EmptyBatchRequest}; use crate::tracing::client::{rx_log_from_json, tx_log_from_str}; use crate::traits::ToRpcParams; use crate::JsonRawValue; -use std::borrow::Cow as StdCow; use core::time::Duration; use helpers::{ build_unsubscribe_message, call_with_timeout, process_batch_response, process_notification, process_single_response, process_subscription_response, stop_subscription, }; -use jsonrpsee_types::{InvalidRequestId, ResponseSuccess, TwoPointZero}; +use jsonrpsee_types::{InvalidRequestId, ResponseSuccess}; use manager::RequestManager; use std::sync::Arc; diff --git a/server/src/tests/ws.rs b/server/src/tests/ws.rs index 10e7976cda..4a53aa62e1 100644 --- a/server/src/tests/ws.rs +++ b/server/src/tests/ws.rs @@ -465,7 +465,7 @@ async fn invalid_request_should_not_close_connection() { let addr = server().await; let mut client = WebSocketTestClient::new(addr).with_default_timeout().await.unwrap().unwrap(); - let req = r#"{"method":"bar","id":1}"#; + let req = r#"{"nethod":"bar","id":1}"#; let response = client.send_request_text(req).with_default_timeout().await.unwrap().unwrap(); assert_eq!(response, invalid_request(Id::Num(1))); let request = r#"{"jsonrpc":"2.0","method":"say_hello","id":33}"#; From 1c55079b0313b65d9e561639cc4110ef6360decd Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 31 May 2024 17:35:51 +0200 Subject: [PATCH 4/4] Update types/src/request.rs --- types/src/request.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/src/request.rs b/types/src/request.rs index 2363943f37..a3081eb8c3 100644 --- a/types/src/request.rs +++ b/types/src/request.rs @@ -300,7 +300,7 @@ mod test { // Without params field (r#"{"jsonrpc":"2.0","id":1,"method":"subtract"}"#, Some(id), None, method, Some(TwoPointZero)), // Without params and ID. - (r#"{"jsonrpc":"2.0","id":null,"method":"subtract"}"#, None, None, method, Some(TwoPointZero)), + (r#"{"id":null,"method":"subtract"}"#, None, None, method, None), ]; for (ser, id, params, method, version) in test_vector.iter().cloned() {